如何在非主键上正确连接多个表?

时间:2018-01-08 14:58:36

标签: sql-server tsql

我正在尝试创建一个视图,其中用户看到每个“批处理”加入一行,这样当来自不同表的“批处理”匹配时 - 那么它们应该一起作为一行。但是如果任何一个表本身都有“批处理”,那么它也应该作为一行添加到其他列中的“NULL”行。

我认为问题在于如何加入表格。但我无法弄清楚这个问题。

CREATE TABLE #ItemTable ([Item] nvarchar(16))
CREATE TABLE #LocationTable ([Item] nvarchar(16), [Batch] nvarchar(32), [Location] nvarchar(13), [Quantity] int)
CREATE TABLE #OrderTable ([Item] nvarchar(16), [Batch] nvarchar(32), [Quantity] int)
CREATE TABLE #BookingTable ([Item] nvarchar(16), [Batch] nvarchar(32), [Quantity] int)

--------------------------------------------------------------------------------------------------
-- CURRENT RESULT:
--------------------------------------------------------------------------------------------------
--  Item    Batch   Location        QuantityOnLocation  OrderedQuantity BookedQuantity
--  1000    1       Location_1      10                  NULL            NULL
--  1000    22      Location_2      10                  NULL            NULL
--  2000    333     Location_3      0                   10              NULL
--  2000    4444    Location_4      10                  NULL            NULL
--  3000    666666  NULL            NULL                10              10

--------------------------------------------------------------------------------------------------
-- DESIRED RESULT:
--------------------------------------------------------------------------------------------------
--  Item    Batch   Location        QuantityOnLocation  OrderedQuantity BookedQuantity
--  1000    1       Location_1      10                  NULL            10
--  1000    22      Location_2      10                  NULL            0
--  1000    55555   NULL            NULL                NULL            10
--  2000    333     Location_3      0                   10              NULL
--  2000    4444    Location_4      10                  NULL            NULL
--  3000    666666  NULL            NULL                10              10


INSERT INTO #ItemTable ([Item]) VALUES 
('1000'), 
('2000'), 
('3000')

INSERT INTO #LocationTable ([Item], [Batch], [Location], [Quantity]) VALUES 
('1000', '1', 'Location_1', 10), 
('1000', '22', 'Location_2', 10), 
('2000', '333', 'Location_3', 0),
('2000', '4444', 'Location_4', 10)

INSERT INTO #OrderTable ([Item], [Batch], [Quantity]) VALUES 
('2000', '333', 10), 
('3000', '666666', 10)

INSERT INTO #BookingTable ([Item], [Batch], [Quantity]) VALUES 
('1000', '1', 10), 
('1000', '55555', 10), 
('3000', '666666', 10)


SELECT 
    [Item].[Item] AS [Item], 
    COALESCE([Location].[Batch], [Order].[Batch], [Booking].[Batch]) AS [Batch],
    [Location].[Location] AS [Location], 
    [Location].[Quantity] AS [QuantityOnLocation],
    [Order].[Quantity] AS [OrderedQuantity],
    [Booking].Quantity AS [BookedQuantity]
