在OR操作中混合WHERE和HAVING

时间:2015-08-17 16:56:31

标签: mysql sql

我有以下数据库结构(为清晰起见删除了一些字段):

quotes
------
id
name

business_quotes
---------------
id
quote_id
business_id
status

对于status表中的business_quotes字段,可能的值为:

  • 0 - 引用未解答
  • 1 - 引用已解答
  • 2 - 报价已订购
  • 3 - 引用被拒绝

我想检索所有至少一个订单(status = 2的引用,其中所有关联的business_quotes记录被拒绝了。我可以通过以下查询得到一个或另一个。

获取包含订单的所有quotes

SELECT quotes.* 
FROM quotes 
INNER JOIN business_quotes 
ON quotes.id = business_quotes.quote_id 
WHERE business_quotes.status = 2 
GROUP BY quotes.id

让所有quotes被拒绝所有business_quotes

SELECT quotes.* 
FROM quotes 
INNER JOIN business_quotes 
ON quotes.id = business_quotes.quote_id 
HAVING SUM(business_quotes.status) = COUNT(business_quotes.id) * 3

我不能做的是在一个查询中混合这两个条件。

在某些情况下,可以简单地将WHERE条件转换为HAVING,如此答案中所述:https://stackoverflow.com/a/20900476/1128918。但我不能遵循相同的逻辑,因为status列不在select语句中。

3 个答案:

答案 0 :(得分:2)

这样的事情应该有效。 select中的聚合是可选的。基本上,您只需要查询具有任何“2”状态的引号,或者具有值为“3”的所有状态。

免责声明:未检查语法错误,我通常的SQL语言是T-SQL,因此可能需要调整。

SELECT 
   quotes.id,
   quotes.name,
   SUM(CASE WHEN business_quotes.status = 2 THEN 1 ELSE 0 END) as NumOrdered,
   SUM(CASE WHEN business_quotes.status = 3 THEN 1 ELSE 0 END) as NumRefused
FROM 
   quotes 
   INNER JOIN business_quotes ON quotes.id = business_quotes.quote_id 
GROUP BY 
   quotes.id, 
   quotes.name
HAVING 
   SUM(CASE WHEN business_quotes.status = 2 THEN 1 ELSE 0 END) > 0
   OR 
   SUM(CASE WHEN business_quotes.status = 3 THEN 1 ELSE 0 END) 
   = COUNT(quotes.id)

答案 1 :(得分:1)

UNION很有用的地方:

SELECT quotes.* 
FROM quotes 
INNER JOIN business_quotes 
ON quotes.id = business_quotes.quote_id 
WHERE business_quotes.status = 2 
GROUP BY quotes.id
UNION
SELECT quotes.* 
FROM quotes 
INNER JOIN business_quotes 
ON quotes.id = business_quotes.quote_id 
HAVING SUM(business_quotes.status) = COUNT(business_quotes.id) * 3

答案 2 :(得分:0)

如果每个报价至少有一个订单,那么您可以使用not exists检查所有订单是否具有特定状态,并exists检查是否至少有一个订单具有某种状态

select * from quotes q
where exists (
    select 1 from business_quotes bq
    where bq.status = 2
    and bq.quote_id = q.id
)
or where not exists (
    select 1 from business_quotes bq
    where bq.status <> 3
    and bq.quote_id = q.id
)