复杂的SQL查询。一个聚合函数在另一个内部

时间:2019-06-02 17:32:52

标签: sql sql-server

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 个答案:

答案 0 :(得分:0)

您需要两个聚合级别,一个在电影级别,另一个在导演级别:

library(broom)
library(tidyverse)
library(splines)

d <- data.frame(x = rnorm(100, 0, 1),
                y = rnorm(100, 0, 1),
                z = rnorm(100, 0, 1))

func <-function(d){
  fit1 <- lm( y~ x + z, data = d)
  fit2 <- lm( y~x + I(z^2), data = d)
  fit3 <- lm( y~poly(x,3) + z, data = d)
  fit4 <- lm( y~ns(x, 3) + z, data = d)
  l <- list(fit1, fit2, fit3, fit4)
  names(l) <- paste0("fit", 1:4) 
  return(l)
}

mods <- func(d) 

list_representation<- map(mods,tidy)  

答案 1 :(得分:0)

尝试一下,查询中将说明过滤器:

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