如何在SQL Server中只匹配一行?

x33g5p2x  于 2022-11-28  发布在  SQL Server
关注(0)|答案(1)|浏览(207)

在SQL Server 2016(v13)中连接两个表时,我遇到了以下问题,我恳请您提供帮助。
我有两个表,分别是RevenuesCashins
Revenues
| 收入ID|产品ID|发票编号|金额|
| - -|- -|- -|- -|
| 一百二十三|四百五十六|九百八十七|千|
|二百三十四| 四百五十六|九百八十七|千|
Cashins
| 现金ID|产品ID|初始编号|金额|
| - -|- -|- -|- -|
|ABC必确| 四百五十六|九百八十七|千|
|药品审评中心| 四百五十六|九百八十七|千|
目标是自动匹配现金收入(但只有一次!)。
两个表都有其唯一ID,但用于连接这些表的列是

  • 产品ID
  • 发票编号
  • 金额

对于每个表中只有一行符合这些条件的条目,一切都正常。
但是有时候,在这些列中有几行具有相同的值(如上所述),但具有唯一的ID(这不是错误,而是应该的方式)。
它的问题是,当加入它时,会产生笛卡尔积。
要重新创建表,请在此处输入以下语句:

DROP TABLE IF EXISTS Revenues
GO

CREATE TABLE Revenues 
(
    RevenueID [nvarchar](10) NULL,  
    ProductID [nvarchar](10) NULL,  
    InvoiceNo [nvarchar](10) NULL,      
    Amount money NULL
)
GO

DROP TABLE IF EXISTS CashIns
GO

CREATE TABLE CashIns 
(
    CashinID [nvarchar](10) NULL,
    ProductID [nvarchar](10) NULL,  
    InvoiceNo [nvarchar](10) NULL,      
    Amount money NULL
)
GO

INSERT INTO [Revenues] VALUES ('123', '456', '987', 1000)
INSERT INTO [Revenues] VALUES ('234', '456', '987', 1000)

INSERT INTO [CashIns] VALUES ('ABC', '456', '987', 1000)
INSERT INTO [CashIns] VALUES ('BCD', '456', '987', 1000)

所需输出:
| 收入ID|产品ID|发票编号|金额|现金ID|
| - -|- -|- -|- -|- -|
| 一百二十三|四百五十六|九百八十七|千|ABC公司|
| 二百三十四|四百五十六|九百八十七|千|药品审评中心|

SELECT 
    R.RevenueID,
    R.ProductID,
    R.InvoiceNo,
    R.Amount,
    C.CashinID,
FROM 
    [Revenues] R
LEFT JOIN 
    [CashIns] C ON R.ProductID = C.ProductID
                AND R.InvoiceNo = C.InvoiceNo
                AND R.Amount = C.Amount

结果:
| 收入ID|产品ID|发票编号|金额|现金ID|
| - -|- -|- -|- -|- -|
| 一百二十三|四百五十六|九百八十七|千|ABC公司|
| 一百二十三|四百五十六|九百八十七|千|药品审评中心|
| 二百三十四|四百五十六|九百八十七|千|ABC公司|
| 二百三十四|四百五十六|九百八十七|千|药品审评中心|
这在理论上是有道理的,但我似乎找不到一个每行只使用一次的解决方案。
我发现并尝试了两个函数:窗口函数和TOP(1)选择的OUTER APPLY函数。这两个函数都得到了相同的结果:

SELECT
    *
FROM 
    [Revenues] R
OUTER APPLY 
    (SELECT TOP(1) *
     FROM [CashIns] C) C

它从Revenues表中返回所需的列,但只与Cashins表中第一次出现的列匹配:
| 收入ID|产品ID|发票编号|金额|现金ID|
| - -|- -|- -|- -|- -|
| 一百二十三|四百五十六|九百八十七|千|ABC公司|
| 二百三十四|四百五十六|九百八十七|千|ABC公司|
我还考虑过更新Revenues表,这样匹配的CashinID就在一行的旁边,然后每次检查CashinID是否还没有在该表中使用,但是我无法使它工作...
非常感谢提前任何帮助或提示在正确的方向!

sqougxex

sqougxex1#

正如我在注解中所说的,您的数据关系存在一个根本问题。您需要在一个表中引用另一个表的唯一标识符。如果不这样做,则只能对两个表中的事务进行排序,并按行号联接它们。您是在使用希望和祈祷来联接数据,而不是使用不可靠的标识符。

--This example orders the transactions in each transaction table and uses
--the order number to join them.
WITH RevPrelim AS (
    SELECT *
      , ROW_NUMBER() OVER(PARTITION BY InvoiceNo, ProductID, Amount ORDER BY RevenueID) AS row_num
    FROM [Revenues] R
), CashinsPrelim AS (
    SELECT *
        , ROW_NUMBER() OVER(PARTITION BY InvoiceNo, ProductID, Amount ORDER BY CashinID) AS row_num
    FROM [CashIns] AS C
)
SELECT *
FROM RevPrlim AS r
    LEFT OUTER JOIN CashinsPrelim AS c
        ON c.ProductID = r.ProductID
            AND c.InvoiceNo = r.InvoiceNo
            AND c.Amount = r.Amount
            AND c.row_num = r.row_num

相关问题