【问题标题】:Struggle with complex SQL query: are two nodes linked in a directed graph?与复杂的 SQL 查询作斗争:两个节点是否在有向图中链接?
【发布时间】:2022-12-17 22:13:16
【问题描述】:

我已经在这个 SQL 查询上停留了一天,所以我把它扔在这里,并感谢其他人可以提供的任何建议。

这就是问题所在:我想生成一组tags(文章中的命名实体)、ab,按它们同时出现在多少篇文章中排序。这相对简单。然而,有一个转折:查询还应该检查另一个表,link,看看两个标签之间是否已经存在链接。 link 是有向边,即。两个tags可以连接到a->bb->a

至少,我想过滤掉所有已连接 ab 的链接 - 但更好的实现将允许我返回未过滤的对,只要链接存在,链接的 type 就会返回。

这是基本的配对查询,它按预期工作:

SELECT
   l.cluster AS left_id,
   l.cluster_type AS left_type,
   l.cluster_label AS left_label,
   r.cluster AS right_id,
   r.cluster_type AS right_type,
   r.cluster_label AS right_label,
   count(distinct(l.article)) AS articles
FROM tag AS l, tag AS r
WHERE
   l.cluster > r.cluster
   AND l.article = r.article
GROUP BY l.cluster, l.cluster_label, l.cluster_type, r.cluster, r.cluster_label, r.cluster_type
ORDER BY count(distinct(l.article)) DESC;

基于 CTE 的方法

这是获取存在链接的所有对的子问题的一种解决方案:

WITH links AS (
  SELECT
    greatest(link.source_cluster, link.target_cluster) AS big,
    least(link.source_cluster, link.target_cluster) AS smol,
    link.type AS type
  FROM link AS link
)
SELECT l.cluster AS left_id, l.cluster_type AS left_type, l.cluster_label AS left_label, r.cluster AS right_id, r.cluster_type AS right_type, r.cluster_label AS right_label,
  count(distinct(l.article)) AS articles,
  array_agg(distinct(links.type)) AS link_types
FROM tag AS r, tag AS l
  JOIN links ON l.cluster = links.big
WHERE
  l.cluster > r.cluster
  AND l.article = r.article
  AND r.cluster = links.smol
GROUP BY l.cluster, l.cluster_label, l.cluster_type, r.cluster, r.cluster_label, r.cluster_type
ORDER BY count(distinct(l.article)) DESC

但这不处理显示未链接对,或同时显示链接和未链接对。也许有某种方法可以在处理非链接对的主查询中子查询 links CTE?

表定义

CREATE TABLE tag (
    cluster character varying(40),
    article character varying(255),
    cluster_type character varying(10),
    cluster_label character varying,
);

CREATE TABLE link (
    source_cluster character varying(40),
    target_cluster character varying(40),
    type character varying(255),
);

示例数据

tag

"cluster","cluster_type","cluster_label","article"
"fffcc580c020f689e206fddbc32777f0d0866f23","LOC","Russia","a"
"fffcc580c020f689e206fddbc32777f0d0866f23","LOC","Russia","b"
"fff03a54c98cf079d562998d511ef2823d1f1863","PER","Vladimir Putin","a"
"fff03a54c98cf079d562998d511ef2823d1f1863","PER","Vladimir Putin","b"
"fff03a54c98cf079d562998d511ef2823d1f1863","PER","Vladimir Putin","d"
"ff9be8adf69cddee1b910e592b119478388e2194","LOC","Moscow","a"
"ff9be8adf69cddee1b910e592b119478388e2194","LOC","Moscow","b"
"ffeeb6ebcdc1fe87a3a2b84d707e17bd716dd20b","LOC","Latvia","a"
"ffd364472a999c3d1001f5910398a53997ae0afe","ORG","OCCRP","a"
"ffd364472a999c3d1001f5910398a53997ae0afe","ORG","OCCRP","d"
"fef5381215b1dfded414f5e60469ce32f3334fdd","ORG","Moldindconbank","a"
"fef5381215b1dfded414f5e60469ce32f3334fdd","ORG","Moldindconbank","c"
"fe855a808f535efa417f6d082f5e5b6581fb6835","ORG","KGB","a"
"fe855a808f535efa417f6d082f5e5b6581fb6835","ORG","KGB","b"
"fe855a808f535efa417f6d082f5e5b6581fb6835","ORG","KGB","d"
"fff14a3c6d8f6d04f4a7f224b043380bb45cb57a","ORG","Moldova","a"
"fff14a3c6d8f6d04f4a7f224b043380bb45cb57a","ORG","Moldova","c"

link

"source_cluster","target_cluster","type"
"fff03a54c98cf079d562998d511ef2823d1f1863","fffcc580c020f689e206fddbc32777f0d0866f23","LOCATED"
"fe855a808f535efa417f6d082f5e5b6581fb6835","fff03a54c98cf079d562998d511ef2823d1f1863","EMPLOYER"
"fff14a3c6d8f6d04f4a7f224b043380bb45cb57a","fef5381215b1dfded414f5e60469ce32f3334fdd","LOCATED"

【问题讨论】:

    标签: sql postgresql graph common-table-expression


    【解决方案1】:

    我想你想要的是一个从标签到链接的LEFT OUTER JOIN,它不会过滤掉没有链接的标签对,而是在链接存在时用链接注释它们。

    SELECT
       l.cluster AS left_id,
       l.cluster_type AS left_type,
       l.cluster_label AS left_label,
       r.cluster AS right_id,
       r.cluster_type AS right_type,
       r.cluster_label AS right_label,
       count(distinct(l.article)) AS articles,
       max(link.type) as type,
       l.cluster = max(link.source_cluster) AS "->"
    FROM tag AS l CROSS JOIN tag AS r
    LEFT OUTER JOIN link ON 
    (l.cluster = link.source_cluster AND r.cluster = link.target_cluster)
    OR
    (l.cluster = link.target_cluster AND r.cluster = link.source_cluster)
    WHERE
       l.cluster > r.cluster
       AND l.article = r.article
    GROUP BY l.cluster, l.cluster_label, l.cluster_type, r.cluster, r.cluster_label, r.cluster_type
    ORDER BY count(distinct(l.article)) DESC;
    

    max() 业务是我懒于修复查询不知道每个标签对最多有一个链接的事实,因此它需要一个聚合函数。

    【讨论】:

      猜你喜欢
      • 2019-04-20
      • 1970-01-01
      • 2021-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-14
      相关资源
      最近更新 更多