当所有连接条件与TSQL匹配时,如何以特定顺序将2个表连接在一起

问题描述 投票:2回答:1

我遇到的问题是这样的。我需要创建一个包含以下信息的视图

订单号,订单行,装箱单号,发票号

有更多的信息,但上面的4是问题。

存在的系统没有从装箱单到发票的连接,但装箱单和发票都连接到订单行。

所以我想说我在装箱单上有这个信息

Order1 Line1 PackingSlip1 20
Order1 Line1 PackingSlip2 30
Order1 Line2 PackingSlip3 25
Order1 Line2 PackingSlip4 25

并在发票表中显示此信息

Order1 Line1 Invoice1 20
Order1 Line1 Invoice2 30
Order1 Line2 Invoice3 25
Order1 Line2 Invoice4 25

这里基本上有两种情况。第一个很简单,因为我们可以在数量,订单号和订单行上将PackingSlip表加入InvoiceTable。问题是,如果我们这样做,第二种情况(数量相同)将有4行作为输出而不是2。

所以我的问题是。如何将这两个表连接在一起,以便匹配订单号和行。然后找到第一个匹配数量并加入该行。所以我希望PackingSlip3匹配Invoice3和PackingSlip4以匹配Invoice4。

作为附加信息,包装表具有包装日期,发票表具有发票日期。所以我想加入最早的包装订单,排到最早的发票订单行。

任何帮助将不胜感激。谢谢

编辑。这里有一些示例代码

Declare @InvoiceTable as Table(
    OrderNumber nvarchar(10),
    OrderLine   int,
    InvoiceNumber nvarchar(10),
    QuantityInvoiced int
)

Declare @PackingTable as Table(
    OrderNumber nvarchar(10),
    OrderLine   int,
    PackingNumber nvarchar(10),
    QuantityPacked int
)

Insert into @PackingTable(OrderNumber, OrderLine, PackingNumber, QuantityPacked) Values ('O1', 1, 'P1', 20),('O1', 1, 'P2', 30), ('O1', 2, 'P3', 25), ('O1', 2, 'P4', 25)
Insert into @InvoiceTable(OrderNumber, OrderLine, InvoiceNumber, QuantityInvoiced) Values ('O1', 1, 'I1', 20),('O1', 1, 'I2', 30), ('O1', 2, 'I3', 25), ('O1', 2, 'I4', 25);

with ctePackingSlip as
(
    select distinct OrderNumber, OrderLine, PackingNumber, QuantityPacked
    from @PackingTable
), cteInvoice as
(
    select distinct OrderNumber, OrderLine, InvoiceNumber, QuantityInvoiced
    from @InvoiceTable
)
SELECT t0.OrderNumber, t0.OrderLine, PackingNumber, InvoiceNumber, t0.QuantityPacked
FROM ctePackingSlip As t0
JOIN @InvoiceTable As t1
    ON t0.OrderNumber = t1.OrderNumber 
   AND t0.OrderLine = t1.OrderLine
   AND t0.QuantityPacked = t1.QuantityInvoiced

问题是这输出如下

O1 1 P1 I1 20

O1 1 P2 I2 30

O1 2 P3 I3 25

O1 2 P4 I3 25

O1 2 P3 I4 25

O1 2 P4 I4 25

正如您在最后看到的那样,P3和P4有2条线。我只想要每行1行

sql tsql
1个回答
2
投票

这是非常重要的:

作为附加信息,包装表具有包装日期,发票表具有发票日期。所以我想加入最早的包装订单,排到最早的发票订单行。

根据打包/发票日期为每个组中的行分配行号,然后将其添加到连接中:

with ctePacking as
(
 SELECT OrderNumber, OrderLine, PackingSlipNumber, Quantity,
        ROW_NUMBER() OVER (PARTITION BY OrderNumber, OrderLine ORDER BY PackingDate ASC) RN
 FROM PackingSlip
)
, cteInvoice as
(
 SELECT OrderNumber, OrderLine, InvoiceNumber, Quantity,
        ROW_NUMBER() OVER (PARTITION BY OrderNumber, OrderLine ORDER BY InvoiceDate ASC) RN
 FROM Invoice
)

SELECT P.OrderNumber, P.OrderLine, P.PackingSlipNumber, I.InvoiceNumber
FROM ctePacking P
JOIN cteInvoice I ON P.OrderNumber = I.OrderNumber
              AND P.OrderLine = I.OrderLine
              AND P.RN = I.RN

编辑 - 一些解释:

这里的想法是你知道条目的时间相互关联(第一个装箱单条目=第一个发票条目),但我认为这些时间可能略有不同,所以你不能直接加入它们。

为了解决这个问题,我们可以按照有序时间对它们进行编号,然后加入该数字。

ROW_NUMBER()是一个窗口函数,它将为我们可以加入的每一行(作为新列)分配一个数字。基本语法是这样的:

ROW_NUMBER() OVER (PARTITION BY columnsInGroup ORDER BY columnsToOrderBy)

有关here的更多信息,请参阅ROW_NUMBER()

在您的情况下,我们希望按日期时间排序,并按每个订单号和订单行分组。如果订单总是一个接一个地完美插入,我们可以完全删除分区分组,但它可能更安全,所以:

ROW_NUMBER() OVER (PARTITION BY OrderNumber, OrderLine ORDER BY OrderDate) RN --RN is an alias for the new column

现在,实现添加行号列以供我们在主查询中引用的最简单方法是使用CTE。这使我们可以创建列,将其别名,并且已经可以将其用于最终查询。另一种选择是使用这样的派生表:

SELECT P.OrderNumber, P.OrderLine, P.PackingSlipNumber, I.InvoiceNumber
FROM (SELECT OrderNumber, OrderLine, PackingSlipNumber, Quantity,
            ROW_NUMBER() OVER (PARTITION BY OrderNumber, OrderLine ORDER BY PackingDate ASC) RN
     FROM PackingSlip) P
JOIN (SELECT OrderNumber, OrderLine, InvoiceNumber, Quantity,
            ROW_NUMBER() OVER (PARTITION BY OrderNumber, OrderLine ORDER BY InvoiceDate ASC) RN
     FROM Invoice) I ON P.OrderNumber = I.OrderNumber
                    AND P.OrderLine = I.OrderLine
                    AND P.RN = I.RN

对于大多数人来说,CTE是一种更清晰的方式来分离逻辑并使您的最终查询更简单。

总而言之,我们使用CTE将行号添加到基表数据,然后我们查询CTE而不是基表来访问和使用我们的连接中的新RN列。

© www.soinside.com 2019 - 2024. All rights reserved.