SQL Query返回与任何或所有过滤器匹配但不超过过滤器的行

时间:2017-11-30 15:49:16

标签: sql tsql

我尝试做的简化方案是:

我有一个代表过滤器的列表。

我想从一个表中进行选择,只包含连接到一个匹配一个或多个过滤器值的表的行,但也排除在过滤器中不存在值的结果。

例如:我想要的结果是

MovieA
MovieB

任何人都可以帮忙解决问题。

CREATE TABLE [Movie] (Name VARCHAR(100) NOT NULL)
CREATE TABLE [Actor] (Name VARCHAR(100) NOT NULL)
CREATE TABLE [Character] (Name VARCHAR(100) NOT NULL, Movie VARCHAR(100) NOT NULL, Actor VARCHAR(100) NOT NULL)

INSERT INTO Movie (Name) VALUES ('MovieA'), ('MovieB'), ('MovieC')
INSERT INTO Actor (Name) VALUES ('Bob'), ('Fred'), ('Sally')
INSERT INTO [Character] (Name, Movie, Actor) VALUES ('BobA', 'MovieA', 'Bob')
INSERT INTO [Character] (Name, Movie, Actor) VALUES ('BobB', 'MovieB', 'Bob')
INSERT INTO [Character] (Name, Movie, Actor) VALUES ('BobC', 'MovieC', 'Bob')
INSERT INTO [Character] (Name, Movie, Actor) VALUES ('FredA', 'MovieA', 'Fred')
INSERT INTO [Character] (Name, Movie, Actor) VALUES ('FredC', 'MovieC', 'Fred')
INSERT INTO [Character] (Name, Movie, Actor) VALUES ('SallyC', 'MovieC', 'Sally')

CREATE TYPE [Names] AS TABLE([Name] VARCHAR(100) NOT NULL)

DECLARE @ActorNamesFilter dbo.Names
INSERT INTO @ActorNamesFilter (Name) VALUES ('Bob'), ('Fred')

-- I want to return all movies that include *any* of the above actors but exclude movies that have other actors in them.

SELECT m.Name
FROM [Character] c
    INNER JOIN Movie m ON c.Movie = m.Name
    LEFT OUTER JOIN Actor a ON c.Actor = a.Name
    LEFT OUTER JOIN @ActorNamesFilter filter ON a.Name = filter.Name

2 个答案:

答案 0 :(得分:1)

你可以从Character& amp;过滤表Demo

SELECT
      Character.Movie
FROM Character
LEFT JOIN ActorNamesFilter filter ON Character.Actor = filter.Name
GROUP BY
      Character.Movie
HAVING COUNT(DISTINCT Character.Actor) = COUNT(DISTINCT filter.name) 

<强> Results

|  Movie |
|--------|
| MovieA |
| MovieB |

答案 1 :(得分:0)

您可以使用group byhaving

SELECT m.Name
FROM [Character] c INNER JOIN
     Movie m
     ON c.Movie = m.Name JOIN
     Actor a 
     ON c.Actor = a.Name JOIN
     @ActorNamesFilter filter
     ON a.Name = filter.Name
GROUP BY m.Name
HAVING COUNT(*) = (SELECT COUNT(*) FROM @ActorNamesFilter);

这会计算影片中的演员数量,然后检查匹配数量是否与过滤器中的名称数量相同。

作为注释:如果演员可以播放多个角色,那么这应该使用count(distinct)

HAVING COUNT(DISTINCT a.Name) = (SELECT COUNT(*) FROM @ActorNamesFilter);

编辑:

我想我误解了原来的问题。以下内容确保所有actor都明确地位于actor列表中:

SELECT m.Name
FROM [Character] c LEFT JOIN
     Movie m
     ON c.Movie = m.Name LEFT JOIN
     Actor a 
     ON c.Actor = a.Name LEFT JOIN
     @ActorNamesFilter filter
     ON a.Name = filter.Name
GROUP BY m.Name
HAVING COUNT(*) = COUNT(filter.name) ;

Here是一个SQL小提琴。