SQL JOIN与COALESCE的条件是重复行

时间:2021-05-31 19:20:30

I am trying to join two tables together. The first table contains data records that I do not want to duplicate. The second table I am joining to the first table to lookup a [value] by a distinct [profileId] and [role]. The [profileId], [role] column in the second table has a unique constraint on the combination, but [role] can sometimes be NULL, in which case I treat that value as the default for that profile.

我想把两张桌子连在一起。第一个表包含我不想重复的数据记录。我将连接到第一个表的第二个表,通过不同的[profileId]和[role]查找[值]。第二个表中的[profileId]、[role]列对组合有惟一的约束,但[role]有时可以为空,在这种情况下,我将该值视为该概要文件的默认值。

How can I join these tables together without duplicating the rows, and without using multiple left joins? My actual query is more complex than the example.

如何在不重复行、不使用多个左连接的情况下将这些表连接在一起?我的实际查询比示例更复杂。

See example below.

请参见下面的例子。

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]

This gives me (and I understand why)

这给了我(我明白为什么)

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

While I want

当我想要

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

3 个解决方案

#1


1  

You can use APPLY and TOP:

你可以使用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

#2


2  

This SQL works fine:

这个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]
;

#3


0  

if you know the DEFAULT value use left join.

如果知道默认值,请使用左连接。

SQL Fiddle Demo

SQL小提琴演示

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

Otherwise

否则

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]
       ;  

#1


1  

You can use APPLY and TOP:

你可以使用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

#2


2  

This SQL works fine:

这个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]
;

#3


0  

if you know the DEFAULT value use left join.

如果知道默认值,请使用左连接。

SQL Fiddle Demo

SQL小提琴演示

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

Otherwise

否则

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]
       ;