我有两张桌子:
实体:
id
状态:
id
entity_id
status
每个实体都可以拥有多种状态,我只需要选择已经付款的实体'状态并且没有取消'状态。我该如何正确加入呢?
示例:
entities: id 7
entities: id 8
entities: id 9
entities: id 10
statuses: id 1, entity_id 7, status 'paid'
statuses: id 2, entity_id 7, status 'canceled'
statuses: id 3, entity_id 8, status 'paid'
statuses: id 4, entity_id 10, status 'onhold'
statuses: id 5, entity_id 8, status 'whatever'
只有8
的ID才会被选中。
答案 0 :(得分:1)
像这样的东西。我们按实体ID对状态进行分组,并在分组后仅将其过滤到具有付费的MIN和MAX的那些状态。实体7的MIN为"取消"和#34;支付"所以它被排除在外。
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事情感兴趣,然后我们只对那些付费的东西感兴趣,如果他们从来没有取消过。我们所做的,然后是状态是:
要明白我的意思,请看:
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进行此过滤只是稍微短一点
答案 1 :(得分:1)
可能类似以下内容:
SELECT e.*
FROM
entities as e INNER JOIN statuses as spaid
ON e.id = spaid.entity_id and spaid.status = 'paid'
LEFT JOIN statuses as scanceled
ON e.id = scanceled.entity_id and scanceled.status = 'canceled'
WHERE scanceled.id IS NULL
第一次加入需要付费'的实体。状态。
第二次加入会为已取消'的实体添加第二个状态。状态,或没有取消状态的实体的NULL
然后,where子句过滤条目,仅将具有NULL的行作为'取消'状态。