混合完全和左连接的A,B和C之间的SQL关节

时间:2018-06-06 14:02:01

标签: sql sql-server

我想知道在下面的例子中是否有更好的方法来创建我的左连接

SELECT TOP 10 COALESCE(A.COD_PRODUCT, B.COD_PRODUCT),
              COALESCE(A.COD_FAMILY, B.COD_FAMILY),
              COALESCE(A.DATE_EXTRACT, B.DATE_EXTRACT),
              A.MASS
              B.VOLUME
              C.PRICE
FROM FIRSTTABLE A
FULL JOIN SECONDTABLE B
     ON B.COD_PRODUCT = A.COD_PRODUCT
     AND B.COD_FAMILY = A.COD_FAMILY
     AND B.DATE_EXTRACT = A.DATE_EXTRACT
LEFT JOIN THIRDTABLE C
     ON C.COD_PRODUCT = COALESCE(A.COD_PRODUCT, B.COD_PRODUCT)
     AND C.COD_FAMILY = COALESCE(A.COD_FAMILY, B.COD_FAMILY)
     AND C.DATE_EXTRACT = COALESCE(A.DATE_EXTRACT, B.DATE_EXTRACT)

这种关节需要很长时间,我怀疑它非常昂贵且可以改进

编辑:我想在视图中改进此SELECt FROM JOIN语句。

5 个答案:

答案 0 :(得分:0)

将执行计划与此替换联接进行比较:

LEFT JOIN THIRDTABLE C
     ON (C.COD_PRODUCT = A.COD_PRODUCT or C.COD_PRODUCT = B.COD_PRODUCT)
     AND (C.COD_FAMILY = A.COD_FAMILY or C.COD_FAMILY = B.COD_FAMILY)
     AND (C.DATE_EXTRACT =A.DATE_EXTRACT or C.DATE_EXTRACT = B.DATE_EXTRACT)

答案 1 :(得分:0)

您可以使用UNION或UNION ALL

获得相同的结果
WITH cte AS (

    SELECT  
        A.COD_PRODUCT,
        A.COD_FAMILY,
        A.DATE_EXTRACT,
        A.MASS,
        NULL as VOLUME
    FROM
        FIRSTTABLE A
    UNION
    SELECT  
        B.COD_PRODUCT,
        B.COD_FAMILY,
        B.DATE_EXTRACT,
        NULL,
        B.VOLUME
    FROM
        FIRSTTABLE A
)
SELECT  
    *
FROM
    cte AB
LEFT JOIN 
    THIRDTABLE C    ON C.COD_PRODUCT = AB.COD_PRODUCT
        AND C.COD_FAMILY = AB.COD_FAMILY
        AND C.DATE_EXTRACT = AB.DATE_EXTRACT

如果您可以为产品,系列,提取组合提供质量和体积,则可以使用聚合来一起加入A和B

WITH cte AS (
    SELECT 
        COD_PRODUCT,
        COD_FAMILY,
        DATE_EXTRACT,
        MAX(MASS) MASS,
        MAX(VOLUME) VOLUME
    FROM (
        SELECT  
            A.COD_PRODUCT,
            A.COD_FAMILY,
            A.DATE_EXTRACT,
            A.MASS,
            NULL as VOLUME
        FROM
            FIRSTTABLE A
        UNION ALL
        SELECT  
            B.COD_PRODUCT,
            B.COD_FAMILY,
            B.DATE_EXTRACT,
            NULL,
            B.VOLUME
        FROM
            FIRSTTABLE A
        ) T
    GROUP BY
        COD_PRODUCT,
        COD_FAMILY,
        DATE_EXTRACT
)
SELECT  
    *
FROM
    cte AB
LEFT JOIN 
    THIRDTABLE C    ON C.COD_PRODUCT = AB.COD_PRODUCT
        AND C.COD_FAMILY = AB.COD_FAMILY
        AND C.DATE_EXTRACT = AB.DATE_EXTRACT

答案 2 :(得分:0)

你可以试试这个:

--- isolate the full join data from a and b into a temp table
SELECT 
    COD_PRODUCT=    COALESCE(A.COD_PRODUCT, B.COD_PRODUCT),
    COD_FAMILY=     COALESCE(A.COD_FAMILY, B.COD_FAMILY),
    DATE_EXTRACT=   COALESCE(A.DATE_EXTRACT, B.DATE_EXTRACT),
    MASS=           A.MASS,
    VOLUME=         B.VOLUME
