MYSQL Запрос к тому же столбцу с условиями И и ИЛИ - PullRequest
1 голос
/ 17 января 2020

У меня есть следующие таблицы:

       Topic                 Content_Topic                Content

id_topic   topic         id_content   id_topic     id_content  content
    1      aaaaa             1            2             1        xxxxx
    2      bbbbb             1            4             2        yyyyy
    3      ccccc             1            5             3        zzzzz
    4      ddddd             2            1             4        wwwww
    5      eeeee             2            3             5        kkkkk
    6      fffff             2            5             6        jjjjj
        ...                  3            3                  ...
                             3            4 
                             3            5 
                                  ... 

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

SELECT content FROM Content_Topic ct
LEFT JOIN Content c ON ct.id_content=c.id_topic
LEFT JOIN Topic t ON ct.id_topic=t.id_topic
WHERE   (ct.id_topic=2 OR ct.id_topic=3) AND 
        ct.id_topic IN (4,7,10) AND 
        (ct.id_topic=5 OR ct.id_topic=9)

То, что я ожидаю, это иметь весь контент с id_topi c 2,4,5 или 3,4,5 или 2,7,5 или 3,7,5 и т. д. ... вместо этого я получаю недействительный результат.

Что я делаю не так?

Ответы [ 5 ]

1 голос
/ 17 января 2020

Похоже, вы делаете особый тип реляционного разделения. То есть вы ищете контент, который соответствует набору тем, где каждый элемент имеет чередующиеся.

Вы не можете сделать это только с условием в предложении WHERE, потому что условие оценивается по одному ряду за раз. Не существует значения id_topic для данной строки, которая одновременно является 2 и 4 и 5.

Вам необходимо условие для наборов строк, и это то, чем является реляционное деление.

В вашем случае я бы сделал это с помощью соединений. Используя объединения, вы можете сделать три ссылки на различные строки Content_Topi c, поэтому условия могут быть взаимоисключающими.

SELECT c.content
FROM Content c
INNER JOIN Content_Topic ct1 
  ON c.id_content=ct1.id_content AND ct1.id_topic IN (2,3)
INNER JOIN Content_Topic ct2 
  ON c.id_content=ct2.id_content AND ct2.id_topic IN (4,7,10)
INNER JOIN Content_Topic ct3
  ON c.id_content=ct3.id_content AND ct3.id_topic IN (5,9)

Этот запрос должен соответствовать содержимому трех тем , Если он не соответствует всем трем, содержимое не будет возвращено запросом.

Но у каждого из трех есть альтернативы.

1 голос
/ 17 января 2020

Вы говорите (2 или 3) И (4 или 7 или 10) И (5 или 9)

Это означает, что вы никогда не получите никаких результатов.

y = 2 or 3

x = 4, 7 or 10

z = 5 or 9

В этом случае невозможно сделать x AND y истинным.

Я бы использовал псевдонимы таблиц для ссылки на вашу таблицу Content_Topi c 3 раза, чтобы вы могли заставить работать каждый из ваших критериев, а я бы использовал Присоединяется, а не подбирает, потому что это быстрее:

SELECT content FROM Content c 
INNER JOIN Content_Topic ct1 ON ct1.id_content=c.id_topic AND (ct1.id_topic=2 OR ct1.id_topic=3)
INNER JOIN Content_Topic ct2 ON ct2.id_content=c.id_topic AND (ct2.id_topic IN (4,7,10))
INNER JOIN Content_Topic ct3 ON ct3.id_content=c.id_topic AND (ct3.id_topic=5 OR ct3.id_topic=9)
0 голосов
/ 17 января 2020

Я думаю, что это было бы проще сделать с агрегацией и предложением HAVING для фильтрации:

SELECT c.content 
FROM Content c
INNER JOIN Content_Topic ct ON ct.id_content = c.id_content
GROUP BY c.id_content, c.content
HAVING
    -- 2, 4, 5
    (MAX(c.id_topic = 2) = 1 AND MAX(c.id_topic = 4) = 1 AND MAX(c.id_topic = 5) = 1)
    -- 3, 4, 5
    OR (MAX(c.id_topic = 3) = 1 AND MAX(c.id_topic = 4) = 1 AND MAX(c.id_topic = 5) = 1)
    -- 2, 5, 7
    OR (MAX(c.id_topic = 2) = 1 AND MAX(c.id_topic = 5) = 1 AND MAX(c.id_topic = 7) = 1)
    -- add more if needed ...

Это даст вам все content с тем, которые имеют темы 2, 3 и 5, ИЛИ темы 3, 4 и 5, ИЛИ темы 2, 5 и 7. Вы можете расширить условие HAVING, добавив при необходимости больше условий OR.

Еще одна вещь, на которую следует обратить внимание, это то, что вы этого не делаете на самом деле для этой задачи необходимо ввести таблицу Topic (необходимая информация доступна в Content_Topic).

0 голосов
/ 17 января 2020
SELECT *
FROM Content_Topic ct1
JOIN Content c1 ON ct`.id_content=c`.id_topic
JOIN ( SELECT id_content
       FROM Content_Topic ct
       LEFT JOIN Content c ON ct.id_content=c.id_topic
       LEFT JOIN Topic t ON ct.id_topic=t.id_topic
       GROUP BY id_content
       HAVING SUM(ct.id_topic IN (2,3)) > 0
          AND SUM(ct.id_topic IN (4,7,10)) > 0
          AND SUM(ct.id_topic IN (5,9)) > 0 
     ) sq ON ct.id_content = ct1.id_content
0 голосов
/ 17 января 2020

Я думаю, что ваше условие присоединения идет не так -

SELECT content
FROM Content_Topic ct
LEFT JOIN Content c ON ct.id_content=c.id_content
WHERE EXISTS (SELECT 1
              FROM Topic T
              WHERE T.id_topic = ct.Content_Topic
              AND ct.id_topic IN (2, 3))
AND EXISTS (SELECT 1
            FROM Topic T1
            WHERE T1.id_topic = ct.Content_Topic
            AND ct.id_topic IN (4,7,10))
AND EXISTS (SELECT 1
            FROM Topic T2
            WHERE T2.id_topic = ct.Content_Topic
            AND ct.id_topic IN (5, 9))

...