SQLzoo更多JOIN练习#16

时间:2013-03-17 22:08:35

标签: sql join

我正在处理电影数据库的更多JOIN操作。我的问题是问题#16:列出所有与'Art Garfunkel'合作的人

您需要首先将Art Garfunkel所在的所有电影作为一个值获取,然后通过将其与第一个值进行比较来获取同一电影中所有人的姓名。

我提出了我自己的查询和逻辑它应该工作,但不是由于超时(我假设是由于查询效率低)

我的查询:

SELECT DISTINCT a.name
FROM actor a
JOIN casting b ON (a.id=b.actorid) 
JOIN movie c ON (b.movieid=c.id)
WHERE c.title IN(SELECT z.title
FROM movie z
JOIN casting y ON (z.id=y.movieid)
JOIN actor x on (y.actorid=x.id)
WHERE x.name='Art Garfunkel')

另一个版本:

SELECT DISTINCT actor.name
FROM movie,actor,casting
WHERE movie.id=casting.movieid
AND actor.id=casting.actorid
AND movie.title IN(SELECT movie.title
FROM movie,actor,casting
WHERE movie.id=casting.movieid
AND actor.id=casting.actorid
AND actor.name='Art Garfunkel')

这两个都抛出一个解析错误,说有一个超时试图查询上面显示的内容。

他们提供的被接受为答案的查询版本是:

SELECT DISTINCT d.name
FROM actor d JOIN casting a ON (a.actorid=d.id)
   JOIN casting b ON (a.movieid=b.movieid)
   JOIN actor c ON (b.actorid=c.id 
                AND c.name='Art Garfunkel')
  WHERE d.id!=c.id

我的逻辑在这里完全错了吗?或者是查询的效率非常低效(我在想)。有没有办法解决它运行并得到正确的答案?或者我应该在逻辑上更正确地考虑正确查询的方式吗?

这么多问题,但我想要反馈为什么这个查询不起作用以及下一步是什么。

12 个答案:

答案 0 :(得分:1)

以下是所有sql zoo问题的答案: answers

SELECT a.name
 FROM casting c JOIN actor a ON
  a.id = c.actorid
 WHERE 
  a.name <> 'Art Garfunkel' AND
  c.movieid 
 IN (
  SELECT m.id
     FROM casting c JOIN movie m ON
       m.id = c.movieid
     JOIN actor a ON
       c.actorid = a.id
     WHERE a.name = 'ART Garfunkel'
)
ORDER BY a.name

答案 1 :(得分:1)

这是我的查询,并清楚地说明了如何得出该查询。

第1步:获取Art Garfunkel的所有movieids

select movie.id 
from actor 
     join 
     casting on actor.id=casting.actorid 
     join 
     movie on movie.id=casting.movieid
where actor.name='Art Garfunkel'
group by movie.id

第2步:现在从movieids的那些列表中获得这些电影中的所有演员。

  select actor.name 
  from casting 
       join 
       actor on casting.actorid=actor.id 
       join 
       movie on movie.id=casting.movieid
 where casting.movieid in
                       ( select movie.id 
                         from actor 
                              join 
                              casting on actor.id=casting.actorid 
                              join 
                              movie on movie.id=casting.movieid
                         where actor.name='Art Garfunkel'
                         group by movie.id
                      )

第3步:我们需要共同参与方'Art Garfunkel',因此从结果集中消除'Art Garfunkel'

     select actor.name 
     from casting 
           join 
           actor on casting.actorid=actor.id 
           join 
           movie on movie.id=casting.movieid
     where casting.movieid in
                           ( select movie.id 
                             from actor 
                                  join 
                                  casting on actor.id=casting.actorid 
                                  join 
                                  movie on movie.id=casting.movieid
                             where actor.name='Art Garfunkel'
                             group by movie.id
                          )
   and actor.name!='Art Garfunkel'

答案 2 :(得分:0)

