Sqlite 查找电影在发行当年的出租次数
我有这样的设置:Sqlite 查找电影在发行当年的出租次数,sqlite,Sqlite,我有这样的设置: Movies ( movieId INTEGER PRIMARY KEY, title TEXT, year INTEGER ) Rentals ( cardNo INTEGER, movieId INTEGER, date DATE, rating INTEGER, PRIMARY KEY(cardNo, movieID, date), FOREIGN KEY (cardNo) REFERENCES C
Movies (
movieId INTEGER PRIMARY KEY,
title TEXT,
year INTEGER
)
Rentals (
cardNo INTEGER,
movieId INTEGER,
date DATE,
rating INTEGER,
PRIMARY KEY(cardNo, movieID, date),
FOREIGN KEY (cardNo) REFERENCES Customers,
FOREIGN KEY (movieId) REFERENCES Movies
)
我想知道哪部电影在一年中被出租的次数最多,如果且仅当电影在那一年发行
例如:如果电影_x在2003年租得最多,但在2003年也没有发行,那么它就不算了。如果这部电影都是在2003年发行的,并且在2003年租了最多的(当年发行的电影),那么它确实算数
我想我需要设置一个临时表来存储movieId
和count(movieId)
,这样我就可以对计数执行selectmax()
我正在使用python,因此我可以将max()
的movieId
存储在一个变量中,然后检查原始movies
列以将其与电影的标题匹配,如果有帮助的话。这个答案中使用的策略是将租赁
和电影
表连接在一起,以匹配电影ID
和年份。这用于丢弃租赁
表中未在电影发行的同一年出现的任何记录
我们可以聚合这样一个连接,然后生成整个数据库的年/电影租赁计数。但是,由于您只希望电影在给定的一年中拥有最高的出租率,我们需要做更多的工作。在本例中,我们可以找到每年最高的租金计数(请参见下面的子查询t2
),并加入前面描述的子查询
SELECT
t1.movieId,
t1.title,
t1.year,
t1.num_rentals
FROM
(
SELECT
m.movieId,
m.title,
m.year,
COUNT(*) AS num_rentals
FROM Rentals r
INNER JOIN Movies m
ON r.movieId = m.movieId AND CAST(SUBSTR(r.date, 1, 4) AS INTEGER) = m.year
GROUP BY
m.movieId,
m.title,
m.year
) t1
INNER JOIN
(
SELECT year, MAX(num_rentals) AS max_num_rentals
FROM
(
SELECT
m.year,
COUNT(*) AS num_rentals
FROM Rentals r
INNER JOIN Movies m
ON r.movieId = m.movieId AND CAST(SUBSTR(r.date, 1, 4) AS INTEGER) = m.year
GROUP BY
m.movieId,
m.year
) t
GROUP BY year
) t2
ON t1.year = t2.year AND t1.num_rentals = t2.max_num_rentals
-- WHERE t1.year = 2003
ORDER BY
t1.year;
这个答案将报告所有年份,以及该年发行的所有租金最高的电影。如果某一年中有两部或两部以上的电影出现平局,则会报告所有平局的电影
请注意,如果SQLite支持分析函数,查询可以大大简化。这里有一种稍微不同的方法,使用CTE而不是嵌套子查询
WITH first_year_rentals(movieid, title, rentals, year) AS
(SELECT m.movieid, m.title, count(*), m.year
FROM movies AS m
JOIN rentals AS r ON m.movieid = r.movieid AND m.year = strftime('%Y', r.date)
GROUP BY m.movieid)
, maximums(year, maxrent) AS
(SELECT year, max(rentals)
FROM first_year_rentals
GROUP BY year)
SELECT movieid, title, rentals, f.year AS year
FROM first_year_rentals AS f
JOIN maximums AS m ON f.year = m.year AND m.maxrent = f.rentals
ORDER BY f.year, title;
CTE(公共表表达式)类似于只存在一条语句的视图。非常方便地组织具有多个查询的语句。第一个生成的结果计算出每部电影在发行当年的出租次数。第二个是每年新版本的最高租金。然后,只需加入两个CTE,并将结果限制在租赁数量等于该电影发行年度最高的行
编辑:
使用以下表格和数据进行测试:
CREATE TABLE Movies (
movieId INTEGER PRIMARY KEY,
title TEXT,
year INTEGER
);
INSERT INTO Movies VALUES(1,'a good movie',2003);
INSERT INTO Movies VALUES(2,'a better movie',2003);
INSERT INTO Movies VALUES(3,'the best movie',2004);
INSERT INTO Movies VALUES(4,'the worst movie',2004);
CREATE TABLE Rentals (
cardNo INTEGER,
movieId INTEGER,
date DATE,
rating INTEGER,
PRIMARY KEY(cardNo, movieID, date),
-- FOREIGN KEY (cardNo) REFERENCES Customers,
FOREIGN KEY (movieId) REFERENCES Movies
);
INSERT INTO Rentals VALUES(1,1,'2003-01-01',NULL);
INSERT INTO Rentals VALUES(1,2,'2003-01-01',NULL);
INSERT INTO Rentals VALUES(1,3,'2006-01-01',NULL);
INSERT INTO Rentals VALUES(2,1,'2003-01-01',NULL);
INSERT INTO Rentals VALUES(2,3,'2004-01-01',NULL);
INSERT INTO Rentals VALUES(2,2,'2004-01-01',NULL);
INSERT INTO Rentals VALUES(3,2,'2003-01-01',NULL);
INSERT INTO Rentals VALUES(3,1,'2005-01-01',NULL);
INSERT INTO Rentals VALUES(3,4,'2004-01-01',NULL);
INSERT INTO Rentals VALUES(4,2,'2003-01-01',NULL);
INSERT INTO Rentals VALUES(4,4,'2004-01-01',NULL);
INSERT INTO Rentals VALUES(5,1,'2003-01-01',NULL);
给予:
movieid title rentals year
---------- -------------- ---------- ----------
2 a better movie 3 2003
1 a good movie 3 2003
4 the worst movi 2 2004
进一步编辑:
在另一个答案中提到分析函数提醒了我;sqlite现在有了它们(添加在3.25中)!所以
它使用窗口函数将第一个查询中的两个CTE合并为一个CTE。(可能还有更好的方法;我还不能非常流利地使用它们)
以及使用排名建议的不同版本:
WITH first_year_rentals(movieid, title, rentals, ranking, year) AS
(SELECT m.movieid
, m.title
, count(*)
, rank() OVER (PARTITION BY m.year ORDER BY count(*) DESC)
, m.year
FROM movies AS m
JOIN rentals AS r ON m.movieid = r.movieid AND m.year = strftime('%Y', r.date)
GROUP BY m.movieid)
SELECT movieid, title, rentals, year
FROM first_year_rentals
WHERE ranking = 1
ORDER BY year, title;
一次只能报告一年,或者您的报告有几年?它可以包含几年。我认为我最头疼的事情是创建一个临时表,其中包含电影id列和租用次数列,只要电影在给定的年份发行并在给定的年份租用。如果我能弄清楚如何做到这一点,那么我可以在它的#of times rendered列上运行max()查询,找到电影id,然后链接到电影标题。我尝试了下面的答案。一些样本数据可能会有帮助。如果是领带,你想要什么?@Shawn所有领带的电影都应该包括在内。我真正想要的是创建一个临时表的方法,其中包括电影id和电影在给定年份的出租次数,只要电影在给定年份发布。我可以很容易地解决这个问题。我不确定我是否能够理解这里发生的事情,因为我对SQL非常陌生。有没有办法只创建一个临时表,其中在一列中包含电影id和电影出租次数,并且只有在电影的出租和发行日期发生在给定年份时才有电影条目?我也在db上运行了这个,它似乎不能正常工作。它返回了错误的电影。@Mdomin45我想我们可以让上面的查询为您服务。请尝试一下并留下反馈,谢谢。在给定的一年中,我会把它放在哪里?假设我想检查2000年。给定年份的硬编码会改变整个查询,既然你没有要求,我不愿意改变我的整个答案。一个快速的方法是在外部查询中添加一个WHERE
子句,查看我的更新答案。它仍然给出了不正确的答案。我希望我能解释一下原因,但我使用的数据库相当大,我对代码本身了解甚少。@TimBiegeleisen更新。我怀疑您的fiddle不起作用,因为您没有使用与年份列具有适当关联的实际表,这意味着strftime()
返回的字符串没有转换为数字,因此比较失败。当Sqlite在比较中转换值时,它有时会很棘手而且不明显。是的,它现在看起来很好+1。不幸的是,我的大脑太油腻了,无法理解你的查询,但它似乎起作用了。@TimBiegeleisen我用窗口函数抛出了第二个版本,它也油腻了我的大脑。这些东西都是黑魔法。好的……另一种方法是使用RANK
或densite\u RANK
,在年份上划分分区,在计数下降时使用ORDER BY
。然后,只保留rank=1记录(这将捕获第一名的所有关系)。
WITH first_year_rentals(movieid, title, rentals, ranking, year) AS
(SELECT m.movieid
, m.title
, count(*)
, rank() OVER (PARTITION BY m.year ORDER BY count(*) DESC)
, m.year
FROM movies AS m
JOIN rentals AS r ON m.movieid = r.movieid AND m.year = strftime('%Y', r.date)
GROUP BY m.movieid)
SELECT movieid, title, rentals, year
FROM first_year_rentals
WHERE ranking = 1
ORDER BY year, title;