我有三个表:视频,视频_类别和类别。
表格如下:
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
)
但是对于我添加到multiselect的每个类别,我必须在内部选择中添加一个连接:
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
)
我不禁觉得这是真的错误这样做的方法,但是我试图看到正确的方法来阻止它。
答案 0 :(得分:6)
如果这是主键:
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
)
答案 1 :(得分:0)
这是一个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)
答案 2 :(得分:0)
听起来类似于SQL searching for rows that contain multiple criteria
为避免为每个类别进行另一次连接(从而更改查询的结构),您可以将类别放入临时表中,然后再加入该表。
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(...)”。