Postgresql 为每个类型找到最大值 transaction_id 给出重复项(当它不应该用于 PK 时)

Postgresql finding max transaction_id for each type giving duplicates (when it's not supposed to for PK)

问题如题;所以我有如下所示的代码来查找按卡类型交易的金额最高的 ID

SELECT tr.identifier, cc.type, tr.amount as max_amount
FROM credit_cards cc, transactions tr 
WHERE (tr.amount, cc.type) IN (SELECT MAX(tr.amount), cc.type   
                FROM credit_cards cc, transactions tr 
                WHERE cc.number = tr.number
                 GROUP BY cc.type)
GROUP BY tr.identifier, cc.type;

当我 运行 代码时,我得到了重复的 transaction_identifier 这不应该发生,因为它是交易的 PK table;当我 运行 上面的代码如下所示时的输出

ID --------Card type--------------- Max amount
2196    "diners-club-carte-blanche" 1000.62
2196        "visa"                  1000.62
11141   "mastercard"                1000.54
2378    "mastercard"                1000.54

例如上面的 2196 存在于食客全权而不是签证; 'mastercard' 是正确的,因为 2 个不同的 ID 可以有相同的最大交易。

但是,此代码应该 运行,因为 2 个 不同的 id 可能具有相同的每种类型的最大数量。

有谁知道如何防止重复出现?

这是因为 WHERE ... IN 子句匹配了最大金额或卡类型吗? (重复的是 Visa 和 Diners-Carte-Blanche,它们都具有相同的最大值 1000.62,所以我认为这是它们匹配错误的地方)

TL/DR:将WHERE cc.number = tr.number添加到外部查询。

长版

当您在外部查询中查询 FROM table_1, table_2 并且不连接 table 时(通过连接或 where 子句),结果是 cartesian product,表示每一行来自 table_1 的每一行都与来自 table_2 的每一行相连。这与 CROSS JOIN.

相同

因此,虽然您的内部查询有一个 where 子句和(正确地)returns 每种信用卡类型的最大值...您的外部查询没有,因此所有可能的信用组合卡和交易正在与最大值进行比较,而不仅仅是有效的。

例如,如果 cc 有三行(mastercard、visa、amex)而 tr 有三行(1、2、3),则选择“from cc, tr”会产生九行:

mastercard,1
mastercard,2
mastercard,3
visa,1
visa,2
visa,3
amex,1
amex,2
amex,3

你想要的是:

mastercard,1
visa,3
amex,2

第一行中的每一行 table 将针对第二行中的每一行重复。然后 WHERE (...) IN (...)this 行集限制为仅与内部查询中的行匹配的行。可以想象,这很容易导致重复的结果。其中一些重复项正在被外部 GROUP BY 删除,一旦此问题得到解决,就不再需要了。

作为一般规则,我从不使用 join [table_1], [table_2] 并且更喜欢始终明确进行内部或外部联接(或者在某些情况下,交叉联接)以帮助避免此类问题,并且让 reader.

更清楚
SELECT tr.identifier, cc.type, tr.amount as max_amount
FROM credit_cards cc INNER JOIN transactions tr ON (cc.number = tr.number)
WHERE (tr.amount, cc.type) IN (
  SELECT MAX(tr.amount), cc.type   
  FROM credit_cards cc 
  INNER JOIN transactions tr ON (cc.number = tr.number)
  GROUP BY cc.type
)

注意:在平局的情况下,这将为您提供每种信用卡类型的 笔交易的最大金额。