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 时)的主要内容,如果未能解决你的问题,请参考以下文章

在 postgresql 表中查找最大条目,sql

PostgreSQL:查找有关用户定义类型的信息

使用 PostgreSQL 范围类型查找冲突的计划

Postgresql获取具有多列的每个组的最大值[重复]

如何为postgresql中的每个用户返回具有最大值的类别?

在 Postgresql 中为每个被拒绝或接受的日期查找第一个 OPENED_DATE