【问题标题】:SQL - Self Join to find two label with a release in common with a third labelSQL - 自加入以查找两个标签,其中一个发布与第三个标签相同
【发布时间】:2018-06-03 13:46:00
【问题描述】:

我正在使用 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

感谢您的建议。

【问题讨论】:

  • 一些示例数据会有所帮助,并且还可以考虑使您的问题比目前更小(如果这仍然可以让您的观点得到理解)。
  • @TimBiegeleisen 实际上这些表充满了数据。 Label 包含很多 ID 和名称,对于每个名称,在 release_label 中与另一个标签有一个或多个对应关系。

标签: sql postgresql pgadmin self-join musicbrainz


【解决方案1】:

此查询获取从未发布过任何共同点的标签对:

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 检查您要检查的三个条件。这是我会使用的版本,因为我认为逻辑更容易理解。

在任一查询中,您(当然)可以在前两个 id 上使用 select distinct 来获取您正在寻找的对。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-20
    • 1970-01-01
    • 1970-01-01
    • 2017-06-13
    • 2019-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多