Как исключить строки из выборки SQL, имеющие связанное ключевое слово через отношение многие ко многим - PullRequest
0 голосов
/ 01 июня 2019

У меня есть база данных MySQL с таблицей media, таблицей keywords и отношением «многие ко многим» между media и keywords через таблицу соединений media_keywords.

Я хочу получить все записи из таблицы мультимедиа, где соответствует следующий набор условий:

'description' is like 'dog' OR 
'media.keywords' includes the id for the 'dog' keyword [100]

И исключить из найденного набора любые записи, где:

'description' is like 'cat' OR
'media.keywords' includes the id for the 'cat' keyword [400]

А также исключить любую строку, где:

'media.keywords' includes the id for the 'monochrome' keyword [500]

Я также хочу вернуть только отдельные строки, поэтому я использую GROUP By 'media.id'

Оператор SQL, который у меня есть на данный момент, выглядит следующим образом:

    SELECT DISTINCT 
    `media`.`id`,`media`.`description`, 
    `keywords`.`id` AS `keywords.id`, 
    `keywords->media_keywords`.`id` AS `keywords.media_keywords.id`, 
    `keywords->media_keywords`.`media_id` AS `keywords.media_keywords.media_id`, 
    `keywords->media_keywords`.`keyword_id` AS `keywords.media_keywords.keyword_id` 

    FROM database.media 

    LEFT OUTER JOIN 
    ( 
        `media_keywords` AS `keywords->media_keywords` 

        INNER JOIN `keywords` AS `keywords` 
        ON `keywords`.`id` = `keywords->media_keywords`.`keyword_id`
    ) 

    ON `media`.`id` = `keywords->media_keywords`.`media_id` 

    WHERE 
    ( 
            (`media`.`description` LIKE '%dog%' ) 

            OR `keywords`.`id` IN (100) 
    )

    AND NOT 
    ( 
            (`media`.`description` LIKE '%cat%' ) 

            OR `keywords`.`id` IN (400,500)
    )

    GROUP BY `media`.`id` ;

Это корректно выбирает записи, где «собака» присутствует в описании или является ключевым словом, но полностью игнорирует исключения.

Кто-нибудь может увидеть, что я здесь делаю не так?

Ответы [ 2 ]

1 голос
/ 02 июня 2019

Я бы использовал предложение where:

select m.*
from media m
where (m.description like '%dog%' or
       exists (select 1
               from keywords k
               where k.media_id = m.id and
                     k.keyword_id = 100
              )
      ) and
      (m.description not like '%cat%' or
       exists (select 1
               from keywords k
               where k.media_id = m.id and
                     k.keyword_id in (400, 500)
              )
       );

Это в значительной степени прямой перевод ваших условий.

1 голос
/ 01 июня 2019

Я не очень много работаю с MySQL, но я бы предложил другой подход

  • Переместите условие «СОБАКА» в ЛЕВОЕ СОЕДИНЕНИЕ (чтобы получить только ключевые слова соответствие "СОБАКА") и сделать его JOIN. Теперь у вас будет список всех спички.
  • добавить подзапрос в предложении WHERE
  • ГДЕ идентификатор не указан (ВЫБЕРИТЕ идентификатор ОТ ... ГДЕ НРАВИТСЯ '% cat%')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...