FROM 
    #ItemTable AS [Item]
    LEFT OUTER JOIN (
        SELECT [Item], [Quantity], [Batch], [Location]
        FROM #LocationTable)
    AS [Location] ON [Location].[Item] = [Item].[Item] 

    LEFT OUTER JOIN (
        SELECT [Item], [Quantity], [Batch]
        FROM #OrderTable) 
    AS [Order] ON [Order].[Item] = [Item].[Item] 
        AND ISNULL([Order].[Batch], '') = ISNULL([Location].[Batch], [Order].[Batch]) 

    LEFT OUTER JOIN (
        SELECT [Item], [Quantity], [Batch]
        FROM #BookingTable) 
    AS [Booking] ON [Order].[Item] = [Item].[Item]
        AND ISNULL([Booking].[Batch], '') = COALESCE([Location].[Batch], [Order].[Batch], [Booking].[Batch]) 
WHERE
    ISNULL([Location].[Quantity], 0) <> 0
    OR ISNULL([Order].[Quantity], 0) <> 0
    OR ISNULL([Booking].Quantity, 0) <> 0


DROP TABLE #ItemTable
DROP TABLE #LocationTable
DROP TABLE #BookingTable 
DROP TABLE #OrderTable

3 个答案:

答案 0 :(得分:3)

你在上一次加入时输入了一个拼写错误(我认为),这一点:

LEFT OUTER JOIN (
    SELECT [Item], [Quantity], [Batch]
    FROM #BookingTable) 
AS [Booking] ON [Order].[Item] = [Item].[Item]

不应该是:

ON [Booking].[Item] = [Item].[Item]

我稍微改写了你的查询:

SELECT 
    i.Item AS Item, 
    COALESCE(l.Batch, o.Batch, b.Batch) AS Batch,
    l.Location AS Location, 
    l.Quantity AS QuantityOnLocation,
    o.Quantity AS OrderedQuantity,
    b.Quantity AS BookedQuantity
FROM 
    #ItemTable i
    LEFT JOIN #LocationTable l ON l.Item = i.Item
    LEFT JOIN #OrderTable o ON o.Item = i.Item AND o.Batch = ISNULL(l.Batch, o.Batch) 
    LEFT JOIN #BookingTable b ON b.Item = i.Item AND b.Batch = COALESCE(l.Batch, o.Batch, b.Batch) 
WHERE
    ISNULL(l.Quantity, 0) != 0
    OR ISNULL(o.Quantity, 0) != 0
    OR ISNULL(b.Quantity, 0) != 0;

这对我来说似乎更具可读性,但我想这是个人偏好?

然后我意识到这仍然没有给你你想要的东西,所以我再次重构它以获得这个(这确实给你想要的结果):

WITH UniqueItemBatch AS (
    SELECT DISTINCT Item, Batch FROM #LocationTable
    UNION
    SELECT DISTINCT Item, Batch FROM #OrderTable
    UNION
    SELECT DISTINCT Item, Batch FROM #BookingTable)
SELECT 
    u.Item AS Item, 
    u.Batch,
    l.Location AS Location, 
    l.Quantity AS QuantityOnLocation,
    o.Quantity AS OrderedQuantity,
    b.Quantity AS BookedQuantity
FROM
    UniqueItemBatch u
    LEFT JOIN #ItemTable i ON i.Item = u.Item
    LEFT JOIN #LocationTable l ON l.Item = u.Item AND l.Batch = u.Batch
    LEFT JOIN #OrderTable o ON o.Item = u.Item AND o.Batch = u.Batch
    LEFT JOIN #BookingTable b ON b.Item = u.Item AND b.Batch = u.Batch
WHERE
    ISNULL(l.Quantity, 0) != 0
    OR ISNULL(o.Quantity, 0) != 0
    OR ISNULL(b.Quantity, 0) != 0;

答案 1 :(得分:1)

我不确定最后一列的逻辑,但这会为其他列提供所需的结果。

要根据显示为批处理的预订或位置获取查询,我已在查询中将两个表联合在一起。

如果可能,我会建议您重新审视数据结构的设计

select 
    item.Item,
    batch.Batch, 
    max(batch.location) as location,
    sum(batch.LQuantity) as QuantityOnLocation,
    orders.Quantity as OrderedQuantity,
    sum(batch.BQuantity) as BookedQuantity
from
    #ItemTable item
        left join 
        (
            select Item, Batch, quantity as BQuantity, null as Location, null  as LQuantity from #BookingTable
            union
            select item, Batch, null, Location, Quantity as LQuantity from #LocationTable
        ) batch
            on item.Item = batch.Item
    left join #OrderTable orders
        on item.Item = orders.Item and batch.Batch = orders.Batch
group by 
    item.Item,
    batch.Batch,    
    orders.Quantity

答案 2 :(得分:-1)

我想我更喜欢不同的方法。如何将所有的batchnumber都添加为空列并添加所有列。然后从每个表中更新不同的列。

像这样:

SELECT INTO #MyTableResult Batch FROM TableA
UNION 
SELECT Batch FROM TableB

等等。联盟删除了重复项。

然后你更新如下:

Update #MyTableResult SET Column A = ValueA FROM TableA WHERE 
#MyTableResult.Batch = TableA.Batch.

完成表格的所有更新后,您将获得所需的结果。