如何返回与JOIN标准的某些部分匹配的数据,几乎就像FULL OUTER JOIN一样?

时间:2018-04-05 20:05:07

标签: sql sql-server tsql

这是我想要弄清楚的。假设我有两个数据集,我试图通过将它们连接在一起进行比较并将它们并排放置并查看差异:

Table1
Name       Description       Style          Cost
Chair-1    Simple Chair      Contemporary   $100

Table2
Name       Description       Style          Cost
Chair-1    Simple Chair      Modern         $150 

我会像这样写一些SQL:

SELECT T1.Name, T1.Description, T1.Style, T1.Cost
T2.Name, T2.Description, T2.Style, T2.Cost
FROM Table1 T1
FULL OUTER JOIN Table2 T2
ON T1.Name = T2.Name
AND T1.Description = T2.Description
AND T1.Style = T2.Style
--WHERE T1.Cost <> T2.Cost

但是,结果集会给我2条记录,T1记录的T2字段为NULL,T2记录的T1字段为NULL,因为它们不完全匹配。

我的问题是:有没有办法将这两个数据集连接在一起,如果它们匹配某些字段而不是ALL,则将它们并排?我尝试使用FULL OUTER JOIN执行此操作,但它们仍然必须匹配JOIN条件中的所有字段。

例如,由于上面的两个记录具有相同的名称和描述但风格不同,我希望将它们连接在一起,因为它们匹配3个条件中的2个。

我将在SQL Server 2016上运行它。

编辑:我认为这可能是OUTER APPLY的一个用例,但我并不完全确定。我重新编写了我的代码看起来像这样(示例是所有伪代码):

SELECT T1.Name, T1.Description, T1.Style, T1.Cost
T2.Name, T2.Description, T2.Style, T2.Cost
FROM Table1 T1
OUTER APPLY 
(
SELECT T2.Name, T2.Description, T2.Style, T2.Cost
FROM Table2 T2
WHERE T1.Name = T2.Name
AND T1.Description = T2.Description
AND T1.Style = T2.Style
--AND T1.Cost <> T2.Cost --This is what I'm looking for ultimately
) T2

我是否理解OUTER APPLY将返回具有最匹配条件的记录?

3 个答案:

答案 0 :(得分:1)

您可以使用OR进行加入。

SELECT T1.Name, T1.Description, T1.Style, T1.Cost
       T2.Name, T2.Description, T2.Style, T2.Cost
FROM Table1 T1 FULL OUTER JOIN
     Table2 T2
     ON T1.Name = T2.Name OR
        T1.Description = T2.Description OR
        T1.Style = T2.Style

如果3列中的任何一列匹配,这将给出结果。要使用ANDOR的组合,可以使其匹配3列中的2列。

示例:

(T1.Name = T2.Name AND T1.Description = T2.Description)
OR (T1.Description = T2.Description AND T1.Style = T2.Style)
OR (T1.Name = T2.Name AND T1.Style = T2.Style)

答案 1 :(得分:0)

我认为您可以将where条件移至on子句:

SELECT T1.Name, T1.Description, T1.Style, T1.Cost
       T2.Name, T2.Description, T2.Style, T2.Cost
FROM Table1 T1 FULL OUTER JOIN
     Table2 T2
     ON T1.Name = T2.Name AND
        T1.Description = T2.Description AND
        T1.Style = T2.Style AND
        T1.Cost <> T2.Cost

FULL OUTER JOIN在涉及过滤时很棘手。如果您不希望成本匹配的行,请添加:

WHERE T1.Cost IS NOT NULL AND t2.Cost IS NOT NULL

但是,这相当于INNER JOIN

SELECT T1.Name, T1.Description, T1.Style, T1.Cost
       T2.Name, T2.Description, T2.Style, T2.Cost
FROM Table1 T1 INNER JOIN
     Table2 T2
     ON T1.Name = T2.Name AND
        T1.Description = T2.Description AND
        T1.Style = T2.Style AND
        T1.Cost <> T2.Cost;

这可能是你真正想要的。

答案 2 :(得分:0)

OUTER APPLY将返回两个表中的所有记录,包括那些没有匹配的记录。您需要使用APPLY而不是JOIN的最常见原因是当您应用&#34;应用&#34;现有表的表值函数。换句话说,您正在进行JOIN,但是您正在使用一个表来加入TableA,该表是查询的结果(有点像视图)而不是另一个现有表。听起来在这种情况下,你最好使用JOIN。但是,在少数情况下OUTER APPLY可能更快 - 使用它的另一个潜在原因。我不是优化运行时的专家,所以你必须查看执行计划。

临床医生的答案很好,但唯一(潜在的)问题是你可能遇到一个你想要获得更多行的场景。换句话说,我相信使用那些OR运算符会产生重复的行,因为每行将匹配多行。

我认为您最好的选择可能是使用CASE WHEN声明只是为了安全起见。

SELECT T1.Name, T1.Description, T1.Style, T1.Cost
       T2.Name, T2.Description, T2.Style, T2.Cost
FROM Table1 T1 FULL OUTER JOIN
     Table2 T2
     ON case when T1.Name = T2.Name then T1.Name
             when T1.Description = T2.Description then T1.Description
             else T1.Style
             end
             =
        case when T1.Name = T2.Name then T2.Name
             when T1.Description = T2.Description then T2.Description
             else T2.Style
             end