首页 > 解决方案 > HAVING vs WHERE vs GROUP BY 子句,何时使用它们以及是否使用''

问题描述

希望这篇文章能帮助我和许多像我一样的人更好地理解 WHERE、HAVING、GROUP BY 等问题。每个人都有自己的语法方式,因为在 MYSQL 中有不止一种方法可以使某些东西工作,这个想法是帮助我完成这项工作,同时也帮助整个社区:) 以下是设计我的查询的一种建议方法。

SELECT t1.post_id, t2.name,
           MAX(case when meta_key = 'value' THEN `meta_value` ELSE NULL END) as  Email,
       MAX(CASE WHEN `meta_key` = 'value' THEN `meta_value` ELSE NULL END) as CustomerId,
       MAX(CASE WHEN `meta_key` = 'value' THEN `meta_value` ELSE NULL  END) as DeliveryDate,
        MAX(CASE WHEN `meta_key` = 'value' THEN `meta_value` ELSE NULL  END) as DeliveryTime,
        MAX(CASE WHEN `meta_key` = 'value' THEN `meta_value` ELSE NULL  END) as DeliveryType,
          MAX(case when meta_key = 'value' THEN `meta_value` ELSE NULL END) as  Zip,
       MAX(case when meta_key = 'value' THEN `meta_value` ELSE NULL END) as  OrderNote,
       MAX(case when meta_key = 'value' THEN `meta_value` ELSE NULL END) as  PaymentTotal,
       MAX(case when meta_key = 'value' THEN `meta_value` ELSE NULL END) as  OrderStatus

FROM table_A  t1
inner join table_B t2 on find_in_set(t1.post_id, t2.payment_ids)
where  OrderStatus rlike '%trans%|ready'
    and DeliveryDate >= current_date - interval 7 day
    and DeliveryType = 'pickup'
group by 
    t1.post_id, 
    t2.name

这会产生错误>>>>“#1054 - 'where 子句'中的未知列'DeliveryDate'”我认为它会产生此错误,因为“orderStatus”不是实际的列名,而是从另一列中提取的值,然后通过以下方式制作自己的专栏:

MAX(case when meta_key = '_order_status' THEN `meta_value` ELSE NULL END) as  OrderStatus

所以我假设我需要在语句的 SELECT 区域和 WHERE 区域中将名称括在“”中。但是会产生错误 >>>>>>>>>>>>“警告:#1292 截断不正确的日期值:'DeliveryDate'”

为什么会这样,解决方案是什么?

编辑因为有些人建议不能以上述方式使用 WHERE 子句,所以我使用下面的代码使用了 HAVING 子句。这是代码:

选择.......^^从上面............

FROM table_A t1
inner join table_B t2 on find_in_set(t1.post_id, t2.payment_ids)
GROUP BY post_id
HAVING DeliveryDate = (DATE_SUB(CURDATE(), INTERVAL 7 DAY)) 
AND DeliveryType = 'pickup' 
AND  OrderStatus = 'ready' 
OR OrderStatus = 'transit'
ORDER BY 'DeliveryTime'  DESC

以上也不起作用。这里的问题是 AND 子句更重要,并且似乎淘汰了日期过滤器。当我使用此代码时,无论日期如何,它都会返回所有记录。

编辑 2 >>>>>>>>>> 也试过了,但它仍然没有过滤掉 3 个月大的条目

选择.......^^从上面............

FROM table_A t1
inner join table_B t2 on find_in_set(t1.post_id, t2.payment_ids)
GROUP BY post_id
HAVING MAX(CASE WHEN 'meta_key' = 'value' THEN 'meta_value' ELSE NULL END)>= current_date - interval 7 day 
AND DeliveryType = 'pickup' 
AND  OrderStatus = 'ready' 
OR OrderStatus = 'transit'
ORDER BY 'DeliveryTime'  DESC

编辑 3 >>>>>>>>>> 简化代码。结果相同。即使使用 CURDATE() 仍然显示 3 个月前的记录

……………………………………………………………………………………………………………………

FROM table_A t1
inner join table_B t2 on find_in_set(t1.post_id, t2.payment_ids)
GROUP BY post_id
HAVING MAX(CASE WHEN 'meta_key' = 'value' THEN 'meta_value' ELSE NULL END)= CURDATE()
AND DeliveryType = 'pickup' 
AND  OrderStatus = 'ready' 
OR OrderStatus = 'transit'
ORDER BY 'DeliveryTime'  DESC

编辑 4 >>>>>>>>>>>>>>>>>>>>>> 最小的例子...

选择 t1.post_id,t2.name,

   MAX(CASE WHEN `meta_key` = 'value' THEN `meta_value` ELSE NULL  END) as DeliveryDate,
    MAX(CASE WHEN `meta_key` = 'value' THEN `meta_value` ELSE NULL  END) as DeliveryTime,
    MAX(CASE WHEN `meta_key` = 'value' THEN `meta_value` ELSE NULL  END) as DeliveryType,
   MAX(case when meta_key = 'value' THEN `meta_value` ELSE NULL END) as  OrderStatus

FROM table_A t1
inner join table_B t2 on find_in_set(t1.post_id, t2.payment_ids)
GROUP BY post_id
HAVING MAX(CASE WHEN 'meta_key' = 'value' THEN 'meta_value' ELSE NULL END)= CURDATE()
AND DeliveryType = 'pickup' 
AND  OrderStatus = 'ready' 
OR OrderStatus = 'transit'
ORDER BY 'DeliveryTime'  DESC

我希望这只会返回今天的记录。它返回所有时间的所有记录,同时满足其他 HAVING 子句要求

标签: mysqlgroup-bywhere-clausehaving-clause

解决方案


您是正确的,WHERE 子句不能引用同一查询中的列别名。

这样想:

满足查询的第一步是从 FROM、JOIN 和 ON 子句构造一个虚拟表。

第二步是根据 WHERE 子句过滤该虚拟表。

第三步是根据需要减少虚拟表,根据 GROUP BY 和聚合函数(SUM、COUNT、GROUP_CONCAT 等)

然后,如有必要,HAVING 基于减少的数据进行过滤。(HAVING COUNT(*) > 1例如。)

然后,SELECT 子句选择、计算并使用别名命名要从查询返回的列。

最后,ORDER BY 子句进行排序操作。

因此,当查询计划器执行 WHERE 过滤时,SELECT 子句中的别名和计算列值尚未在范围内。

解决方案是将一个查询嵌套在另一个查询中,如下所示:

SELECT q.* FROM (
   SELECT a, b, c AS number
     FROM tbl
    WHERE whatever ) q
  WHERE q.number > 2

别名或内部查询在外部查询的 WHERE 子句的范围内。

这种查询模式很常见,查询优化器会尽可能高效地处理它们。

而且,您违反了 wp_postmeta 将每个值表示为文本字符串的方式的限制。如果要对此类值进行日期运算,请先使用 STR_TO_DATE()。


推荐阅读