mysql - 为什么我在这个 MySQL 中需要 COUNT(DISTINCT ...)?

标签 mysql sql join distinct

我有一个系统,允许用户创建要观看的视频时间表。以下 MySQL 提取事件时间表以及有关时间表中的视频数量、已观看的数量以及今天应观看的数量的信息。它通过多个连接到跟踪日程到视频关联的同一个表来实现这一点。

SELECT
    schedules.*,
    COUNT(DISTINCT sv1.vid_id) AS total_vids, #<-- the problem
    GROUP_CONCAT(DISTINCT sv1.context_node_id) AS topics,
    COUNT(sv2.vid_id) AS vids_watched,
    COUNT(sv3.vid_id) AS today
FROM schedules
JOIN schedule_vids sv1 ON schedules.id = sv1.schedule_id
LEFT JOIN schedule_vids sv2 ON schedules.id = sv2.schedule_id && sv2.watched IS NOT NULL
LEFT JOIN schedule_vids sv3 ON schedules.id = sv3.schedule_id && sv3.date = CURDATE()
WHERE user_id = ? && schedules.id = ?
GROUP BY schedules.id
ORDER BY created DESC

问题:如果我不使用COUNT (DISTINCT sv1.vid_id)(即只是COUNT(sv1.vid_id))我得到的数字远远超过真实数字。我已经在数据库中验证了这一点。有人看到我哪里出错了吗?

有趣的是,如果我删除与 sv3 的连接(当然还有 select 语句的相应部分),问题就会消失。

[更新]

下面是涉及到的两个表的表结构:

CREATE TABLE `schedules` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `name` varchar(50) NOT NULL,
 `user_id` varchar(11) NOT NULL,
 `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
 `start` date NOT NULL,
 `end` date NOT NULL,
 `inc_weekends` enum('y') DEFAULT NULL,
 `type` enum('ls','c') NOT NULL DEFAULT 'ls' COMMENT 'ls = learning schedule; c = course',
 `subj_id` varchar(30) NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=51 DEFAULT CHARSET=latin1

CREATE TABLE `schedule_vids` (
 `schedule_id` int(11) NOT NULL,
 `vid_id` varchar(11) NOT NULL,
 `context_node_id` varchar(11) NOT NULL,
 `date` date NOT NULL,
 `watched` date DEFAULT NULL,
 PRIMARY KEY (`schedule_id`,`vid_id`,`context_node_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

示例输出:

id              50
name            some-schedule
user_id         yd8i0i63bd8
created         2017-04-01 11:58:22
start           2017-04-01
end             2017-04-03
inc_weekends    y
type            ls
total_vids      91
topics          maths
vids_watched    0
today           91

最佳答案

很有可能,您不需要 distinct。问题是你的加入。改为使用条件聚合:

SELECT s.*,
       COUNT(*) AS total_vids, #<-- the problem
       GROUP_CONCAT(DISTINCT sv.context_node_id) AS topics,  -- distinct is probably still needed here
       COUNT(watched) AS vids_watched,
       SUM(sv.date = CURDATE()) AS today
FROM schedules s JOIN
     schedule_vids sv
     ON s.id = sv.schedule_id LEFT JOIN
     school_users su
     ON s.user_id = su.uid  -- I'm guessing `user_id` comes from s
WHERE s.user_id = ? AND s.id = ?
GROUP BY s.id
ORDER BY s.created DESC;

如果您在没有聚合的情况下运行查询,您将看到发生了什么。您得到的是视频的笛卡尔积,这就是计数不计的原因。

关于mysql - 为什么我在这个 MySQL 中需要 COUNT(DISTINCT ...)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43156114/

相关文章:

sql - PostgreSQL:按计算值的总和排序

mysql - 使用 MySQL 查询获取特定行的位置排名

java - 是否可以在 postgresql 中创建没有执行过程的触发器?

mysql - 如何通过从另一个表加入来更新 mysql 中的列?

mysql - 平均 SQL 触发器

join - SQL 语法挑战

sql-server-2008 - SQL SERVER 2008 JOIN 提示

laravel - 在laravel中写一个查询join sum group by

mysql - 获取 MySql 中两个日期之间的相似计数

mysql - 如何从第一行减去第二行并在mysql中生成输出列