INTO #TEMP
FROM FIRSTTABLE A
FULL JOIN SECONDTABLE B
     ON B.COD_PRODUCT = A.COD_PRODUCT
     AND B.COD_FAMILY = A.COD_FAMILY
     AND B.DATE_EXTRACT = A.DATE_EXTRACT
-- add index clustered onto table (covering index)
CREATE CLUSTERED INDEX ix_tempCIndex ON #Temp ([COD_PRODUCT],[COD_FAMILY],[DATE_EXTRACT],[MASS],[VOLUME]);

-- left join C to this temp table
SELECT TOP 10
    T.*, C.PRICE
FROM #TEMP T
LEFT JOIN THIRDTABLE C
     ON C.COD_PRODUCT = T.COD_PRODUCT
     AND C.COD_FAMILY = T.COD_FAMILY
     AND C.DATE_EXTRACT = T.DATE_EXTRACT
-- drop temp table
DROP TABLE #TEMP

答案 3 :(得分:0)

您可以将查询分为两部分:收集所有与FIRSTTABLE匹配的数据。然后将其与FIRSTTABLE中没有的所有匹配SECONDTABLE的数据合并。

这应该使SQL Server可以更好地使用这些表上的索引。

SELECT A.COD_PRODUCT,
       A.COD_FAMILY,
       A.DATE_EXTRACT,
       A.MASS,
       B.VOLUME,
       C.PRICE
FROM FIRSTTABLE A
LEFT OUTER JOIN SECONDTABLE B
     ON B.COD_PRODUCT = A.COD_PRODUCT
     AND B.COD_FAMILY = A.COD_FAMILY
     AND B.DATE_EXTRACT = A.DATE_EXTRACT
LEFT OUTER JOIN THIRDTABLE C
     ON C.COD_PRODUCT = A.COD_PRODUCT
     AND C.COD_FAMILY = A.COD_FAMILY
     AND C.DATE_EXTRACT = A.DATE_EXTRACT
UNION ALL
SELECT B.COD_PRODUCT,
       B.COD_FAMILY,
       B.DATE_EXTRACT,
       NULL AS MASS,
       B.VOLUME,
       C.PRICE
FROM SECONDTABLE B
LEFT OUTER JOIN THIRDTABLE C
     ON C.COD_PRODUCT = B.COD_PRODUCT
     AND C.COD_FAMILY = B.COD_FAMILY
     AND C.DATE_EXTRACT = B.DATE_EXTRACT
WHERE NOT EXISTS (SELECT 1
                  FROM   FIRSTTABLE A
                  WHERE  A.COD_PRODUCT = B.COD_PRODUCT
                  AND    A.COD_FAMILY = B.COD_FAMILY
                  AND    A.DATE_EXTRACT = B.DATE_EXTRACT)

答案 4 :(得分:0)

联接内的合并或OR将大大减慢查询速度。根据表的大小,更好的答案可能是两次连接到表c。一次在表a上,再一次在表B上,然后在select子句内部合并。

选择前10大凉粉(A.COD_PRODUCT,B.COD_PRODUCT,c.COD_PRODUCT,ca.COD_PRODUCT),
COALESCE(A.COD_FAMILY,B.COD_FAMILY,c.COD_FAMILY,ca.COD_FAMILY),
COALESCE(A.DATE_EXTRACT,B.DATE_EXTRACT,c.DATE_EXTRACT,ca.DATE_EXTRACT),
A.MASS
B.VOLUME
C.PRICE
来自第一表A
完全联接第二台B
ON B.COD_PRODUCT = A.COD_PRODUCT
AND B.COD_FAMILY = A.COD_FAMILY
AND B.DATE_EXTRACT = A.DATE_EXTRACT
左联接第三台C
ON C.COD_PRODUCT = A.COD_PRODUCT
AND C.COD_FAMILY = A.COD_FAMILY
AND C.DATE_EXTRACT = A.DATE_EXTRACT
左联接三级钙
开启Ca.COD_PRODUCT = b.COD_PRODUCT
AND Ca.COD_FAMILY = b.COD_FAMILY
AND Ca.DATE_EXTRACT = b.DATE_EXTRACT