2016-01-25 3 views
2

Я пытаюсь объединить две таблицы вместе. Первая таблица содержит записи данных, которые я не хочу дублировать. Во второй таблице я присоединяюсь к первой таблице для поиска [значения] с помощью различных [profileId] и [role]. Столбец [profileId], [role] во второй таблице имеет уникальное ограничение для комбинации, но [role] иногда может быть NULL, и в этом случае я рассматриваю это значение как значение по умолчанию для этого профиля.SQL JOIN with COALESCE в состоянии дублирует строки

Как объединить эти таблицы без дублирования строк и без использования нескольких левых соединений? Мой фактический запрос более сложный, чем пример.

См. Пример ниже.

DECLARE @temp TABLE ([profileId] int, [role] int) 
DECLARE @temp2 TABLE ([profileId] int, [role] int, [value] nvarchar(50)) 

INSERT INTO @temp ([profileId], [role]) VALUES (1, 1) 
INSERT INTO @temp ([profileId], [role]) VALUES (1, 2) 
INSERT INTO @temp ([profileId], [role]) VALUES (2, 1) 
INSERT INTO @temp ([profileId], [role]) VALUES (2, 2) 
INSERT INTO @temp2 ([profileId], [role], [value]) VALUES (1, 1, 'MATCH') 
INSERT INTO @temp2 ([profileId], [role], [value]) VALUES (1, NULL, 'DEFAULT1') 
INSERT INTO @temp2 ([profileId], [role], [value]) VALUES (2, NULL, 'DEFAULT2') 

SELECT 
    T1.[profileId], 
    T1.[role], 
    T2.value 
FROM 
    @temp T1 
    JOIN @temp2 T2 ON T1.profileId = T2.profileId AND COALESCE(T2.[role], T1.[role]) = T1.[role] 

Это дает мне (и я понимаю, почему)

================================ 
| profileId | role | value | 
================================ 
|  1  | 1 | MATCH | 
-------------------------------- 
|  1  | 1 | DEFAULT1 | 
-------------------------------- 
|  1  | 2 | DEFAULT1 | 
-------------------------------- 
|  2  | 1 | DEFAULT2 | 
-------------------------------- 
|  2  | 2 | DEFAULT2 | 
================================ 

В то время как я хочу

================================ 
| profileId | role | value | 
================================ 
|  1  | 1 | MATCH | 
-------------------------------- 
|  1  | 2 | DEFAULT1 | 
-------------------------------- 
|  2  | 1 | DEFAULT2 | 
-------------------------------- 
|  2  | 2 | DEFAULT2 | 
================================ 
+0

Ваше значение по умолчанию находится в базе данных или вы можете использовать 'CASE' для его получения? –

+0

Будет ли несколько NULL 'role' в' @ temp2'? –

+0

@FelixPamittan Да, в соответствии с комментарием в моем ответе. Существует также некоторый 'profileID' –

ответ

1

Вы можете использовать APPLY и TOP:

SELECT 
    t.profileId, 
    t.role, 
    x.value 
FROM @temp t 
OUTER APPLY(
    SELECT TOP 1 value 
    FROM @temp2 
    WHERE 
     profileId = t.profileId 
     AND (role = t.role OR role IS NULL) 
    ORDER BY 
     CASE WHEN role IS NOT NULL THEN 0 ELSE 1 END 
)x 
0

, если вы знаете, использовать в DEFAULTleft join значение.

SQL Fiddle Demo

SELECT 
    T1.[role], 
    COALESCE(T2.value, 'DEFAULT') as value 
FROM 
    temp T1 
LEFT JOIN temp2 T2 
     ON T1.[role] = T2.[role]; 

В противном случае

SELECT 
    T1.[role], 
    COALESCE(T2.value, (SELECT value 
         FROM temp2 
         WHERE role is NULL and temp2.profileID = T1.profileID)) as value 
FROM 
    temp T1 
LEFT JOIN temp2 T2 
     ON T1.[role] = T2.[role] 
     AND T1.[profileID] = T2.[profileID] 
     ; 
+0

. [Value] s редактируются пользователем, поэтому я не знаю DEFAULT. Кроме того, я изменю определение @ temp2, ясно, что существует много значений DEFAULT (на основе идентификатора профиля). – ben

+0

Затем используйте вторую версию. –

2

Этот SQL работает отлично:

SELECT 
    T1.[role], 
    Value = coalesce(max(nullif(T2.value,'DEFAULT')),'DEFAULT') 
FROM 
    @temp T1 
    JOIN @temp2 T2 ON COALESCE(T2.[role], T1.[role]) = T1.[role] 
group by 
    T1.[role] 
;