从数据透视表中获取非重复数据

时间:2014-05-29 16:18:10

标签: mysql sql

我有树桌。视频,类别和video_categories(基本上是视频和类别之间的数据透视表)。

我正在尝试获取所有没有特定类别的视频。问题是我的结果不止一次包含同一个视频,我只需要一次。

这就是我得到的

SELECT videos.* FROM videos
JOIN video_categories ON videos.id = video_categories.video_id
WHERE category_id NOT IN (64452, 1031, 32595, 1015, 26484, 1019)
ORDER BY downloads

我得到的结果是包含一个视频与视频类别数相同的次数。还有一件事是视频表有55 300行,而数据透视表video_categories有40万行,所以我不能使用DISTINCT而不是查询运行大约10秒。

我从PHP调用此查询,并且由于分页而无法从检索中手动排除类别。

有任何建议我该怎么做?

修改 一个视频可以有很多类别。所以这是多方面的关系。

2 个答案:

答案 0 :(得分:2)

你现在拥有它的查询不仅效率低下(除了我认为是错误的from子句),考虑视频在运行时有类别1和1031:

SELECT videos.* FROM Videos
JOIN video_categories ON videos.id = video_categories.video_id
WHERE category_id NOT IN (64452, 1031, 32595, 1015, 26484, 1019)
ORDER BY downloads;

此视频将被退回,因为类别1不在提供的类别列表中。您需要做的是找到包含这些类别的所有视频,然后排除这些视频。我通常会使用NOT EXISTS执行此操作,因为我认为它更符合逻辑:

SELECT  v.*
FROM    Videos AS v
WHERE   NOT EXISTS
        (   SELECT  1
            FROM    video_categories AS vc
            WHERE   vc.video_id = v.id
            AND     vc.category_id IN (64452, 1031, 32595, 1015, 26484, 1019)
        );

然而,MySQL optimises this kind of query better using LEFT JOIN/IS NULL

SELECT  v.*
FROM    Videos AS v
        LEFT JOIN video_categories AS vc
            ON vc.video_id = v.id
            AND vc.category_id IN (64452, 1031, 32595, 1015, 26484, 1019)
WHERE   vc.Video_ID IS NULL;

如果这仍然不快,那么您可能缺少逻辑索引。在您的VideosID中应该是群集密钥,在video_categories中,您应该有一个(video_idcategory_id)的复合群集密钥。

答案 1 :(得分:1)

您有桌面视频和video_categories。 目前还不知道它们之间的关系。

如果video_categories是一对一的视频表,那么您的查询将不会返回重复记录。

所以,我假设同一个视频有多个video_categories。

在这种情况下,这是一个可行的解决方案:

select * from video 
where video_id in 
(select video_id from video_category 
where category_id not in (list of meaninless ids))