SQL 仅查询一次连接表行以将付款与发票相匹配
SQL Query to join tables rows only once to match payments to invoices
我有两个表,发票和付款,如下所示:
发票:
| Vendor | Invoice No | Amount |
|--------|------------|--------|
| V1 | A1 | 1200 |
| V1 | A2 | 1000 |
| V1 | A3 | 1500 |
| V1 | A4 | 2100 |
| V1 | A5 | 1500 |
| V2 | A1 | 100 |
| V2 | A2 | 1100 |
| V2 | A3 | 400 |
| V2 | A4 | 200 |
| V2 | A5 | 600 |
付款:
| Vendor | Payment No | Amount |
|--------|------------|--------|
| V1 | P1 | 1000 |
| V1 | P2 | 1000 |
| V1 | P3 | 1500 |
| V1 | P4 | 2000 |
| V2 | P1 | 300 |
| V2 | P2 | 400 |
| V2 | P3 | 400 |
我想加入这些表,以便对于每个发票行,我只想匹配一个付款行。
例如,V1、P1 和 P2 的金额均为 1000,但只有第一个 (P1) 与发票 A2 匹配。
对于每个供应商,不匹配的仍应显示在下方:
| Seq | Vendor | Invoice No | Invoice Amount | Vendor | Payment No | Payment Amount |
|-----|--------|------------|---------------:|--------|------------|---------------:|
| 1 | V1 | A1 | 1200 | | | |
| 2 | V1 | A2 | 1000 | V1 | P1 | 1000 |
| 3 | V1 | A3 | 1500 | V1 | P3 | 1500 |
| 4 | V1 | A4 | 2100 | | | |
| 5 | V1 | A5 | 1500 | | | |
| 6 | | | | V1 | P2 | 1000 |
| 7 | | | | V1 | P4 | 2000 |
| 8 | V2 | A1 | 100 | | | |
| 9 | V2 | A2 | 1100 | | | |
| 10 | V2 | A3 | 400 | V2 | P2 | 400 |
| 11 | V2 | A4 | 200 | | | |
| 12 | V2 | A5 | 600 | | | |
| 13 | | | | V2 | P1 | 300 |
| 14 | | | | V2 | P3 | 400 |
显然,简单的连接不起作用,因为 V1、P1 和 P2 都将匹配 V1 A2
并且 V1 A2 将出现两次,如下面的 SQLFiddle 示例所示:
SQLFIDDLE
如何在不借助游标的情况下实现上述目标?
谢谢。
如果我没理解错的话,你可以用row_number()
和full join
:
select i.*, p.*
from (select i.*, row_number() over (partition by vendor, amount order by ?) as sequm
from invoices i
) i full join
(select p.*, row_number() over (partition by vendor, amount order by ?) as sequm
from payments p
) p
on p.vendor = i.vendor and p.amount = i.amount and p.seqnum = i.seqnum;
请注意,这是排列付款和发票的非常基本的方法。在现实世界中,金额通常不会很好地排列——部分付款、预付款等等。
如果这最终成为您真正的问题,请提出一个 新 问题,并提供适当的样本数据和所需的结果。
Here 是 SQL Fiddle.
我有两个表,发票和付款,如下所示:
发票:
| Vendor | Invoice No | Amount |
|--------|------------|--------|
| V1 | A1 | 1200 |
| V1 | A2 | 1000 |
| V1 | A3 | 1500 |
| V1 | A4 | 2100 |
| V1 | A5 | 1500 |
| V2 | A1 | 100 |
| V2 | A2 | 1100 |
| V2 | A3 | 400 |
| V2 | A4 | 200 |
| V2 | A5 | 600 |
付款:
| Vendor | Payment No | Amount |
|--------|------------|--------|
| V1 | P1 | 1000 |
| V1 | P2 | 1000 |
| V1 | P3 | 1500 |
| V1 | P4 | 2000 |
| V2 | P1 | 300 |
| V2 | P2 | 400 |
| V2 | P3 | 400 |
我想加入这些表,以便对于每个发票行,我只想匹配一个付款行。 例如,V1、P1 和 P2 的金额均为 1000,但只有第一个 (P1) 与发票 A2 匹配。 对于每个供应商,不匹配的仍应显示在下方:
| Seq | Vendor | Invoice No | Invoice Amount | Vendor | Payment No | Payment Amount |
|-----|--------|------------|---------------:|--------|------------|---------------:|
| 1 | V1 | A1 | 1200 | | | |
| 2 | V1 | A2 | 1000 | V1 | P1 | 1000 |
| 3 | V1 | A3 | 1500 | V1 | P3 | 1500 |
| 4 | V1 | A4 | 2100 | | | |
| 5 | V1 | A5 | 1500 | | | |
| 6 | | | | V1 | P2 | 1000 |
| 7 | | | | V1 | P4 | 2000 |
| 8 | V2 | A1 | 100 | | | |
| 9 | V2 | A2 | 1100 | | | |
| 10 | V2 | A3 | 400 | V2 | P2 | 400 |
| 11 | V2 | A4 | 200 | | | |
| 12 | V2 | A5 | 600 | | | |
| 13 | | | | V2 | P1 | 300 |
| 14 | | | | V2 | P3 | 400 |
显然,简单的连接不起作用,因为 V1、P1 和 P2 都将匹配 V1 A2
并且 V1 A2 将出现两次,如下面的 SQLFiddle 示例所示: SQLFIDDLE
如何在不借助游标的情况下实现上述目标?
谢谢。
如果我没理解错的话,你可以用row_number()
和full join
:
select i.*, p.*
from (select i.*, row_number() over (partition by vendor, amount order by ?) as sequm
from invoices i
) i full join
(select p.*, row_number() over (partition by vendor, amount order by ?) as sequm
from payments p
) p
on p.vendor = i.vendor and p.amount = i.amount and p.seqnum = i.seqnum;
请注意,这是排列付款和发票的非常基本的方法。在现实世界中,金额通常不会很好地排列——部分付款、预付款等等。
如果这最终成为您真正的问题,请提出一个 新 问题,并提供适当的样本数据和所需的结果。
Here 是 SQL Fiddle.