类似的东西。我们按实体 ID 对状态进行分组,并在分组后将它们过滤为仅具有 MIN 和 MAX 已付费的状态。实体 7 的 MIN 为“已取消”,MAX 为“已支付”,因此被排除在外。
SELECT e.*
FROM
entities e
INNER JOIN
(
SELECT entity_id FROM statuses s
GROUP BY entity_id
HAVING
MIN(CASE WHEN status = 'canceled' THEN status ELSE 'not canceled' END) = 'not canceled' AND
MAX(CASE WHEN status = 'paid' then 'paid' ELSE 'not paid' END) = 'paid'
) a
ON
a.entity_id = e.id
根据您的评论,关于 MIN 和 MAX 的更多信息:
您说事物可以有多种状态,但实际上我们只对 PAID 事物感兴趣,然后我们只对那些从未有 CANCELED 的 PAID 事物感兴趣。我们做什么,然后状态是:
- 将“已取消”以外的所有内容都变为“未取消”
- 将“付费”以外的所有内容都变成“未付费”
- 链接行条目并查找“已付款”/“未取消”的配对
要明白我的意思,请看:
SELECT
entity_id,
CASE WHEN status = 'paid' then 'paid' ELSE 'not paid' END as is_paid,
CASE WHEN status = 'canceled' THEN status ELSE 'not canceled' END as is_cancelled
FROM
status
现在看看:
SELECT
entity_id,
MAX(CASE WHEN status = 'paid' then 'paid' ELSE 'other' END) as is_paid,
MIN(CASE WHEN status = 'canceled' THEN status ELSE 'not canceled' END) as is_cancelled
FROM
status
GROUP BY
entity_id
这是一个“枢轴”操作;它在概念上将行变成列。项目 7 的多行变为具有多列的单行。最小值和最大值可以计算出来,因为按字母顺序,“已付款”在“未付款”之后,“已取消”在“”之前。
这就是我们寻找“付费”/“未取消”配对的方式。此时我们可以这样说:
SELECT * FROM entities INNER JOIN
(
SELECT
entity_id,
MAX(CASE WHEN status = 'paid' then 'paid' ELSE 'other' END) as is_paid,
MIN(CASE WHEN status = 'canceled' THEN status ELSE 'not canceled' END) as is_cancelled
FROM
status
GROUP BY
entity_id
) finder
ON
entities.id = finder.entity_ID
WHERE
finder.is_paid = 'paid' and finder.is_canceled = 'not canceled'
使用 HAVING 进行过滤比稍后使用 WHERE 进行过滤要短一些