HAVING vs WHERE vs GROUP BY 子句,何时使用它们以及是否使用 ' '

HAVING vs WHERE vs GROUP BY clauses, when to use them and if you use ' '

希望这个 post 能帮助我和许多像我一样的人更好地理解 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 clause' 中的未知列 'DeliveryDate'” 我认为它会产生此错误,因为“orderStatus”不是实际的列名,而是一个从另一列中提取值,然后通过 :

使其成为自己的列
MAX(case when meta_key = '_order_status' THEN `meta_value` ELSE NULL END) as  OrderStatus

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

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

EDITING Because some have suggested the WHERE clause can not be used in the manner above, I have used the HAVING clause using the code below. Here is the code:

SELECT.......^^自上图......

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 子句更重要并且似乎会排除日期过滤器。当我使用此代码时,这 returns 所有记录,无论日期如何。

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

SELECT.......^^自上图......

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 >>>>>>>>>>>>>>>>>>>>>>>> 最小的例子...

SELECT 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

我希望这 return 只有今天的记录。 IT 是 return 所有时间的所有记录,同时满足其他 HAVING 子句要求

您需要了解如何mysql理解查询以及如何mysql执行它。

https://qxf2.com/blog/mysql-query-execution/

When you execute a SQL query, the order in which the SQL directives get executed is:

  • FROM clause
  • WHERE clause
  • GROUP BY clause
  • HAVING clause
  • SELECT clause
  • ORDER BY clause

也就是说,首先 mysql 将评估 FROM 和 Join 子句,然后是 WHERE 子句,它将从 FROM/JOIN 子句中过滤数据集。

过滤完成后,它将根据 GROUP BY 子句对数据进行分组,并且只保留满足 HAVING 子句的数据。之后,它评估 SELECT 子句并按您想要的顺序排序。

对于您的问题,您尝试使用已在 select 子句中定义的字段 (DeliveryDate) 作为过滤器。

尝试 HAVING MAX(CASE WHEN 'meta_key' = 'value' THEN 'meta_value' ELSE NULL END) >= current_date - 间隔 7 天而不是将“DeliveryDate > = current_date - where 子句中的间隔 7 天"

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

这样想:

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

第二步是根据 WHERE 子句筛选虚拟 table。

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

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

然后,SELECT 子句使用别名从查询中选择、计算和命名 return 的列。

最后 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()。

@O 的回答。 Jones 是一个嵌套查询:

SELECT post_id
     , name
     , Email
     , CustomerId
     , DeliveryDate
     , DeliveryTime
     , DeliveryType
     , Zip
     , OrderNote
     , PaymentTotal
     , OrderStatus
  FROM ( 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)  
         GROUP 
             BY t1.post_id
              , t2.name  
       ) AS derived_table
 WHERE OrderStatus RLIKE '%trans%|ready'
   AND DeliveryDate >= CURRENT_DATE - INTERVAL 7 DAY
   AND DeliveryType = 'pickup'