SQL Server - 相关子查询/自连接

时间:2015-10-14 06:26:47

标签: sql sql-server self-join correlated-subquery

选择声明,返回位于独特城市和州的每个供应商的名称,城市和州(即,排除与其他供应商具有相同城市和州的供应商)

SELECT 
    VendorName, VendorCity, VendorState
FROM 
    Vendors
WHERE 
    VendorState + VendorCity NOT IN (SELECT VendorState + VendorCity
                                     FROM Vendors
                                     GROUP BY VendorState + VendorCity
                                     HAVING COUNT(*) > 1)
ORDER BY 
    VendorState, VendorCity;

替代回答

SELECT 
    VendorName, VendorCity, VendorState
FROM 
    Vendors AS Vendors_Main
WHERE 
    VendorCity + VendorState NOT IN (SELECT VendorCity + VendorState
                                     FROM Vendors AS Vendors_Sub
                                     WHERE Vendors_Sub.VendorID <> Vendors_Main.VendorID)
ORDER BY 
    VendorState, VendorCity;

我理解第一个答案,但不了解备用查询。混淆点:下面的行不会返回0行,因为它们引用同一个表而没有额外的where子句吗?

WHERE Vendors_Sub.VendorID <> Vendors_Main.VendorID)

2 个答案:

答案 0 :(得分:0)

SELECT  VendorName ,
        VendorCity ,
        VendorState
FROM    Vendors AS Vendors_Main
WHERE   VendorCity + VendorState NOT IN 
    (
        SELECT  VendorCity + VendorState
        FROM    Vendors AS Vendors_Sub
        WHERE   Vendors_Sub.VendorID <> Vendors_Main.VendorID
    )
ORDER BY VendorState ,VendorCity;

子查询

SELECT  VendorCity + VendorState
FROM    Vendors AS Vendors_Sub
WHERE   Vendors_Sub.VendorID <> Vendors_Main.VendorID

将为主查询中的每一行返回vendorCity + vendorState的所有现有组合,但不包括具有相同ID的行。想象子查询是为主查询中的每一行调用的函数。

如果WHERE Vendors_Sub.VendorID <> Vendors_Main.VendorID不存在,那么每个主查询行都会在子查询中与自身匹配,整个查询将不返回任何行,因为这些组合都不是唯一的。

答案 1 :(得分:0)

WHERE Vendors_Sub.VendorID <> Vendors_Main.VendorID)不会比较同一个表的同一行。

对于外部查询中的每一行,相关子查询在逻辑上执行一次,在这种情况下,它会检查具有相同VendorCity / VendorState组合的行,但不同VendorIDs

事实上,我希望直接翻译成相关的NOT EXISTS

SELECT VendorName, VendorCity, VendorState
FROM Vendors AS Vendors_Main
WHERE NOT EXISTS
 (
   SELECT *
   FROM Vendors AS Vendors_Sub
   WHERE Vendors_Sub.VendorCity  = Vendors_Main.VendorCity  -- same city
     AND Vendors_Sub.VendorState = Vendors_Main.VendorState -- same state
     AND Vendors_Sub.VendorID   <> Vendors_Main.VendorID    -- different vendor
 )
ORDER BY VendorState, VendorCity;

这样可以防止'state' + 'acity''statea' + 'city'之类的误报,这些误报既可以连接到'stateacity',也适用于任何类型的数据类型。