如何获得每年特定类别的计数?

时间:2019-05-17 04:33:57

标签: sql mysql-python

我正在尝试解决一个问题,该问题使我发现“每年计算一下那年只有女演员的电影数量”。

表架构如下:

--------------------   -----------------------   ----------------------
|   Movie          |   |     Person           |  |       Cast         |
--------------------   ------------------------  ----------------------
| MovieID  | year  |   |  PersonID  | Gender  |  | MovieID | PersonID |
--------------------   ------------------------  ----------------------

运行以下查询:

SELECT M.YEAR, COUNT(M.MID) NUMBER_OF_FEMALE_ONLY_MOVIES FROM MOVIE M 
WHERE M.MID IN (SELECT X.MID FROM (SELECT AX.MID, COUNT(AX.PID) TOTAL_CAST 
FROM M_CAST AX GROUP BY AX.MID) X 
WHERE 
X.TOTAL_CAST = (SELECT COUNT(A.PID) FROM M_CAST A, PERSON B WHERE A.MID = 
X.MID AND
TRIM(B.PID) = TRIM(A.PID) AND B.GENDER = 'Female')) GROUP BY M.YEAR

我的结果是:

---------------------------------------
| year | NUMBER_OF_FEMALE_ONLY_MOVIES  |
---------------------------------------
| 1999 |    1                          |
| 2005 |    1                          | 
| 2009 |    1                          |
| 2012 |    1                          |
| 2018 |    1                          |
----------------------------------------

但对于没有此类电影的年份,我需要返回0作为计数。 例如

2013 0

7 个答案:

答案 0 :(得分:1)

    WITH 
PERSON_CAST_MERGE AS
   (
    SELECT P.PID,C.MID,GENDER
    FROM PERSON P
    INNER JOIN M_CAST C ON C.PID = P.PID
   ),
    MALE_COUNT AS
   (
    SELECT F.MID FROM PERSON_CAST_MERGE F
    WHERE TRIM(F.GENDER) NOT  LIKE "%FEMALE%"
   ),
FEMALE_COUNT AS
   (
    SELECT F.MID FROM PERSON_CAST_MERGE F
    WHERE TRIM(F.GENDER) LIKE "%FEMALE%"
   ),
 ONLY_FEMALE AS
 (
    SELECT F.MID FROM FEMALE_COUNT F
    WHERE F.MID NOT IN (SELECT M.MID FROM MALE_COUNT M)
 ),
 TEST AS
 (
 SELECT M.YEAR,COUNT(M.MID) AS NO_OF_MOVIES
 FROM ONLY_FEMALE F
INNER JOIN MOVIE M ON M.MID = F.MID
GROUP BY M.YEAR
 )

 SELECT M.YEAR,
 CASE  
    WHEN M.YEAR IN (SELECT F.YEAR FROM TEST F) THEN
        (SELECT F.NO_OF_MOVIES FROM TEST F WHERE F.YEAR = M.YEAR)
    WHEN M.YEAR <> (SELECT F.YEAR FROM TEST F) THEN
        0
 END
 AS NO_OF_MOVIES
 FROM MOVIE M
 GROUP BY M.YEAR

答案 1 :(得分:1)

我建议探索 CTE 中的数据以获得更好的理解。

第一个 CTE (all_cast):返回整个电影演员表

第二个 CTE (male_present):从存在男演员的 all_cast 返回电影 ID。

结果:从 all_cast 返回电影,其中电影 ID 不存在于 male_present

WITH all_cast AS (
    SELECT SUBSTR(m."year",-4) as 'Year', m.title, trim(m.MID) as MID, p.Name, trim(p.Gender) as Gender  
    FROM Movie m
    JOIN M_Cast mc 
        ON m.MID = mc.MID
    JOIN Person p 
        ON trim(mc.PID) = p.PID
),

male_present AS (
    SELECT year, mid, name
    FROM all_cast
    WHERE Gender = 'Male'
)


SELECT year, COUNT(DISTINCT mid) as 'All Female Cast'
FROM all_cast a
WHERE NOT EXISTS (SELECT * FROM male_present WHERE a.mid = mid)
GROUP BY year

答案 2 :(得分:0)

您只需要使用带有子查询的分组依据,因为您需要引用性别为女性的人像的电影标识符

     SELECT YEAR, COUNT(*) FROM 
     MOVIE 
    Where MovieId IN (SELECT MOVIEId 
   from CAST WHERE PERSONID IN 
   (Select PersonId from Person Where 
    Gender ='FEMALE'))
    Group by Year 

答案 3 :(得分:0)

我认为可以通过联接所有表并过滤女演员的WHERE子句来解决该问题。在这种情况下,联接表也将提供更好的性能,而不是子查询。

请尝试以下代码:

Select year, count(*) 
from movie join Cast on movie.movieid=cast.movieid
join person on person.personid=cast.personid
where person.gender='Female'
group by year

请让我知道这是否适合您。

答案 4 :(得分:0)

尝试一下-需要DISTINCT MovieID,因为单个电影可能有多个女演员。 Distinct将提供电影的实际数量。

SELECT 
M.Year,
COUNT(DISTINCT MovieID)  
FROM Movie M
INNER JOIN Cast C ON M.MovieID = C.MovieID
INNER JOIN Person P ON C.PersonID = P.PersonID 
WHERE P.Gender = 'Female'
GROUP BY M.Year;

答案 5 :(得分:0)

通过使用外部左连接将您的查询与 Movie 表合并,您可以获得所需的结果。与@Lucky 发布的答案相比,花费的时间会非常短

WITH FEMALE_ONLY AS
  (SELECT M.YEAR,
          COUNT(M.MID) COUNT_ALL_FEMALE
   FROM MOVIE M
   WHERE M.MID IN
       (SELECT Q.MID
        FROM
          (SELECT MC.MID,
                  COUNT(MC.PID) total
           FROM M_CAST MC
           GROUP BY MC.MID) Q
        WHERE Q.total =
            (SELECT COUNT(A.PID)
             FROM M_CAST A,
                  PERSON B
             WHERE A.MID = Q.MID
               AND TRIM(B.PID) = TRIM(A.PID)
               AND B.Gender = 'Female'))
   GROUP BY M.YEAR)
SELECT DISTINCT M.year,
                coalesce(FO.COUNT_ALL_FEMALE, 0) FEMALE_ONLY_MOVIES
FROM Movie M
LEFT OUTER JOIN FEMALE_ONLY FO ON M.year = FO.year
ORDER BY M.year;

答案 6 :(得分:0)

你可以这样做

select z.year, count(*)
from Movie z
where not exists (select *
                  from Person x, M_Cast xy
                  where x.PID = xy.PID and xy.MID = z.MID and x.gender!='Female')
group by z.year;