Возвращать значения из разных таблиц на основе приоритета - PullRequest
1 голос
/ 09 октября 2008

Если у меня есть три таблицы: Таблица A (ключ, значение) Таблица B (ключ, значение) TableC (ключ, значение)

и я хочу вернуть значение для всех ключей. Если ключ существует в TableC, вернуть это значение иначе, если ключ существует в B, вернуть это значение, иначе вернуть значение из таблицы A

Лучшее, что я до сих пор придумал, это

SELECT key,Value
FROM TableA
WHERE key NOT IN (SELECT key FROM TableB)
    AND key NOT IN (SELECT key FROM TableC)
UNION
SELECT key,Value
FROM TableB
WHERE key NOT IN (SELECT key FROM TableC)
UNION
SELECT key,Value
FROM TableC

Но это кажется довольно грубой силой. Кто-нибудь знает лучший способ?

Редактировать: вот более конкретный пример. Рассмотрите Таблицу A как стандартный график работы, где ключом является дата, а значением - назначенная смена. Таблица B является официальным праздничным календарем, который переопределяет стандартную рабочую неделю. Таблица C - это график исключений, который используется для переопределения двух других расписаний, когда кого-то просят прийти и выполнить дополнительную смену или другую смену.

Ответы [ 7 ]

3 голосов
/ 09 октября 2008

Хорошо, используя ваш конкретный пример в качестве основы, я нашел решение, отличное от других, опубликованных (хотя я думаю, что ваше решение мне нравится больше) Это было проверено на MS SQL Server 2005 - могут потребоваться изменения для вашего диалекта SQL.

Сначала немного DDL для установки сцены:

CREATE TABLE [dbo].[StandardSchedule](
    [scheduledate] [datetime] NOT NULL,
    [shift] [varchar](25) NOT NULL,
 CONSTRAINT [PK_StandardSchedule] PRIMARY KEY CLUSTERED 
( [scheduledate] ASC ));

CREATE TABLE [dbo].[HolidaySchedule](
    [holidaydate] [datetime] NOT NULL,
    [shift] [varchar](25) NOT NULL,
 CONSTRAINT [PK_HolidaySchedule] PRIMARY KEY CLUSTERED 
( [holidaydate] ASC ));

CREATE TABLE [dbo].[ExceptionSchedule](
    [exceptiondate] [datetime] NOT NULL,
    [shift] [varchar](25) NOT NULL,
 CONSTRAINT [PK_ExceptionDate] PRIMARY KEY CLUSTERED 
( [exceptiondate] ASC ));

INSERT INTO ExceptionSchedule VALUES ('2008.01.06', 'ExceptionShift1');
INSERT INTO ExceptionSchedule VALUES ('2008.01.08', 'ExceptionShift2');
INSERT INTO ExceptionSchedule VALUES ('2008.01.10', 'ExceptionShift3');
INSERT INTO HolidaySchedule VALUES ('2008.01.01', 'HolidayShift1');
INSERT INTO HolidaySchedule VALUES ('2008.01.06', 'HolidayShift2');
INSERT INTO HolidaySchedule VALUES ('2008.01.09', 'HolidayShift3');
INSERT INTO StandardSchedule VALUES ('2008.01.01', 'RegularShift1');
INSERT INTO StandardSchedule VALUES ('2008.01.02', 'RegularShift2');
INSERT INTO StandardSchedule VALUES ('2008.01.03', 'RegularShift3');
INSERT INTO StandardSchedule VALUES ('2008.01.04', 'RegularShift4');
INSERT INTO StandardSchedule VALUES ('2008.01.05', 'RegularShift5');
INSERT INTO StandardSchedule VALUES ('2008.01.07', 'RegularShift6');
INSERT INTO StandardSchedule VALUES ('2008.01.09', 'RegularShift7');
INSERT INTO StandardSchedule VALUES ('2008.01.10', 'RegularShift8');

Используя эти таблицы / строки в качестве основы, этот оператор SELECT извлекает нужные данные:

