我有一个名为Movie,Genre和Keyword的表,从中创建了一个名为“ genkeyword”的视图。视图“ genkeyword”具有很多元组,因此可以在DB Fiddle处对其进行访问。
我有以下查询:
SELECT title,
year,
Count(DISTINCT genre) AS genre_freq,
Count(DISTINCT keyword) AS keyword_freq
FROM genkeyword
WHERE ( genre IN (SELECT genre
FROM genkeyword
WHERE title = 'Harry Potter and the Deathly Hallows')
OR keyword IN (SELECT keyword
FROM genkeyword
WHERE title = 'Harry Potter and the Deathly Hallows') )
AND title <> 'Harry Potter and the Deathly Hallows'
GROUP BY title,
year
ORDER BY genre_freq DESC,
keyword_freq DESC;
我打算使用此查询来获取每部电影的风格和关键字频率,这些电影的风格和关键字与哈利·波特相同: 输出应为:
title | genre_freq | keyword_freq
Cinderella 2 2
The Shape of Water 2 1
How to Train Your Dragon 2 0
Enchanted 1 3
我知道查询不正确,因为我得到了以下输出:
title | genre_freq | keyword_freq
The Shape of Water 4 3
Enchanted 3 4
Cinderella 2 5
How to Train Your Dragon 2 3
但是,我想澄清一下我对查询工作原理的理解。
在查询的“ where”子句中:
where (genre in (select genre from genkeyword where title='Harry Potter') or
keyword in (select keyword from genkeyword where title='Harry Potter'))
我的意思是说,生成了两个结果集,一个结果集包含所有具有在Harry Potter中流派的元组(让它为R1),另一个包含所有具有关键字in中的元组。哈利·波特(让这个叫R2)?
如果所考虑的元组包含流派结果集R1中的流派或关键字结果集R2中的关键字,则对流派/关键字进行计数。我不确定在这种情况下count(distinct genre)和count(distinct关键字)的工作方式。如果元组包含R1中的流派,则仅对流派计数还是对关键字进行计数?当元组在R2中包含关键字时,情况也是如此,类型和关键字一样被计算吗?
我不明白为什么我从查询中弄错了genre_freq和keyword_freq值。这是因为我不完全了解幕后如何统计类型和关键字频率。任何见解都会受到赞赏。
答案 0 :(得分:0)
到目前为止,我对SO提出的最常见的问题之一。
回答您的问题。 OR子句基本上将关键字部分和体裁部分的结果相互粘贴在一起。 SQL在行(或记录)中工作,因此您应该始终在行中思考。
首先,它选择所有包含相同类型的行,例如Harry Potter。然后,它选择包含关键字的所有行。然后它执行计数。显然,这太高了,因为您还将获得所有具有相同流派但具有重叠关键字的记录。您还将获得所有具有重叠流派但没有重叠关键字的行。
要正确计数记录,只需将OR更改为AND。这只会选择具有相同流派以及包含关键字的记录。计数这些将产生正确的结果。
答案 1 :(得分:0)
正如Imre_G所说,这是一个很好的问题,他对问题出在哪里的解释很明确。您基本上是在选择不需要的类型和关键字,然后对它们进行计数,因为它们具有相同的元素。
这是修复它的一种方法,也许不是最好的,而是最简单的:
docker.for.win.localhost
现在,该解决方案仅在电影匹配关键字时才有效。正确的解决方案是将SELECT
COALESCE(a.title, b.title) AS title,
COALESCE(a.year, b.year) AS year,
a.genre_freq,
b.keyword_freq
FROM
(SELECT title, year, count(distinct genre) as genre_freq FROM genkeyword where (genre in
(select genre from genkeyword where title='Harry Potter and the Deathly Hallows') )
AND title <> 'Harry Potter and the Deathly Hallows'
group by title, year) a
LEFT JOIN
(select title, year,
count(distinct keyword) as keyword_freq
from genkeyword
where keyword in (select keyword from genkeyword where title='Harry Potter and the Deathly Hallows')
and title <> 'Harry Potter and the Deathly Hallows' group by title, year) b
ON b.title = a.title;
替换为LEFT JOIN
,但是MySQL由于某些原因不支持FULL OUTER JOIN
。也有一个解决方案,但是很长,并且涉及很多FULL OUTER JOIN
;((
答案 2 :(得分:0)
在总计之前,您可以使用子查询来反转逻辑并从类型和关键字中获取动力
select title,year,
sum(case when src = 'g' then 1 else 0 end) as genre,
sum(case when src = 'k' then 1 else 0 end) as keyword
from
(
select 'g' as src, g1.title ,g1.year, g1.genre
from genkeyword g
join genkeyword g1 on g1.genre = g.genre
where g.title = 'Harry Potter and the Deathly Hallows' and g1.title <> 'Harry Potter and the Deathly Hallows'
union
select 'k' as src, g1.title ,g1.year, g1.genre
from genkeyword g
join genkeyword g1 on g1.keyword = g.keyword
where g.title = 'Harry Potter and the Deathly Hallows' and g1.title <> 'Harry Potter and the Deathly Hallows'
) s
group by title , year;
+--------------------------+------+-------+---------+
| title | year | genre | keyword |
+--------------------------+------+-------+---------+
| Cinderella | 2015 | 2 | 2 |
| Enchanted | 2007 | 1 | 3 |
| How to Train Your Dragon | 2010 | 2 | 0 |
| The Shape of Water | 2017 | 2 | 4 |
+--------------------------+------+-------+---------+
4 rows in set (0.10 sec)
答案 3 :(得分:0)
尝试此查询。
我没有使用您创建的任何视图,但是您可以根据需要使用这些视图。
MySQL
SET @tmpMovieid = (SELECT DISTINCT id
FROM Movie
WHERE title = 'Harry Potter and the Deathly Hallows');
SELECT id,
title,
IFNULL(Max(CASE WHEN coltype = 'genre' THEN col end), 0) AS genre_freq,
IFNULL(Max(CASE WHEN coltype = 'Keyword' THEN col end), 0) AS keyword_freq
FROM (SELECT id,
title,
Count(g.genre) AS col,
'genre' AS colType
FROM Movie m
INNER JOIN Genre g ON m.id = g.Movie_id
WHERE g.genre IN (SELECT DISTINCT genre
FROM Genre
WHERE Movie_id = @tmpMovieid)
GROUP BY id, title
UNION ALL
SELECT id,
title,
Count(k.keyword) AS col,
'Keyword' AS colType
FROM Movie m
INNER JOIN Keyword k ON m.id = k.Movie_id
WHERE k.keyword IN (SELECT DISTINCT keyword
FROM Keyword
WHERE Movie_id = @tmpMovieid)
GROUP BY id, title) tmp
WHERE id <> @tmpMovieid
GROUP BY id, title
ORDER BY genre_freq DESC, keyword_freq DESC;
在线演示:https://www.db-fiddle.com/f/s1xLQ6r4Zwi5hVjCsdcwV8/0
SQL Server
注意:由于您已将“文本”用作某些列数据类型,因此需要进行某些操作的转换。但是再说一次,由于您使用的是MySQL,因此不需要它。无论如何,我写这篇文章的目的是向您展示它们的区别和乐趣。
DECLARE @tmpMovieID INT;
SET @tmpMovieID = (SELECT DISTINCT id
FROM movie
WHERE Cast(title AS NVARCHAR(MAX)) = 'Harry Potter and the Deathly Hallows');
SELECT tmpGenre.id AS id,
tmpGenre.title AS title,
ISNULL(tmpGenre.genre, 0) AS genre,
ISNULL(tmpKeyword.keyword,0) AS keyword
FROM (SELECT id,
Cast(title AS NVARCHAR(MAX)) AS title,
Count(Cast(g.genre AS NVARCHAR(MAX))) AS genre
FROM movie m
INNER JOIN genre g ON m.id = g.movie_id
WHERE Cast(g.genre AS NVARCHAR(MAX)) IN (SELECT DISTINCT Cast(genre AS NVARCHAR(MAX))
FROM genre
WHERE movie_id = @tmpMovieID)
GROUP BY id, Cast(title AS NVARCHAR(MAX))) tmpGenre
FULL OUTER JOIN (SELECT id,
Cast(title AS NVARCHAR(MAX)) AS title,
Count(Cast(k.keyword AS NVARCHAR(MAX))) AS Keyword
FROM movie m
INNER JOIN keyword k ON m.id = k.movie_id
WHERE Cast(k.keyword AS NVARCHAR(MAX)) IN
(SELECT DISTINCT Cast(keyword AS NVARCHAR(MAX))
FROM keyword
WHERE movie_id = @tmpMovieID)
GROUP BY id, Cast(title AS NVARCHAR(MAX))) tmpKeyword
ON tmpGenre.id = tmpKeyword.id
WHERE tmpGenre.id <> @tmpMovieID
ORDER BY tmpGenre.genre DESC, tmpKeyword.keyword DESC;
在线演示:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=a1ee14e1e08b7e55eff2e8e94f89a287&hide=1
结果
+------+---------------------------+-------------+--------------+
| id | title | genre_freq | keyword_freq |
+------+---------------------------+-------------+--------------+
| 407 | Cinderella | 2 | 2 |
| 826 | The Shape of Water | 2 | 1 |
| 523 | How to Train Your Dragon | 2 | 0 |
| 799 | Enchanted | 1 | 3 |
+------+---------------------------+-------------+--------------+
顺便说一句,谢谢您提出一个明确的问题,并给出了表模式,示例数据和所需的输出。