[英]SQL Many-to-Many Query Problem
我有三个表:视频,视频类别和类别。
这些表如下所示:
videos: video_id, title, etc...
videos_categories: video_id, category_id
categories: category_id, name, etc...
在我的应用中,我允许用户多选类别。 当他们这样做时,我需要返回每个选定类别中的所有视频。
我结束了这个:
SELECT * FROM videos WHERE video_id IN (
SELECT c1.video_id FROM videos_categories AS c1
JOIN c2.videos_categories AS c2
ON c1.video_id = c2.video_id
WHERE c1.category_id = 1 AND c2.category_id = 2
)
但是对于我添加到多选中的每个类别,我必须向内部选择中添加一个联接:
SELECT * FROM videos WHERE video_id IN (
SELECT c1.video_id FROM videos_categories AS c1
JOIN videos_categories AS c2
ON c1.video_id = c2.video_id
JOIN videos_categories AS c3
ON c2.video_id = c3.video_id
WHERE c1.category_id = 1 AND c2.category_id = 2 AND c3.category_id = 3
)
我忍不住觉得这是做这件事的错误方法,但是我被阻止尝试寻找正确的方法。
如果这是主键:
videos_categories: video_id, category_id
那么GROUP BY和HAVING应该可以工作,请尝试以下操作:
SELECT
*
FROM videos
WHERE video_id IN (SELECT
video_id
FROM videos_categories
WHERE category_id IN (1,2,3)
GROUP BY video_id
HAVING COUNT(video_id)=3
)
这是一个FOR XML PATH解决方案:
--Sample data
CREATE TABLE Video
(
VideoID int,
VideoName varchar(50)
)
CREATE TABLE Videos_Categories
(
VideoID int,
CategoryID int
)
INSERT Video(VideoID, VideoName)
SELECT 1, 'Indiana Jones'
UNION ALL
SELECT 2, 'Star Trek'
INSERT Videos_Categories(VideoID, CategoryID)
SELECT 1, 1
UNION ALL
SELECT 1, 2
UNION ALL
SELECT 1, 3
UNION ALL
SELECT 2, 1
GO
--The query
;WITH GroupedVideos
AS
(
SELECT v.*,
SUBSTRING(
(SELECT (', ') + CAST(vc.CategoryID AS varchar(20))
FROM Videos_Categories AS vc
WHERE vc.VideoID = v.VideoID
AND vc.CategoryID IN (1,2)
ORDER BY vc.CategoryID
FOR XML PATH('')), 3, 2000) AS CatList
FROM Video AS v
)
SELECT *
FROM GroupedVideos
WHERE CatList = '1, 2'
尝试
WHERE c1.category_id IN (1,2,3)
要么
...
FROM videos v
JOIN Vedeos_categories vc ON v.video_id = vc.video_id
WHERE vc.category_id IN (1,2,3)
根本不需要多个联接。
编辑:将解决方案放在上下文中(我知道这并不明显):
SELECT *
FROM videos
WHERE video_id IN
( SELECT c1.video_id
FROM videos_categories AS c1
WHERE c1.category_id = IN (1,2,3))
要么
SELECT *
FROM videos v
JOIN Vedeos_categories vc ON v.video_id = vc.video_id
WHERE vc.category_id IN (1,2,3)
听起来类似于SQL搜索包含多个条件的行
为了避免每个类别都需要另一个联接(从而更改查询的结构),可以将类别放入临时表中,然后针对该表进行联接。
CREATE TEMPORARY TABLE query_categories(category_id int);
INSERT INTO query_categories(category_id) VALUES(1);
INSERT INTO query_categories(category_id) VALUES(2);
INSERT INTO query_categories(category_id) VALUES(3);
SELECT * FROM videos v WHERE video_id IN (
SELECT video_id FROM video_categories vc JOIN query_categories q ON vc.category_id = qc.category_id
GROUP BY video_id
HAVING COUNT(*) = 3
)
当然,尽管这很丑陋。 您可能要跳过临时表,而在子查询中只说'category_id IN(...)'。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.