Mysql:选择相对于第二个表

时间:2017-08-01 09:47:31

标签: mysql sql database

我有两张桌子:

实体:

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才会被选中。

2 个答案:

答案 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的行作为'取消'状态。