TSQL-LEFT OUTER JOIN意外结果

时间:2019-03-08 16:42:49

标签: tsql left-join

我知道LEFT OUTER JOIN的意思是“给我左表中的所有内容,并返回右表中匹配项的详细信息,以及没有匹配项的NULL值”,因此给出以下代码:

CREATE TABLE #Items(
    WarehouseNumber varchar(2),
    ItemNumber varchar(8),
    ItemDescription varchar(50)
)

INSERT INTO #Items(WarehouseNumber, ItemNumber, ItemDescription) VALUES('01', '12345', 'Widget')
INSERT INTO #Items(WarehouseNumber, ItemNumber, ItemDescription) VALUES('02', '12345', 'Widget')
INSERT INTO #Items(WarehouseNumber, ItemNumber, ItemDescription) VALUES('07', '12345', 'Widget')

CREATE TABLE #InvoiceHdr(
    InvoiceNumber varchar(8),
    WarehouseNumber varchar(2),
    DateOrdered datetime,
    DateInvoiced datetime
)

INSERT INTO #InvoiceHdr(InvoiceNumber, WarehouseNumber, DateOrdered, DateInvoiced) VALUES('1', '01', '20190101', '20190102')
INSERT INTO #InvoiceHdr(InvoiceNumber, WarehouseNumber, DateOrdered, DateInvoiced) VALUES('2', '07', '20190102', '20190103')
INSERT INTO #InvoiceHdr(InvoiceNumber, WarehouseNumber, DateOrdered, DateInvoiced) VALUES('3', '02', '20190201', '20190202')
INSERT INTO #InvoiceHdr(InvoiceNumber, WarehouseNumber, DateOrdered, DateInvoiced) VALUES('4', '07', '20190216', '20190217')
INSERT INTO #InvoiceHdr(InvoiceNumber, WarehouseNumber, DateOrdered, DateInvoiced) VALUES('5', '07', '20190221', '20190222')

CREATE TABLE #InvoiceDtl(
    InvoiceNumber varchar(8),
    InvoiceLineItem int,
    ItemNumber varchar(8),
    QtyOrdered int,
    QtyShipped int
)

INSERT INTO #InvoiceDtl(InvoiceNumber, InvoiceLineItem, ItemNumber, QtyOrdered, QtyShipped) VALUES('1', 1, '12345', 4, 4)
INSERT INTO #InvoiceDtl(InvoiceNumber, InvoiceLineItem, ItemNumber, QtyOrdered, QtyShipped) VALUES('2', 1, '12345', 33, 30)
INSERT INTO #InvoiceDtl(InvoiceNumber, InvoiceLineItem, ItemNumber, QtyOrdered, QtyShipped) VALUES('3', 1, '12345', 5, 5)
INSERT INTO #InvoiceDtl(InvoiceNumber, InvoiceLineItem, ItemNumber, QtyOrdered, QtyShipped) VALUES('4', 1, '12345', 7, 7)
INSERT INTO #InvoiceDtl(InvoiceNumber, InvoiceLineItem, ItemNumber, QtyOrdered, QtyShipped) VALUES('5', 1, '12345', 8, 8

SELECT I.ItemNumber,
        I.WarehouseNumber,
        SUM(Details.Qty) 'Qty'
FROM #Items I
    LEFT OUTER JOIN (SELECT IH.DateInvoiced,
                                IH.WarehouseNumber,
                                ID.ItemNumber,
                                SUM(ID.QtyOrdered) 'Qty'
                        FROM #InvoiceHdr IH
                            INNER JOIN #InvoiceDtl ID ON IH.InvoiceNumber = ID.InvoiceNumber
                        GROUP BY IH.DateInvoiced,
                                    ID.ItemNumber,
                                    IH.WarehouseNumber) Details ON I.ItemNumber = Details.ItemNumber
                                        AND I.WarehouseNumber = Details.WarehouseNumber
WHERE Details.DateInvoiced >= '20190101'
    AND Details.DateInvoiced < '20190108'
GROUP BY I.ItemNumber,
            I.WarehouseNumber

...我收到以下结果:

ItemNumber | WarehouseNumber | Qty
==================================
12345      | 01              | 4
12345      | 07              | 33

当我期望的时候:

ItemNumber | WarehouseNumber | Qty
==================================
12345      | 01              | 4
12345      | 02              | NULL
12345      | 07              | 33

我看过this question and solution,但是公认的解决方案特别指出“我知道这在SQL Server中不起作用,但对MySQL有效”。我想让它们在SQL Server中运行(如果可能,请在2005年运行,如果不能,请在2016年运行)

1 个答案:

答案 0 :(得分:1)

WHERE更改为AND,您应该会很好。将日期条件放在WHERE子句中会将其从结果集中排除。将其放入联接中会将其从联接表中排除,从而导致结果集中为NULL值。

SELECT  I.ItemNumber
        , I.WarehouseNumber
        , SUM(Details.Qty) 'Qty'
FROM    #Items I
        LEFT OUTER JOIN 
        (
            SELECT  IH.DateInvoiced
                    , IH.WarehouseNumber
                    , ID.ItemNumber
                    , SUM(ID.QtyOrdered) 'Qty'
            FROM    #InvoiceHdr IH
                    INNER JOIN #InvoiceDtl ID ON IH.InvoiceNumber = ID.InvoiceNumber
            GROUP BY IH.DateInvoiced, ID.ItemNumber, IH.WarehouseNumber
        ) Details ON 
            I.ItemNumber = Details.ItemNumber
            AND I.WarehouseNumber = Details.WarehouseNumber
/*WHERE*/   AND Details.DateInvoiced >= '20190101'
            AND Details.DateInvoiced < '20190108'
GROUP BY I.ItemNumber, I.WarehouseNumber