Сложный SQL-запрос.одна агрегатная функция внутри другой - PullRequest
0 голосов
/ 02 июня 2019
CREATE TABLE Director
(
     [Id] INT,
     [Name] NVARCHAR(MAX),
     PRIMARY KEY (Id)
);

CREATE TABLE Movie
(
     [Id] INT,
     [Title] NVARCHAR(MAX), 
     [DurationMinutes] INT, 
     [ReleaseDate] DATETIME,
     [DirectorId] INT,
     [Rating] INT NULL, 
     PRIMARY KEY (Id),
     FOREIGN KEY (DirectorId) REFERENCES Director(Id)
);

--ActorId reference actor which participated in certain movie
CREATE TABLE MovieActor
(
     [MovieId] INT,
     [ActorId] INT,
     FOREIGN KEY (MovieId) REFERENCES Movie(Id)
);

У меня есть таблица, из которой мне нужно найти: имена режиссеров, которые сняли 2 или более фильма продолжительностью> = 60 минут, в каждом из которых (!) Участвовали от 3 до 7 актеров.Рейтинг фильма должен быть 9 или выше, а дата выхода должна быть до 2006 года.

Я придумал это решение:

SELECT Name
FROM Director d
JOIN Movie m ON d.Id = m.DirectorId
JOIN MovieActor ma ON m.Id = ma.MovieId
WHERE ReleaseDate <= '2005-12-31'
  AND Rating >= 9
GROUP BY Name
HAVING COUNT(DISTINCT ma.ActorId) BETWEEN 3 AND 7 
   AND COUNT(DISTINCT CASE WHEN m.DurationMinutes >= 60 THEN m.DurationMinutes END) >= 2;

Но оно фильтрует ВСЕХ актеров во ВСЕХподходящие фильмы - возвращает количество отдельных актеров, участвовавших в режиссерских работах, вместо только полнометражных фильмов.

SELECT Name
FROM Director d
JOIN Movie m ON d.Id = m.DirectorId
JOIN MovieActor ma ON m.Id = ma.MovieId
WHERE ReleaseDate <= '2005-12-31'
  AND Rating >= 9
GROUP BY Name
HAVING COUNT(DISTINCT CASE WHEN m.DurationMinutes >= 60 
AND COUNT(DISTINCT ma.ActorId) BETWEEN 3 AND 7 > THEN m.Id END) >= 2;

Но этот код выдает ошибку:

Невозможно выполнитьФункция агрегирования в выражении, содержащем агрегат или подзапрос.


Отредактировано: Добавлены тестовые случаи и требуется вывод.

Давайте использовать эти случаи:

INSERT INTO Director
    ([Id], [Name])
VALUES
    (1, 'Bebopvsky'),
    (2, 'Tarrantino'),
    (3, 'CubeRick')
;

INSERT INTO Movie
    ([Id], [Title], [DurationMinutes], [ReleaseDate], [DirectorId], [Rating])
VALUES
    (1, 'Platform for soul', 121, '2002-12-31', 2, 9),
    (2, 'Full-featured access management', 62, '2002-01-01', 3, 10),
    (3, 'Robust LDAP server for Java', 73, '2005-05-25', 3, 9),
    (4, 'Man of Rain', 114, '2004-07-21', 1, 10),
    (5, 'Man of Arms', 152, '2003-02-17', 1, 9),
    (6, 'Man of War', 93, '2003-07-05', 2, 9),
    (7, 'Man of Legs', 23, '2004-11-11', 2, 9),
    (8, 'Mof', 75, '2002-11-11', 2, 10)
;

INSERT INTO MovieActor
    ([MovieId], [ActorId])
VALUES
    (1,1), (1,3), (1,4), (1,5),    
    (2,1), (2,5),
    (3,1), (3,2), (3,4),
    (4,1), (4,2), (4,3), (4,4), 
    (5,1), (5,2), (5,3), (5,4), (5,5),
    (6,1), (6,2), 
    (7,2), (7,4), (7,5),
    (8,1), (8,4)
;

Для наших целей давайте сделаем все фильмы Дата и рейтинг действительными.

Режиссер №1.Имейте два фильма - # 4 и # 5 , оба они полнометражные и имеют 4 и 5 актеров соответственно.Так что он будет в выходной.

Директор № 2.Есть четыре фильма - # 1, # 6, # 7, # 8 . # 1, # 6, # 8 являются полноразмерными и только # 1, # 7 имеют 4 и 3 актера.Таким образом, у него не будет одновременно двух фильмов с надлежащим актерским составом и длиной, поэтому он не будет выходить.

Режиссер № 3 У него есть два фильма - # 2, # 3 .Оба они полноформатные, но у # 2 есть только 2 актера.Так что он не будет на выходе.

Ответы [ 2 ]

0 голосов
/ 02 июня 2019

Попробуйте с этим, фильтры объясняются в запросе:

select d.Name
from Director d
  join Movie m
    on m.DirectorId=d.Id
   and m.DurationMinutes>=60 -- length >= 60 minutes
   and m.Rating>=9 -- Rating of the film must be 9 or higher
   and year(m.ReleaseDate)<2006 -- release date must be before 2006
  cross apply (
    select 1 as Pass
    from MovieActor ma
    where ma.MovieId=m.Id
    group by ma.MovieId
    having count(1) between 3 and 7 -- 3 to 7 actors participated
  ) a
group by d.Name
having count(1)>=2 -- directed 2 or more movies
0 голосов
/ 02 июня 2019

Вы хотите два уровня агрегации, один на уровне фильма, а другой на уровне режиссера:

SELECT Name
FROM (SELECT M.ID, D.Name, COUNT(*) as NumActors
      FROM Director d JOIN
           Movie m
           ON d.ID = m.DirectorID JOIN
           MovieActor ma
           ON m.ID = ma.MovieID
      WHERE m.ReleaseDate < '2006-01-01' AND
            m.Rating >= 9 AND
            m.DurationMinutes >= 60
      GROUP BY D.Name, M.ID
      HAVING COUNT(*) BETWEEN 3 AND 7
     ) m 
GROUP BY Name
HAVING COUNT(*) >= 2;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...