многие ко многим присоединяются без повторяющихся строк - PullRequest
0 голосов
/ 27 октября 2018

У меня есть несколько таблиц со многими отношениями.Например, настольная схема видео

CREATE TABLE `videos` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `description` varchar(10000) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=47606 DEFAULT CHARSET=utf8;

и две таблицы актеров film_actors, а также, например, сценаристы и сценаристы

схемы актеров и актеров кино

CREATE TABLE `actors` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `actors_UN` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=152216 DEFAULT CHARSET=utf8;


CREATE TABLE `film_actors` (
  `actor_id` int(11) NOT NULL,
  `film_id` int(11) NOT NULL,
  PRIMARY KEY (`film_id`,`actor_id`),
  KEY `FKrs472oyyff3hfwq10pyo94k1d` (`actor_id`),
  CONSTRAINT `FK12uvap3je50qd8cq3s0jf7h7r` FOREIGN KEY (`film_id`) REFERENCES `videos` (`id`) ON DELETE CASCADE,
  CONSTRAINT `FKrs472oyyff3hfwq10pyo94k1d` FOREIGN KEY (`actor_id`) REFERENCES `actors` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

писатель

CREATE TABLE `writers` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `writers_UN` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=39875 DEFAULT CHARSET=utf8;

CREATE TABLE `film_writers` (
  `film_id` int(11) NOT NULL,
  `writer_id` int(11) NOT NULL,
  PRIMARY KEY (`writer_id`,`film_id`),
  KEY `FKh0kfwnarp6utb4f80ycj1lap` (`film_id`),
  CONSTRAINT `FK4hwpb5l48m0xps6jqn1wyjb63` FOREIGN KEY (`writer_id`) REFERENCES `writers` (`id`) ON DELETE CASCADE,
  CONSTRAINT `FKh0kfwnarp6utb4f80ycj1lap` FOREIGN KEY (`film_id`) REFERENCES `videos` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Я пытаюсь выбрать информацию о фильме с актерами и писателями, но результат содержит много повторяющихся строк.Я использую этот SQL-запрос

SELECT
    vid.id,
    vid.title,
    vid.original_title_name,
    vid.`year`,
    ac.id as actor_id,
    ac.name as actor_name,
    wr.id as writer_id,
    wr.name as writer_name
from
    (
    select
        *
    From
        videos v
    where
        v.id = 1722
    ) vid
JOIN film_actors fa ON
    vid.id = fa.film_id
JOIN actors ac ON
    fa.actor_id = ac.id
JOIN film_writers fw ON
    vid.id = fw.film_id
JOIN writers wr ON
    fw.writer_id = wr.id

Вывод строки много дубликатов.

id   |title           |original_title_name |year |actor_id |actor_name         |writer_id |writer_name    |
-----|----------------|--------------------|-----|---------|-------------------|----------|---------------|
1722 |Назад в будущее |Back to the Future  |1985 |1796     |Майкл Дж. Фокс     |319       |Боб Гейл       |
1722 |Назад в будущее |Back to the Future  |1985 |2648     |Джордж ДиЧенцо     |319       |Боб Гейл       |
1722 |Назад в будущее |Back to the Future  |1985 |4807     |Криспин Гловер     |319       |Боб Гейл       |
1722 |Назад в будущее |Back to the Future  |1985 |7601     |Кристофер Ллойд    |319       |Боб Гейл       |
1722 |Назад в будущее |Back to the Future  |1985 |8195     |Лиа Томпсон        |319       |Боб Гейл       |
1722 |Назад в будущее |Back to the Future  |1985 |8707     |Марк МакКлюр       |319       |Боб Гейл       |
1722 |Назад в будущее |Back to the Future  |1985 |9242     |Фрэнсис Ли МакКейн |319       |Боб Гейл       |
1722 |Назад в будущее |Back to the Future  |1985 |9602     |Уэнди Джо Спербер  |319       |Боб Гейл       |
1722 |Назад в будущее |Back to the Future  |1985 |10545    |Клаудия Уэллс      |319       |Боб Гейл       |
1722 |Назад в будущее |Back to the Future  |1985 |10546    |Томас Ф. Уилсон    |319       |Боб Гейл       |
1722 |Назад в будущее |Back to the Future  |1985 |1796     |Майкл Дж. Фокс     |320       |Роберт Земекис |
1722 |Назад в будущее |Back to the Future  |1985 |2648     |Джордж ДиЧенцо     |320       |Роберт Земекис |
1722 |Назад в будущее |Back to the Future  |1985 |4807     |Криспин Гловер     |320       |Роберт Земекис |
1722 |Назад в будущее |Back to the Future  |1985 |7601     |Кристофер Ллойд    |320       |Роберт Земекис |
1722 |Назад в будущее |Back to the Future  |1985 |8195     |Лиа Томпсон        |320       |Роберт Земекис |
1722 |Назад в будущее |Back to the Future  |1985 |8707     |Марк МакКлюр       |320       |Роберт Земекис |
1722 |Назад в будущее |Back to the Future  |1985 |9242     |Фрэнсис Ли МакКейн |320       |Роберт Земекис |

Можно ли как-то преобразовать результат в нечто подобное?

id   |title           |original_title_name |year |actor_id |actor_name         |writer_id |writer_name    |
-----|----------------|--------------------|-----|---------|-------------------|----------|---------------|
1722 |Назад в будущее |Back to the Future  |1985 |1796     |Майкл Дж. Фокс     |319       |Боб Гейл       |
1722 |Назад в будущее |Back to the Future  |1985 |2648     |Джордж ДиЧенцо     |320       |Роберт Земекис |
1722 |Назад в будущее |Back to the Future  |1985 |4807     |Криспин Гловер     |          |               |
1722 |Назад в будущее |Back to the Future  |1985 |7601     |Кристофер Ллойд    |          |               |
1722 |Назад в будущее |Back to the Future  |1985 |8195     |Лиа Томпсон        |          |               |
1722 |Назад в будущее |Back to the Future  |1985 |8707     |Марк МакКлюр       |          |               |
1722 |Назад в будущее |Back to the Future  |1985 |9242     |Фрэнсис Ли МакКейн |          |               |
1722 |Назад в будущее |Back to the Future  |1985 |9602     |Уэнди Джо Спербер  |          |               |
1722 |Назад в будущее |Back to the Future  |1985 |10545    |Клаудия Уэллс      |          |               |
1722 |Назад в будущее |Back to the Future  |1985 |10546    |Томас Ф. Уилсон    |          |               |

Ответы [ 2 ]

0 голосов
/ 27 октября 2018

Причина, по которой вы получаете «повторяющиеся» строки, в том, что в одном фильме много актеров, а в одном фильме много авторов. Между актером фильма и автором фильма вообще нет никакой связи

Простой запрос для образовательных целей:

SELECT * 
FROM
  films 
  INNER JOIN actors on films.id = actors.filmid
  INNER JOIN writers on films.id = writers.filmid

Это упрощено, чтобы подчеркнуть мою точку зрения, оно скрывает сложность ваших таблиц, которые разбивают множество: множество отношений на множество: один

Теперь. Если в фильме 10 актеров и 11 сценаристов, этот запрос даст 110 строк

Каждый актер будет связан с каждым писателем

Почему? Потому что нет абсолютно никакой связи между киноактером и писателем. Эти две вещи не имеют ничего общего друг с другом. Мы не написали ничего в условии JOIN, чтобы утверждать, что некоторый атрибут актера равен некоторому атрибуту писателя, потому что мы не можем - просто нет ничего, чтобы связать их обоих вместе

Единственное, что база данных может сделать в результате, - это создать набор строк, в котором есть строка для каждой комбинации актер / писатель. Данные об актере повторяются 11 раз, а данные записывающего устройства - 10 раз

Actor1/Writer1
Actor1/Writer2
...
Actor2/Writer1
Actor2/Writer2
...
Actor10/Writer11

Нет никакой возможности обойти эту «проблему» - она ​​вызвана попыткой объединить две несвязанные вещи в одном запросе. Единственное «решение» - не помещать их в один и тот же запрос. Если вы пишете такой веб-сайт, как IMDB, и у вас есть веб-страница для фильма с двумя вкладками, одна для актеров и одна для писателей, выполните два отдельных запроса (актеры объединения фильмов) и (сценаристы объединения фильмов), чтобы заполнить данные для каждая вкладка - вы не можете * сделать это в одном запросе.

* когда я говорю «не могу», я имею в виду «действительно не стоит». Сетка «желаемых результатов», которую вы опубликовали, связывает актера 1796 с писателем 319 без всякой веской причины - предполагается, что все в строке связано, и эти два объекта не имеют никакого отношения, кроме какого-либо произвольного решения что они оба ранжируются первыми, когда их идентификаторы располагаются в порядке возрастания. Хотя существуют способы, с помощью которых их можно связать и исключить декартово произведение из вашего запроса, это ужасный запах кода и свидетельствует о том, что вы подходите к какой-то другой проблеме (которую мы не можем видеть) полностью неправильный путь (извините)

0 голосов
/ 27 октября 2018

Вы можете использовать ключевое слово DISTINCT после оператора SELECT, чтобы включить выбор не повторяющихся строк.В этом случае размещение ключевого слова DISTINCT после первого ключевого слова SELECT должно решить вашу проблему.Надеюсь, что на ваш вопрос ответили

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...