HAVING,WHERE和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

EDIT 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  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

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

解决方法

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

这样想:

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

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

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

然后,如有必要,可以根据精简后的数据进行过滤。 (例如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()。

,

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

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

执行SQL查询时,SQL指令的顺序 被执行的是:

  • FROM子句
  • WHERE子句
  • GROUP BY子句
  • HAVING子句
  • SELECT子句
  • ORDER BY子句

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

一旦过滤器完成,它将基于GROUP BY子句对数据进行分组,并且仅保留那些满足HAVING子句的数据。之后,它将根据您的需要评估SELECT子句和顺序。

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

尝试获得一个最大值(在'meta_key'='value'THEN'meta_value'ELSE NULL END的情况下)> = current_date-间隔7天,而不是在where子句中放置“ DeliveryDate> = current_date-间隔7天”

,

根据@O的答案。琼斯是一个嵌套查询:

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'