好吧,我花了几个小时来真正计算出这个(第16号),因为建议的解决方案一见钟情(第二次都没有)。 但是,在我提出自己的解决方案之后,我设法弄清楚了,这是更容易理解的(我觉得)。 首先是我的解决方案:

select name from actor 
join casting on actor.id=actorid
where movieid in
(select movieid from casting
join actor on actorid=actor.id
where name='Art Garfunkel')
and name <>'Art Garfunkel'

我搜索Art Garfunkel扮演角色(内部选择)的那些movieids的所有actorids(=外部选择),然后我自己过滤出Art Garfunkel。

足够简单。

您可以在查询末尾添加以下行,这样会很好:

order by name

但不再接受该查询为正确。

当我不理解别人的解决方案时,它让我感到烦恼,我花了一些时间在别处给出的那个。 这又是:

SELECT DISTINCT a.name
FROM actor a 
JOIN casting b ON (a.id=b.actorid)
JOIN casting c on b.movieid=c.movieid
JOIN actor d ON (c.actorid=d.id 
                AND d.name='Art Garfunkel')
WHERE a.id!=d.id

有趣的是,你可以写出稍微不同的内容并将where子句从最后一个连接中删除:

SELECT DISTINCT a.name
FROM actor a 
JOIN casting b ON (a.id=b.actorid)
JOIN casting c on b.movieid=c.movieid
JOIN actor d ON (c.actorid=d.id)
WHERE d.name='Art Garfunkel' 
AND a.id!=d.id

无论如何,你必须看到这个倒退,否则它永远没有意义。 这似乎是发生的事情:

actor-d (或者Where子句的第一部分,似乎首先被评估)设置(或限制)Art Garfunkel并将其传递回 casting-c < / strong>即可。 cast-c 从Art Garfunkel中查找movieids(顺便说一下是两个:1412用于catch-22和1597用于Boxing Helena)并将它们设置为 cast-b <的过滤器/ strong> -as cast-b 接管他们。 Casting-b 然后 - 将过滤器设置为来自Garfunkel的两部电影 - 恢复为 actor-a 中的所有actorID,其中所有演员的名字都已加星标这两部电影都被抬起头来。 最后,Art Garfunkel被过滤掉 - 就是这样。

我觉得这就好像是一些机器代码,好像有些查询优化器已经提出来了。 一个明智的人不会沿着这些思路思考(至少我不会)。

答案 3 :(得分:0)

SELECT name
  FROM movie, casting, actor
  WHERE movieid=movie.id
    AND actorid=actor.id 
and movieid IN
    (SELECT movieid FROM casting, actor
     WHERE actorid=actor.id
     AND name='Art Garfunkel')and name <>'Art Garfunkel'

答案 4 :(得分:0)

以下是上面给出的SQL答案:

SELECT a.name from actor a 
inner join casting c on a.id=c.actorid 
inner join movie m on m.id=c.movieid 
WHERE m.id in (SELECT c.movieid from casting c inner join actor a 
on a.id=c.actorid WHERE a.name='Art Garfunkel') 
and a.name<>'Art Garfunkel'

然而,作为一个仍习惯于工会的SQL初学者,我提出的第一个代码如下:

SELECT name from actor WHERE id IN 
(SELECT actorid from casting WHERE movieid IN (SELECT movieid 
from casting WHERE actorid IN (SELECT 
id from actor WHERE name='Art Garfunkel'))) 
and name<>'Art Garfunkel'

它基本上与上面的解释相同 - SELECT id 语句找到Art的演员ID。 SELECT movieid 找到他所在的电影。 SELECT actorid 找到这些电影中的其他演员,而 SELECT name 找到他们的名字。

学习如何做联合是理想的,我最终得到了内连接语法,但只是为那些对SELECT更熟悉或仍在学习联合的SQL用户抛出了另一个答案。

答案 5 :(得分:0)

另一个有效的解决方案如下:

