SQL - Self Join, чтобы найти две метки с выпуском, общим с третьей меткой - PullRequest
0 голосов
/ 03 июня 2018

Я использую PostgreSQL и PgAdmin 4 и работаю с базой данных MusicBrainz.Мне нужно найти пары меток, которые никогда не выпускали общий выпуск, но они оба выпустили релиз с третьим лейблом (одинаковый для обоих).

В базе данных есть эти таблицы: label (id, name ..) id - это первичный ключ.release_label (id, release, label) id - это первичный ключ и внешний ключ метки.

Я пробовал с самостоятельным соединением, но оно не работает:

SELECT l1.name as label_1 , l2.name as label_2
FROM release_label as r1 INNER JOIN label as l1 ON r1.label=l1.id, label as l2
INNER JOIN (release_label as r2 LEFT JOIN release_label as r3
ON r3.label=r2.label)ON r2.label=l2.id WHERE r1.release != r2.release 
AND r1.label!= r3.label AND r1.release=r3.release
GROUP BY label_1,label_2 ORDER BY label_1,label_2

Спасибо за совет.

1 Ответ

0 голосов
/ 03 июня 2018

Этот запрос получает пары меток, которые никогда не выпускали ничего общего:

select l1.id as id1, l2.id as id2
from label l1 cross join
     label l2 left join
     release_label rl1 
     on l1.id = rl1.label left join
     release_label rl2
     on l2.id = rl2.label and rl2.release = rl1.release
where rl1.label is null and l1.id < l2.id;

Теперь вам нужен третий ярлык, который выпустил с обоими.,,

select ll.*, rl3_1.label as in_common
from (select l1.id as id1, l2.id as id2
      from label l1 cross join
           label l2 left join
           release_label rl1 
           on l1.id = rl1.label left join
           release_label rl2
           on l2.id = rl2.label and rl2.release = rl1.release
      where rl1.label is null and l1.id < l2.id
     ) ll join
     release_label rl1
     on rl1.label = ll.id1 join
     release_label rl2
     on rl2.label = ll.id2 join
     release_label rl3_1
     on rl3_1.release = rl1.release join 
     release_label rl3_2
     on rl3_2.release = rl2.release and
        rl3_2.label = rl3_1.label;

РЕДАКТИРОВАТЬ:

Альтернативный метод может быть проще:

select l1.id, l2.id, l3.id as in_common_id
from label l1 join
     label l2
     on l1.id < l2.id join
     label l3
     on l1.id <> l3.id and l2.id <> l3.id
where -- have no releases in common
      not exists (select 1
                  from release_label rl1 join
                       release_label rl2
                       on rl1.release = rl2.release
                  where rl1.label = l1.id and rl2.label = l2.id
                 ) and
      -- l1 has a release with l3
      exists (select 1
              from release_label rl1 join
                   release_label rl3
                   on rl1.release = rl3.release
                  where rl1.label = l1.id and rl3.label = l3.id
             ) and
      -- l2 has a release with l3
      exists (select 1
              from release_label rl2 join
                   release_label rl3
                   on rl2.release = rl3.release
                  where rl2.label = l2.id and rl3.label = l3.id
             );

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

В любом из этих запросов вы можете (конечно) использовать select distinct в первых двух идентификаторах, чтобы просто получитьпары, которые вы ищете.

...