select customer_id, min(order_date) as first_date, customer_pref_delivery_date
from Delivery
group by customer_id
ORDER BY customer_id;
这是输入表Delivery
:
delivery_id | customer_id | order_date | customer_pref_delivery_date |
---|---|---|---|
1 | 1 | 2019-08-01 | 2019-08-02 |
2 | 2 | 2019-08-02 | 2019-08-02 |
3 | 1 | 2019-08-11 | 2019-08-12 |
4 | 3 | 2019-08-24 | 2019-08-24 |
5 | 3 | 2019-08-21 | 2019-08-22 |
6 | 2 | 2019-08-11 | 2019-08-13 |
7 | 4 | 2019-08-09 | 2019-08-09 |
这是我的结果:
customer_id | first_date | customer_pref_delivery_date |
---|---|---|
1 | 2019-08-01 | 2019-08-02 |
2 | 2019-08-02 | 2019-08-02 |
3 | 2019-08-21 | 2019-08-24 |
4 | 2019-08-09 | 2019-08-09 |
这是预期的结果:
customer_id | first_date | customer_pref_delivery_date |
---|---|---|
1 | 2019-08-01 | 2019-08-02 |
2 | 2019-08-02 | 2019-08-02 |
3 | 2019-08-21 | 2019-08-22 |
4 | 2019-08-09 | 2019-08-09 |
您能帮我,为什么当order_date为2019-08-24时,客户3的customer_pref_delivery_date来自不同行?甚至我将其设置为MIN(order_date),我认为SQL将从同一行返回customer_pref_delivery_date。为什么不是这种情况以及如何解决此问题?
太感谢了!
往上看!太感谢了!
问题是您要选择customer_pref_delivery_date
列,但没有将其添加到GROUP BY
子句中或将其放入聚合功能中。
这通常是无效的SQL语法。因此,这是"luck"的纯粹,该查询完全是执行的,不会产生错误消息。
获得所需结果的一个选项是使用CTE
,该CTE
为每个customer_id获取MIN(order_date)
,然后使用外部查询添加其他列:
WITH minData AS
(SELECT customer_id, MIN(order_date) AS order_date
FROM Delivery
GROUP BY customer_id)
SELECT
customer_id,
order_date AS first_date,
customer_pref_delivery_date
FROM Delivery
WHERE
(customer_id, order_date) IN
(SELECT customer_id, order_date FROM minData)
ORDER BY customer_id;
IN
子句(您也可以使用INNER JOIN
)确保仅获取相关行。
这里是基于您的数据的样品小提琴。
为了防止以后的问题:如上所述,您应该注意使用GROUP BY
时使用有效的语法。您要选择的那些列必须添加到GROUP BY
子句中,或在MIN
,MAX
,AVG
等的聚合功能中使用。
否则,当不遵守这些规则时,不正确的结果将是您将遇到的最佳情况。通常,您会收到这样的错误消息:
Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'Delivery.customer_pref_delivery_date' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
不幸的是,MySQL
有一些丑陋的黑客,可以使用错误的语法。如果您观察到这种情况,我强烈建议将其禁用。因此,您将避免您的问题中解释的问题。
以下命令应停止此模式并启用"standard"模式:
SET sql_mode = 'ONLY_FULL_GROUP_BY';
这样做,您不会想知道意外结果,但会了解GROUP BY
语法的问题,因此解决问题要容易得多。