Почему мой SQL-скрипт выбирает слишком много выходных данных (CS50 pset7 sql.13)?

#sql #cs50

#sql #cs50

Вопрос:

В настоящее время я работаю над pset7 в cs50, и я думал, что выбрал правильное количество указанных значений, но мой скрипт выводит 349 строк вместо 176, которые есть в ключе ответа.

«В 13.sql напишите SQL-запрос, чтобы перечислить имена всех людей, которые снимались в фильме, в котором также снялся Кевин Бэкон. Ваш запрос должен вывести таблицу с одним столбцом для имени каждого пользователя. В базе данных может быть несколько человек с именем Кевин Бэкон. Обязательно выберите только Кевина Бейкона, родившегося в 1958 году. Сам Кевин Бэкон не должен быть включен в результирующий список.»

CS50 pset7 sql.13

 sqlite> .schema
CREATE TABLE movies (
                    id INTEGER,
                    title TEXT NOT NULL,
                    year NUMERIC,
                    PRIMARY KEY(id)
                );
CREATE TABLE stars (
                movie_id INTEGER NOT NULL,
                person_id INTEGER NOT NULL,
                FOREIGN KEY(movie_id) REFERENCES movies(id),
                FOREIGN KEY(person_id) REFERENCES people(id)
            );
CREATE TABLE directors (
                movie_id INTEGER NOT NULL,
                person_id INTEGER NOT NULL,
                FOREIGN KEY(movie_id) REFERENCES movies(id),
                FOREIGN KEY(person_id) REFERENCES people(id)
            );
CREATE TABLE ratings (
                movie_id INTEGER NOT NULL,
                rating REAL NOT NULL,
                votes INTEGER NOT NULL,
                FOREIGN KEY(movie_id) REFERENCES movies(id)
            );
CREATE TABLE people (
                id INTEGER,
                name TEXT NOT NULL,
                birth NUMERIC,
                PRIMARY KEY(id)
            );
  

МОЙ СКРИПТ

 SELECT DISTINCT name

FROM 
    people
    INNER JOIN  stars ON people.id = stars.person_id
    INNER JOIN movies ON movies.id = stars.movie_id

WHERE movies.title IN (

SELECT
    title
    
From
    movies
    INNER JOIN stars ON movies.id = stars.movie_id
    INNER JOIN people ON stars.person_id= people.id
    
WHERE 
    people.name = "Kevin Bacon"
    AND
    people.birth = "1958"
    )
    
EXCEPT SELECT name FROM people WHERE people.name = "Kevin Bacon"
  

Есть ли какие-то логические ошибки в этом скрипте? Моя логика была:

  • Выберите все фильмы, в которых снимается Кевин Бэкон (вложенный ВЫБОР)
  • Выберите имена звезд (основной ВЫБОР), которые появляются в любом из этих фильмов Кевина Бэкона, кроме самого Кевина Бэкона.

Комментарии:

1. Прежде всего, ваш внутренний запрос должен выбрать movies.id , а не title , поскольку id он уникален (хотя title может и не быть) и поскольку id этого достаточно, чтобы узнать, о каком фильме идет речь. Затем вы проверяете, WHERE movie_id IN (...) и, более того, вам не нужно будет присоединяться movies во внешнем запросе, потому что у вас уже есть movie_id из joining stars

2. Спасибо за помощь! Если кто-нибудь также использует это для справки, обратите внимание, что когда Alex заявил об использовании, movie_id вы должны указать, из какой таблицы вы извлекаете идентификатор, потому что movie_id он находится в нескольких таблицах. SQL не знает, какой из них вы пытаетесь использовать. В моем случае он использовал… WHERE stars.movie_id IN ( Еще раз спасибо!

3. Так ли это? Если ваш внешний запрос SELECT DISTINCT name FROM people INNER JOIN stars ON people.id = stars.person_id WHERE ... , то movie_id поступает только из stars , так что никакой двусмысленности нет.

Ответ №1:

Что-то подобное работало бы в postgres. Возможно, потребуется адаптация к вашей базе данных.

     select name
    from (
        with kb_movies as
            (select distinct movies.id as kb_movie_id
            from movies
            join stars 
                on stars.movie_id = movies.id
            join people 
                on people.id = stars.people_id
            where people.name = 'Kevin Bacon'
            and people.birth = '1958' --or 1958
            )
            select distinct people.name
            from people
            join stars 
                on stars.people_id = people.id
            join movies 
                on movies.id = stars.movie_id
            join kb_movies 
                on kb_movie_id = movies.id
        )z
    where name <> 'Kevin Bacon'