SELECT DISTINCT
    COALESCE(e2.exceptiondate, e.exceptiondate, holidaydate, scheduledate) AS ShiftDate,
    COALESCE(e2.shift, e.shift, h.shift, s.shift) AS Shift
FROM standardschedule s
FULL OUTER JOIN holidayschedule h ON s.scheduledate = h.holidaydate
FULL OUTER JOIN exceptionschedule e ON h.holidaydate = e.exceptiondate
FULL OUTER JOIN exceptionschedule e2 ON s.scheduledate = e2.exceptiondate
ORDER BY shiftdate
1 голос
/ 09 октября 2008

Вот альтернативный оператор SQL: -

SELECT
    ALL_KEYS.KEY,
    NVL( TABLEC.VALUE, NVL( TABLEB.VALUE, TABLEA.VALUE)) AS VALUE
FROM
    (SELECT KEY AS KEY FROM TABLEA
     UNION
     SELECT KEY FROM TABLEB
     UNION
     SELECT KEY FROM TABLEC) ALL_KEYS,
     TABLEA,
     TABLEB,
     TABLEC
WHERE
    ALL_KEYS.KEY = TABLEA.KEY(+) AND
    ALL_KEYS.KEY = TABLEB.KEY(+) AND
    ALL_KEYS.KEY = TABLEC.KEY(+);

NB. NVL () - это функция Oracle. Если первый параметр NULL, второй параметр возвращается, в противном случае возвращается первый параметр. Вы не сказали, какую базу данных использовали, но, без сомнения, во всем есть эквиваленты.

0 голосов
/ 09 октября 2008

Создайте основную таблицу для всех ключей, затем присоедините эту основную таблицу к трем таблицам слева и исследуйте команду COALESCE.

0 голосов
/ 09 октября 2008
SELECT isnull( c.key, isnull( b.key, a.key) ) , 
       isnull( c.value, isnull( b.value, a.value ) ) 
FROM   TableA a 
LEFT JOIN TableB b 
ON        a.key = b.key
LEFT JOIN TableC c 
ON        b.key = c.key
0 голосов
/ 09 октября 2008

Вот как я это сделаю в SQL Server. Это решение должно генерировать менее логичный ввод-вывод, чем оригинал. Если бы таблицы были достаточно большими, я бы переключился на таблицы #temp для включения параллелизма.

DECLARE @MyTable TABLE
(
  Key int PRIMARY KEY,
  Value int
)

    --Grab from TableC
INSERT INTO @MyTable(Key, Value)
SELECT Key, Value
FROM TableC

    --Grab from TableB
INSERT INTO @MyTable(Key, Value)
SELECT Key, Value
FROM TableB
WHERE Key not in (SELECT Key FROM @MyTable)

    --Grab from TableA  
INSERT INTO @MyTable(Key, Value)
SELECT Key, Value
FROM TableA
WHERE Key not in (SELECT Key FROM @MyTable)
    --Pop the result
SELECT Key, Value
FROM @MyTable

Этот метод отражает, как я буду обрабатывать 3 списка в C # ... путем создания словаря.

0 голосов
/ 09 октября 2008

Ваш запрос выглядит нормально.

В качестве альтернативы, вы можете использовать запрос ниже и фильтровать на стороне клиента. Это будет менее напряженным для сервера базы данных.

SELECT key, value, 2 AS priority
FROM TableA
UNION
SELECT key, value, 1 AS priority
FROM TableB
UNION
SELECT key, value, 0 AS priority
FROM TableC
ORDER BY key, priority
0 голосов
/ 09 октября 2008

Если у вас есть несколько таблиц, из которых вы хотите получать данные, то вам придется выбирать из них, другого пути нет.

Из вашего SQL кажется, что вы можете получить перезапуски из таблицы C, которая содержит ключи в tableA и tableB, поскольку вы ОБЪЕДИНЯЕТЕ перезапуски простого выбора в tableC (в котором нет предложения where). Где вы после эксклюзивного набора ключей, которые не существуют ни в одной из других таблиц? Если это так, то вам нужно будет сделать то, что вы сделали для предложения where для tableA в элементах выбора для tableB и tableC.

Надеюсь, это имеет смысл ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...