基于列值的条件连接

Posted

技术标签:

【中文标题】基于列值的条件连接【英文标题】:Conditional JOIN based on column value 【发布时间】:2017-12-20 19:45:15 【问题描述】:

我已经看遍了,不幸的是,我似乎无法弄清楚我做错了什么。我正在开发一个使用 mysql 服务器的个人财务管理应用程序。对于这个问题,我正在使用 4 个表。

TRANSACTIONS 表包含 CATIDBILLID 列,它们引用 SECONDARYCATEGORIESBILLS 表中的主键。 TRANSACTIONSBILLS 表都有一个列 PCATID,它引用 PRIMARYCATEGORIES 表中的主键。

我正在构建一个 SQL 查询,它对 TRANSACTIONS 表中的“金额”列求和,并从 PCATID 返回主键以及与该值关联的所有记录的总和。如果BILLID 设置为-1,它应该在SECONDARYCATEGORIES 中找到PCATID,其中SECONDARYCATEGORIES.ID = TRANSACTIONS.CATID,否则(因为-1 表示这不是账单),它应该从BILL 记录,其中BILLS.ID 匹配TRANSACTIONS.BILLID

我正在寻找这样的东西(显然不是有效的 SQL):

SELECT
 SECONDARYCATEGORIES.PCATID,
 SUM(TRANSACTIONS.AMOUNT)
FROM
 TRANSACTIONS
IF (BILLID = -1) JOIN SECONDARYCATEGORIES ON SECONDARYCATEGORIES.ID = TRANSACTIONS.CATID
ELSE JOIN SECONDARYCATEGORIES ON SECONDARYCATEGORIES.ID = BILLS.CATID WHERE BILLS.ID = TRANSACTIONS.BILLID

我尝试了无数不同的 JOIN、IF 语句等,但我似乎无法完成这项工作。我曾想过根据BILLID 的值将其分解为不同的 SQL 查询,并对这些值求和,但如果可能的话,我真的很想在一个 SQL 查询中完成所有这些操作。

我知道我在这里遗漏了一些明显的东西;非常感谢任何帮助。

编辑:我忘了描述 BILLS 表。它包含一个主要类别、ID 以及一些描述性数据。

【问题讨论】:

两个左外连接应该可以解决您的问题。但是您的 BILLS 表丢失了 我在这里没有看到 BILLS 表。 你能提供一些示例数据和预期的输出吗? 【参考方案1】:

您可以在JOIN 中使用OR,如下所示:

SELECT S.PCATID,
       SUM(T.AMOUNT)
FROM TRANSACTIONS T 
LEFT JOIN BILLS ON BILLS.ID = T.BILLID 
JOIN SECONDARYCATEGORIES S ON (S.ID = T.CATID AND T.BILLID = -1)
                           OR (S.ID = BILLS.CATID AND BILLS.ID = T.BILLID)

【讨论】:

这正是我想要的。不知何故,我的印象是在 JOIN 的 ON 部分中不允许使用 AND/OR。非常感谢您的帮助。 这种条件连接对性能有何影响?有没有其他方法可以在 JOIN 条件下不做所有决策?【参考方案2】:

您也可以在您的JOINs 中使用COALESCECASE

SELECT ID = COALESCE(s.PCATID,b.PCATID)
    ,Total = SUM(t.AMOUNT)
FROM TRANSACTIONS t
LEFT JOIN BILLS b ON b.BILLID = CASE WHEN t.BILLID <> -1 THEN t.BILLID END
LEFT JOIN SECONDARYCATEGORIES s ON s.CATID = CASE WHEN t.BILLID = -1 THEN t.CATID END
GROUP BY COALESCE(s.PCATID,b.BILLID) 

【讨论】:

这不是条件连接。那就是无条件地进行连接,然后选择一个值或另一个值。这效率不高。 @QuolonelQuestions 实际上,如果您将我的查询生成的执行计划与接受答案的查询生成的执行计划进行比较,您会发现它们几乎相同,除了一对额外的Compute Scalars在我的计划中。我的解决方案并不比在 join 子句中包含 OR 效率低。【参考方案3】:

我使用UNION 来选择任一查询。但是第二个查询显然不起作用,因为它缺少BILLS 表。

SELECT SECONDARYCATEGORIES.PCATID
    , SUM(TRANSACTIONS.AMOUNT)
FROM TRANSACTIONS
JOIN SECONDARYCATEGORIES ON SECONDARYCATEGORIES.ID = TRANSACTIONS.CATID AND BILLID = -1
UNION
SELECT SECONDARYCATEGORIES.PCATID
    , SUM(TRANSACTIONS.AMOUNT)
FROM TRANSACTIONS
JOIN SECONDARYCATEGORIES ON SECONDARYCATEGORIES.ID = BILLS.CATID AND BILLID <> -1
WHERE BILLS.ID = TRANSACTIONS.BILLID

【讨论】:

以上是关于基于列值的条件连接的主要内容,如果未能解决你的问题,请参考以下文章

基于组不变列值的条件分组

有没有一种有效的方法来计算 Pandas 中的列值,使用基于其他列的条件值的前行的值?

SELECT 与其他列值的条件不同

Pandas:如何根据其他列值的条件对列进行求和?

Azure 表存储:是不是可以使用与添加两列值的结果进行比较的查询条件?

PySpark DataFrame 根据另一列中时间戳值的最小/最大条件更新列值