Postgresql 查找每个类型的最大 transaction_id 给出重复项(当它不应该用于 PK 时)
Posted
技术标签:
【中文标题】Postgresql 查找每个类型的最大 transaction_id 给出重复项(当它不应该用于 PK 时)【英文标题】:Postgresql finding max transaction_id for each type giving duplicates (when it's not supposed to for PK) 【发布时间】:2021-11-05 09:23:07 【问题描述】:问题作为标题;所以我有一个如下所示的代码来查找按卡类型交易金额最高的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,这不应该发生,因为它是 transactions 表的 PK;当我运行上面的代码时的输出如下所示
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 存在于 diners carte-blanche 而不是签证; 'mastercard' 是正确的,因为 2 个不同的 ID 可以有相同的最大交易量。
但是,此代码应该运行,因为 2 个不同的 id 可能对每种类型具有相同的最大数量。
有谁知道如何防止重复发生?
这是因为 WHERE ... IN 子句匹配最大金额或卡类型吗? (有重复的是 Visa 和 Diners-Carte-Blanche,它们的最大值都是 1000.62,所以我认为这就是它们匹配错误的地方)
【问题讨论】:
那SELECT
给你一个错误?确切的错误信息是什么?
它实际上并没有给出错误,但我得到了重复的 ID 值。被 PK 的 ID 不应出现两次(其中一个重复的 ID 与与其无关的卡匹配)
请勿将图像用于文本信息。将输出作为文本复制并粘贴到您的问题中。此外,如果没有某种方式将外部查询中的 identifier
链接到子选择中的 identifier
,我也看不到这是如何进行的。
@AdrianKlaver ok 删除它并作为单独的代码块放入以方便参考。问题是它“有效”,因为 2 个 ID 可能具有相同的最大金额(例如上面的万事达卡),但对于上面的 id 2196,签证和用餐者不能出现两次(假设 2196 是 PK + 它只与一种类型相关联)
【参考方案1】:
TL/DR:将WHERE cc.number = tr.number
添加到外部查询。
加长版
当您在外部查询中查询 FROM table_1, table_2
并且不连接表(通过连接或 where 子句)时,结果是 cartesian product,这意味着 table_1 中的每一行都连接到 table_2 中的每一行。这与CROSS JOIN
相同。
因此,虽然您的内部查询有一个 where
子句并且(正确地)返回每种信用卡类型的最大值......但您的外部查询没有,因此信用卡和交易的所有可能组合正在与最大值,而不仅仅是有效的。
例如,如果 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
第一个表中的每一行将针对第二个表中的每一行重复。然后 WHERE (...) IN (...)
将 this 行集限制为仅与内部查询中的行匹配的行。可以想象,这很容易导致重复的结果。其中一些重复项已被外部 GROUP BY
删除,一旦此问题得到解决,就不需要这样做了。
作为一般规则,我从不使用 join [table_1], [table_2]
并且更喜欢始终明确地说明进行内部或外部联接(或者,在某些情况下,交叉联接),以帮助避免此类问题并更清楚地说明读者。
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
)
注意:在平局的情况下,这将为您提供与最大金额绑定的每种信用卡类型的每笔笔交易。
【讨论】:
感谢您的深入解释!绝对帮助我更好地理解它以上是关于Postgresql 查找每个类型的最大 transaction_id 给出重复项(当它不应该用于 PK 时)的主要内容,如果未能解决你的问题,请参考以下文章