postgresql “链/可传递”连接最佳方式

omvjsjqw  于 2022-11-04  发布在  PostgreSQL
关注(0)|答案(1)|浏览(99)

我遇到了下面看起来很容易的问题,但是我找不到一个最优的方法来创建查询。
我有一个表,其中有对,并且都有一个party_id。
| 姓名|名称对|交易方标识|
| - -|- -|- -|
| A级|A1级|一个|
| A级|A2页|2个|
| A2页|C1级|三个|
| 地下二层|第一天|四个|
| 地下二层|E1级|五个|
由于[A,A1],[A,A2],[A2,C1],其意味着**[A,A1,A2,C1]应该在一起,并且公共party_id应该是所有这些party_id的最小值,因此1**A-〉A,A1,A2-〉C1 -〉A,A1,A2,C1
对方为[B2,D1,E1] -〉4
我希望看到的结果:
| 姓名|名称对|交易方标识|结果|
| - -|- -|- -|- -|
| A级|A1级|一个|一个|
| A级|A2页|2个|一个|
| A2页|C1级|三个|一个|
| 地下二层|第一天|四个|四个|
| 地下二层|E1级|五个|四个|
首先我试着交叉加入,但它只sloves直到党的大小是2...
速度很重要,因为此表有数百万行。

2mbi3lxu

2mbi3lxu1#

就我对您的情况的理解,您需要一个递归查询,因为C1是A2的对,A2是A的对。下面是一个需要花费一些时间的解决方案,因为它需要在递归查询的第一部分扫描整个表,即使列name上存在索引,并且应该由查询计划器在第二部分使用:

WITH RECURSIVE list (name, name_pair, party_id, result, checks) AS (
  SELECT *
       , min(party_id) OVER (PARTITION BY name)
       , array[name]
    FROM mytable AS name
  UNION ALL
  SELECT t.*
       , least(l.result, min(t.party_id) OVER (PARTITION BY t.name))
       , l.checks || t.name
    FROM list AS l
   INNER JOIN mytable AS t
      ON t.name = l.name_pair
   WHERE NOT l.checks @> array[t.name] -- this condition avoids infinite loops
)
SELECT name
     , name_pair
     , party_id
     , min(result) AS result
  FROM list
 GROUP BY name, name_pair, party_id

请参见dbfiddle中的测试结果

相关问题