【问题标题】:Match every record only once in a joined table在连接表中只匹配每条记录一次
【发布时间】:2018-07-23 18:14:42
【问题描述】:

我有两张桌子。第一个inv 包含发票记录,第二个包含payments。我想通过inv_amountinv_date 匹配inv 表中的付款。同一天可能有不止一张相同金额的发票,而且同一天可能有不止一张相同金额的付款。

付款应与第一张匹配的发票匹配,并且每次付款只能匹配一次。

这是我的数据:

inv

 inv_id | inv_amount |  inv_date  | inv_number
--------+------------+------------+------------
      1 |         10 | 2018-01-01 |          1
      2 |         16 | 2018-01-01 |          1
      3 |         12 | 2018-02-02 |          2
      4 |         14 | 2018-02-03 |          3
      5 |         19 | 2018-02-04 |          3
      6 |         19 | 2018-02-04 |          5
      7 |          5 | 2018-02-04 |          6
      8 |         40 | 2018-02-04 |          7
      9 |         19 | 2018-02-04 |          8
     10 |         19 | 2018-02-05 |          9
     11 |         20 | 2018-02-05 |         10
     12 |         20 | 2018-02-07 |         11

pay

 pay_id | pay_amount |  pay_date
--------+------------+------------
      1 |         10 | 2018-01-01
      2 |         12 | 2018-02-02
      4 |         19 | 2018-02-04
      3 |         14 | 2018-02-03
      5 |          5 | 2018-02-04
      6 |         19 | 2018-02-04
      7 |         19 | 2018-02-05
      8 |         20 | 2018-02-07

我的查询:

 SELECT DISTINCT ON (inv.inv_id) inv.inv_id,
    inv.inv_amount,
    inv.inv_date,
    inv.inv_number,
    pay.pay_id
   FROM ("2016".pay
     RIGHT JOIN "2016".inv ON (((pay.pay_amount = inv.inv_amount) AND (pay.pay_date = inv.inv_date))))
  ORDER BY inv.inv_id

导致:

 inv_id | inv_amount |  inv_date  | inv_number | pay_id
--------+------------+------------+------------+--------
      1 |         10 | 2018-01-01 |          1 |      1
      2 |         16 | 2018-01-01 |          1 |
      3 |         12 | 2018-02-02 |          2 |      2
      4 |         14 | 2018-02-03 |          3 |      3
      5 |         19 | 2018-02-04 |          3 |      4
      6 |         19 | 2018-02-04 |          5 |      4
      7 |          5 | 2018-02-04 |          6 |      5
      8 |         40 | 2018-02-04 |          7 |
      9 |         19 | 2018-02-04 |          8 |      6
     10 |         19 | 2018-02-05 |          9 |      7
     11 |         20 | 2018-02-05 |         10 |
     12 |         20 | 2018-02-07 |         11 |      8

记录inv_id = 6不应该与pay_id = 4匹配,因为这意味着支付4被插入了两次

想要的结果:

inv_id | inv_amount |  inv_date  | inv_number | pay_id
--------+------------+------------+------------+--------
      1 |         10 | 2018-01-01 |          1 |      1
      2 |         16 | 2018-01-01 |          1 |
      3 |         12 | 2018-02-02 |          2 |      2
      4 |         14 | 2018-02-03 |          3 |      3
      5 |         19 | 2018-02-04 |          3 |      4
      6 |         19 | 2018-02-04 |          5 |        <- should be empty**
      7 |          5 | 2018-02-04 |          6 |      5
      8 |         40 | 2018-02-04 |          7 |
      9 |         19 | 2018-02-04 |          8 |      6
     10 |         19 | 2018-02-05 |          9 |      7
     11 |         20 | 2018-02-05 |         10 |
     12 |         20 | 2018-02-07 |         11 |      8

免责声明:是的,我昨天用原始数据提出了这个问题,但有人指出我的 sql 很难阅读。因此,我试图为我的问题创建一个更清晰的表示。

为方便起见,这里有一个要测试的 SQL Fiddle:http://sqlfiddle.com/#!17/018d7/1

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    看到示例后,我想我已经为您找到了查询:

    WITH payments_cte AS (
        SELECT
            payment_id,
            payment_amount,
            payment_date,
            ROW_NUMBER() OVER (PARTITION BY payment_amount, payment_date ORDER BY payment_id) AS payment_row
        FROM payments
    ), invoices_cte AS (
        SELECT
            invoice_id,
            invoice_amount,
            invoice_date,
            invoice_number,
            ROW_NUMBER() OVER (PARTITION BY invoice_amount, invoice_date ORDER BY invoice_id) AS invoice_row
        FROM invoices
    )
    SELECT invoice_id, invoice_amount, invoice_date, invoice_number, payment_id
    FROM invoices_cte
    LEFT JOIN payments_cte
        ON payment_amount = invoice_amount
        AND payment_date = invoice_date
        AND payment_row = invoice_row
    ORDER BY invoice_id, payment_id
    

    【讨论】:

    • 感谢您的回答和编辑。我刚刚看到数据的顺序错误。我更新了帖子和 sqlfiddle。但是,在您的查询中缺少记录。没有 inv_id 3,6 和 12。我用所需的结果更新了帖子。
    • @user2626227 我已经更新了查询,我认为这正是您想要的:)
    • 感谢您更新查询。但是,通过此查询,pay_id 4 与 invoice_id 6 匹配,而不是第一种可能的 invoice_id 5。我插入了一些真实数据并使用了您的查询。 sqlfiddle.com/#!17/72ee1/1。如您所见,payment_id 6201 不在应有的位置,payment_id 6212 和 6218 完全不正常。我想也许我正在尝试做的事情对于 sql 查询是不可能的。付款应将日期和金额的记录与发票从上到下以及金额和日期匹配的地方随机匹配。
    • 公用表表达式(带有查询)可能仍然可行,但编写起来有点困难,而且我的时间有点紧。
    • @leu 我再次更新了答案,这应该通过唯一比较所有重复项来处理所有边缘情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多