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 结果不是你想要的错误

这是一个解释如何获得你想要的结果、它为什么有效以及有一个更简单的查询的答案。