2012-02-03 6 views
24

Korzystając z bazy danych IMDB, mam tabele actor, casts i movie, i muszę wybrać aktorów z numerem Kevina Bacona 2. Myślałem, że to powinno być zrobione, ale otrzymuję 0 wierszy zwróconych. Jaki jest mój błąd?Zapytanie SQL o numer Kevina Bacona 2

select fname, lname 
from actor join casts on pid=actor.id 
where actor.id in (
    select a3.id --actors who have a kb number of 2 
    from casts c3 join actor a3 on c3.pid=a3.id, 
    (
    (select c1.mid --actors who have a kb number of 1 
    from (casts c1 join actor a1 on c1.pid=a1.id), (casts c2 join actor a2 on c2.pid=a2.id) 
    where c1.mid=c2.mid and a2.fname='Kevin' and a2.lname='Bacon') 
    )Level1 where c3.mid=Level1.mid 
) 
and actor.id not in (select a4.id --and only a kb number of 2 
    from (casts c4 join actor a4 on c4.pid=a4.id), (casts c5 join actor a5 on c5.pid=a5.id) 
    where c4.mid=c5.mid and a5.fname='Kevin' and a5.lname='Bacon'); 

Oto schematy tabeli:

ACTOR (id, fname, lname, gender) 
MOVIE (id, name, year) 
CASTS (pid, mid, role) 

mid jest kluczem obcym do id filmowego i pid jest kluczem obcym aktora id.

Zauważ, że ograniczenia dotyczące pytania uniemożliwiają mi używanie tabel tymczasowych lub rekurencji: zapytanie powinno zostać wykonane z podselekcjami.


Próbowałem też

select count(distinct pid) from casts join actor on pid=actor.id where mid in (
    select mid from casts where pid in (
     select distinct pid from casts where mid in (
      select mid from casts join actor on pid=actor.id where fname='Kevin' and lname='Bacon'))) 

and pid not in 
    (select distinct pid from casts where mid in (
     select mid from casts join actor on pid=actor.id where fname='Kevin' and lname='Bacon')); 

który również wydaje się, że powinna działać, ale to nie kończąc.


końcu udało mi się zdobyć kod roboczych:

select count(distinct pid) from casts where mid in (
    select mid from casts where pid in (
     select distinct pid from casts where mid in (
      select mid from casts join actor on pid=actor.id where fname='Kevin' and lname='Bacon'))) 

and pid not in 
    (select distinct pid from casts where mid in (
     select mid from casts join actor on pid=actor.id where fname='Kevin' and lname='Bacon')); 

W podzapytania powrotu sensownych odpowiedzi, przynajmniej. Ale to trwa wiecznie. Każde podzapytanie trwało mniej niż 30 sekund, ale razem trwają 6 minut i liczą. Czemu?


Uwaga: Otrzymałem to zadanie domowe. Aby uniknąć jakiejkolwiek części błędnego postępowania akademickiego z mojej strony, wolałbym, aby ludzie nie zamieszczali kompletnych/dokładnych rozwiązań, ale wskazywali ogólne rzeczy, które robię źle/generowali ogólne sugestie co do tego, jak powinienem postępować w tej sprawie. .

+2

@AbeMiessler http://sqlfiddle.com/ – scottm

+0

dokonać przypadek testowy: tworzenie tabel TEMP z danymi – cetver

+0

AWW, a tu po prostu zorientowali się, jak to zrobić z rekurencyjnej CTE zbyt (to był ciekawy kontekst postępowania z wykresami cyklicznymi) ... Dlaczego nie możesz ich używać? Chociaż nie są to niektóre z nowych baz danych innych niż SQL, które powinny radzić sobie lepiej z tego typu rzeczami - chciałem, że ktoś zrobiłby bazę danych z wykresami sieciowymi? Czy w ogóle możesz używać CTE? –

Odpowiedz

9

Aby dać szkic rozwiązania zamiast dokładnego rozwiązania użyłbym tego ogólnego podejścia

SELECT * 
FROM ACTOR 
WHERE id IN (
SELECT id 
     /* ... of actors that have worked on a film worked 
     on by actors that have worked on a KB film*/ 
EXCEPT 
SELECT id 
/* ... of all actors that have worked on a KB film 
     including KB himself*/) 

Także jak nie wolno używać rekurencyjnych CTE i tak oto odpowiedź za pomocą tych.

WITH RecursiveCTE 
    AS (SELECT C.pid, 
       C.mid, 
       0 as Level 
     FROM CASTS C 
       JOIN ACTOR A 
        ON A.id = C.pid 
     WHERE A.fname = 'Kevin' 
       and A.lname = 'Bacon' 
     UNION ALL 
     SELECT c1.pid, 
       c2.mid, 
       R.Level + 1 
     FROM RecursiveCTE R 
       JOIN CASTS c1 
        ON c1.mid = R.mid 
        AND R.Level < 2 
       JOIN CASTS c2 
        ON c1.pid = c2.pid) 
SELECT * 
FROM ACTOR 
WHERE id IN (SELECT pid 
       FROM RecursiveCTE 
       GROUP BY pid 
       HAVING MIN(Level) = 2) 
+0

szukasz bardziej ogólnych pomysłów na: co robię źle/co powinienem zrobić, ale uruchomię twoje zapytanie i zagłosuję, jeśli odpowiedź pasuje do odpowiedź I (miejmy nadzieję, ostatecznie) dostać. – Colleen

+0

Hmmm to wciąż aktualna odpowiedź, której, jak sądzę, chciał uniknąć. – ErikE

+0

To jest odpowiednia odpowiedź, ale napisałem ten komentarz po tym, jak opublikował odpowiedź, więc jest w porządku. – Colleen