SELECT name
FROM casting
JOIN actor ON actor.id=actorid
WHERE movieid IN (SELECT movieid FROM casting WHERE actorid = 
   (SELECT id FROM actor WHERE name='Art Garfunkel'))
GROUP BY actorid
HAVING name<>'Art Garfunkel'

答案 6 :(得分:0)

我认为这个问题类似于朱莉安德鲁斯项目(目前sqlzoo上的#13),所以我基本上调整了Bill Karwin的优雅solution to the Julie Andrews problem以一种不太优雅的方式解决这个问题。这个解决方案确实使用了所有JOINs,这似乎是这套练习的重点。从本质上讲,我对此进行概念化的方式是,Art Garfunkel被投放在一部电影中,其他人也被演员。换句话说,Garfunkel&lt; - &gt;铸造&lt; - &gt;电影&lt; - &gt;铸造&lt; - &gt;联合主演的名字。

我是一个非常新的SQL用户(老实说,&lt; 24小时)所以这可能很笨重,但它对我有用:

SELECT a2.name
FROM actor a1
JOIN casting AS c1 ON (a1.id = c1.actorid)
JOIN movie ON (c1.movieid=movie.id)
JOIN casting AS c2 ON (movie.id=c2.movieid)
JOIN actor AS a2 ON (c2.actorid=a2.id)
WHERE
    a1.name='Art Garfunkel'
    AND a2.name <> 'Art Garfunkel'
GROUP BY a2.name

答案 7 :(得分:0)

我不明白为什么需要在此查询中加入影片表。本练习中的任务是仅列出演员姓名,而不是名称和标题(这也需要加入电影表)。我提出了以下查询,并且它有效。 :)

SELECT name 
FROM actor 
JOIN casting on actor.id = actorid 
WHERE name <> 'Art Garfunkel' 
AND movieid IN 
(SELECT movieid 
FROM casting 
JOIN actor on actorid = actor.id 
WHERE name = 'Art Garfunkel')

答案 8 :(得分:0)

SELECT a.name FROM actor a 
    JOIN casting c ON a.id=c.actorid 
    JOIN movie m ON c.movieid=m.id
    WHERE c.movieid IN 
        (SELECT movieid FROM casting WHERE actorid IN
            (SELECT id FROM actor WHERE name = 'Art Garfunkel')) 
    AND a.name <> 'Art Garfunkel'

答案 9 :(得分:0)

您的两种解决方案都不完全错误。你只需要为你的sql添加一个条件。 QThread这意味着只找到那些使用List all the people who have worked with 'Art Garfunkel'的人,但是在你的sql中你没有从列表中排除'Art Garfunkel',这就是为什么sqlzoo说你的解决方案是错误的。

这是您的修改版本:

'Art Garfunkel'

SELECT DISTINCT a.name FROM actor a JOIN casting b ON (a.id=b.actorid) JOIN movie c ON (b.movieid=c.id) WHERE c.title IN(SELECT z.title FROM movie z JOIN casting y ON (z.id=y.movieid) JOIN actor x on (y.actorid=x.id) WHERE x.name='Art Garfunkel') AND a.name <> 'Art Garfunkel' 已添加到原始sql

你的解决方案#2:

AND a.name <> 'Art Garfunkel'

SELECT DISTINCT actor.name FROM movie,actor,casting WHERE movie.id=casting.movieid AND actor.id=casting.actorid AND movie.title IN(SELECT movie.title FROM movie,actor,casting WHERE movie.id=casting.movieid AND actor.id=casting.actorid AND actor.name='Art Garfunkel') AND actor.name <> 'Art Garfunkel' 已添加到原始sql

答案 10 :(得分:0)

一个简单的解决方案是 - select distinct(name) from movie join casting on movie.id=movieid join actor on actor.id=actorid where name not in ('Art Garfunkel') and title in (select title from movie join casting on movie.id=movieid join actor on actor.id=actorid where name ='Art Garfunkel')

答案 11 :(得分:0)

None