MySQL: 使用左连接的查询结果错误
MySQL: Wrong result of query using left join
我遇到了此处描述的问题:https://www.media-division.com/using-mysql-generate-daily-sales-reports-filled-gaps/(按日期对 SUM 或 COUNT 的结果进行分组时出现间隙)。我第一次尝试解决这个问题,查询 1:
SELECT
DATE_FORMAT(st.vd, '%Y-%m-%d') as d,
SUM(
CASE
WHEN st.vd IS NULL THEN 0
ELSE 1
END
) AS nrvisits
FROM
(
SELECT v.visit_date vd
FROM `temp_dates_2` t
LEFT JOIN `visits` v ON DATE(v.visit_date) = DATE(t.t_date)
ORDER BY t.t_date
) as st
GROUP BY d
ORDER BY d
(temp_dates_2 包含唯一的日期列表)。我简化了,查询2:
SELECT
DATE_FORMAT(td.t_date, '%Y-%m-%d') as d,
(SELECT COUNT(1)
FROM visits as v
WHERE DATE(v.visit_date) = DATE(td.t_date)
) as nrvisits
FROM temp_dates_2 td
GROUP BY d
ORDER BY d
两个查询都是 运行,没有语法或运行时错误,但结果不同:查询 1 提供的值要大得多。我对单个日期使用了一个非常简单的查询来澄清:
SELECT count(1) FROM visits WHERE DATE_FORMAT(visit_date, '%Y-%m-%d') = '2021-01-21'
它提供了与查询 2 相同的结果。
我的问题是:为什么查询 1 提供了错误的结果?我怀疑带有内部连接的子查询的结果 returns 对同一次访问的多条记录。
更新:sql 转储表:https://webentwicklung.ulrichbangert.de/temp_dates_2.sql https://webentwicklung.ulrichbangert.de/visits.sql
再补充一下我的评论。我建议这样做:
SELECT
t.t_date,
COUNT(v.primarykeycolumn)
FROM
temp_dates_2 t
LEFT JOIN visits v ON DATE(v.visit_date) = t.t_date
GROUP BY t.t_date
基于 temp_dates_2 仅包含日期的假设(因此不需要对它们调用 DATE()),也许 v.visit_date 也包含时间,并且 DATE( ) 正在剥离它
我还建议 q1 有一个错误,因为子查询选择了访问日期,这可能会导致日期 merge/get 丢失。这是一个例子:
Visits
2020-12-24 12:34:56 --(visit on christmas eve - shop still open
2020-12-24 23:45:00 --(visit on christmas eve - shop still open
--(no visit on christmas day - shop closed)
--(no visit on boxing day - shop closed)
2020-12-27 12:34:56 --(visit - shop reopen)
temp_dates_2
2020-12-24
2020-12-25
2020-12-26
2020-12-27
Q1 左连接子查询的结果(删除了不相关的 orderby):
SELECT v.visit_date vd
FROM `temp_dates_2` t
LEFT JOIN `visits` v ON DATE(v.visit_date) = DATE(t.t_date)
2020-12-24 --(visit on christmas eve - shop still open
2020-12-24 --(visit on christmas eve - shop still open
NULL --(no visit on christmas day - shop closed)
NULL --(no visit on boxing day - shop closed)
2020-12-27 --(visit - shop reopen)
然后 q1 分组、求和和格式等,结果是:
Date Count
2020-12-24 2
NULL 0
2020-12-27 1
实际上,它与基本 SELECT date(visit_date), count(*) FROM visits GROUP BY date(visit_date)
没有太大区别,只是它有一个代表圣诞节和节礼日合并的无用 NULL,以及 0 计数。您似乎真正想要的是:
2020-12-24 2 --(visits on christmas eve - shop still open
2020-12-25 0 --(no visit on christmas day - shop closed)
2020-12-26 0 --(no visit on boxing day - shop closed)
2020-12-27 1
由我的第一个查询给出;它使用了 COUNT() 不计算空值的事实,并且通过计算参与 LEFT JOIN 的列或通过计算主键列,我们可以确定 NULL 只发生在那种列中,因为“连接失败;在右手 table 中找不到匹配的行”,而不是因为“数据在行中自然包含空值”
例如:
temp_dates left join visits:
tempdate visitdate visitpk vistorcomment
2020-12-24 2021-12-24 1 null
2020-12-25 null null
2020-12-26 null null
2020-12-27 2021-12-27 2 "nice place"
我们应该 COUNT() visitpk
(主键永远不能为 null)或 visitdate
(如果连接失败它将为 null),我们永远不应该 COUNT 注释,因为它是有时自然为 null(访问者未发表评论)。如果我们使用 visitorcomment 作为计数,它会扭曲数字,因为它意味着“访问发生并且访问者发表了评论”
所有这些都没有回答“为什么我的数字 X 比 Y 大”,但如果没有工作示例就无法回答;创建一个 fiddle 来复制它,我会告诉你。我目前无法从数据中看出为什么 q1 的数字会更大的任何原因 - 你断言 temp_dates 是唯一的所以笛卡尔爆炸不应该发生,而且你似乎正在使用日期数据类型所以混淆了 dd/mm 和 m/dd 不应该发生,但我可以看到你如何处理 data/the 结果不是你想要的错误
这是一个解释如何获得你想要的结果、它为什么有效以及有一个更简单的查询的答案。
我遇到了此处描述的问题:https://www.media-division.com/using-mysql-generate-daily-sales-reports-filled-gaps/(按日期对 SUM 或 COUNT 的结果进行分组时出现间隙)。我第一次尝试解决这个问题,查询 1:
SELECT
DATE_FORMAT(st.vd, '%Y-%m-%d') as d,
SUM(
CASE
WHEN st.vd IS NULL THEN 0
ELSE 1
END
) AS nrvisits
FROM
(
SELECT v.visit_date vd
FROM `temp_dates_2` t
LEFT JOIN `visits` v ON DATE(v.visit_date) = DATE(t.t_date)
ORDER BY t.t_date
) as st
GROUP BY d
ORDER BY d
(temp_dates_2 包含唯一的日期列表)。我简化了,查询2:
SELECT
DATE_FORMAT(td.t_date, '%Y-%m-%d') as d,
(SELECT COUNT(1)
FROM visits as v
WHERE DATE(v.visit_date) = DATE(td.t_date)
) as nrvisits
FROM temp_dates_2 td
GROUP BY d
ORDER BY d
两个查询都是 运行,没有语法或运行时错误,但结果不同:查询 1 提供的值要大得多。我对单个日期使用了一个非常简单的查询来澄清:
SELECT count(1) FROM visits WHERE DATE_FORMAT(visit_date, '%Y-%m-%d') = '2021-01-21'
它提供了与查询 2 相同的结果。 我的问题是:为什么查询 1 提供了错误的结果?我怀疑带有内部连接的子查询的结果 returns 对同一次访问的多条记录。 更新:sql 转储表:https://webentwicklung.ulrichbangert.de/temp_dates_2.sql https://webentwicklung.ulrichbangert.de/visits.sql
再补充一下我的评论。我建议这样做:
SELECT
t.t_date,
COUNT(v.primarykeycolumn)
FROM
temp_dates_2 t
LEFT JOIN visits v ON DATE(v.visit_date) = t.t_date
GROUP BY t.t_date
基于 temp_dates_2 仅包含日期的假设(因此不需要对它们调用 DATE()),也许 v.visit_date 也包含时间,并且 DATE( ) 正在剥离它
我还建议 q1 有一个错误,因为子查询选择了访问日期,这可能会导致日期 merge/get 丢失。这是一个例子:
Visits
2020-12-24 12:34:56 --(visit on christmas eve - shop still open
2020-12-24 23:45:00 --(visit on christmas eve - shop still open
--(no visit on christmas day - shop closed)
--(no visit on boxing day - shop closed)
2020-12-27 12:34:56 --(visit - shop reopen)
temp_dates_2
2020-12-24
2020-12-25
2020-12-26
2020-12-27
Q1 左连接子查询的结果(删除了不相关的 orderby):
SELECT v.visit_date vd
FROM `temp_dates_2` t
LEFT JOIN `visits` v ON DATE(v.visit_date) = DATE(t.t_date)
2020-12-24 --(visit on christmas eve - shop still open
2020-12-24 --(visit on christmas eve - shop still open
NULL --(no visit on christmas day - shop closed)
NULL --(no visit on boxing day - shop closed)
2020-12-27 --(visit - shop reopen)
然后 q1 分组、求和和格式等,结果是:
Date Count
2020-12-24 2
NULL 0
2020-12-27 1
实际上,它与基本 SELECT date(visit_date), count(*) FROM visits GROUP BY date(visit_date)
没有太大区别,只是它有一个代表圣诞节和节礼日合并的无用 NULL,以及 0 计数。您似乎真正想要的是:
2020-12-24 2 --(visits on christmas eve - shop still open
2020-12-25 0 --(no visit on christmas day - shop closed)
2020-12-26 0 --(no visit on boxing day - shop closed)
2020-12-27 1
由我的第一个查询给出;它使用了 COUNT() 不计算空值的事实,并且通过计算参与 LEFT JOIN 的列或通过计算主键列,我们可以确定 NULL 只发生在那种列中,因为“连接失败;在右手 table 中找不到匹配的行”,而不是因为“数据在行中自然包含空值”
例如:
temp_dates left join visits:
tempdate visitdate visitpk vistorcomment
2020-12-24 2021-12-24 1 null
2020-12-25 null null
2020-12-26 null null
2020-12-27 2021-12-27 2 "nice place"
我们应该 COUNT() visitpk
(主键永远不能为 null)或 visitdate
(如果连接失败它将为 null),我们永远不应该 COUNT 注释,因为它是有时自然为 null(访问者未发表评论)。如果我们使用 visitorcomment 作为计数,它会扭曲数字,因为它意味着“访问发生并且访问者发表了评论”
所有这些都没有回答“为什么我的数字 X 比 Y 大”,但如果没有工作示例就无法回答;创建一个 fiddle 来复制它,我会告诉你。我目前无法从数据中看出为什么 q1 的数字会更大的任何原因 - 你断言 temp_dates 是唯一的所以笛卡尔爆炸不应该发生,而且你似乎正在使用日期数据类型所以混淆了 dd/mm 和 m/dd 不应该发生,但我可以看到你如何处理 data/the 结果不是你想要的错误
这是一个解释如何获得你想要的结果、它为什么有效以及有一个更简单的查询的答案。