Sql Postgres父子网络id

Sql Postgres父子网络id,sql,postgresql,graph-theory,Sql,Postgresql,Graph Theory,我需要计算相互依赖对象的网络。对于每个E-C链接,我需要额外的列,即这些对象所属的“唯一网络id”。例如,在金融业,贷款与他们融资的对象相关联 create table ec ( e varchar(10), c varchar(10) ); insert into ec values ('E1','C1'); insert into ec values ('E1','C2'); insert into ec values ('E1','C3'); insert into ec

我需要计算相互依赖对象的网络。对于每个E-C链接,我需要额外的列,即这些对象所属的“唯一网络id”。例如,在金融业,贷款与他们融资的对象相关联

create table ec (
    e varchar(10),
    c varchar(10)
);

insert into ec values ('E1','C1');
insert into ec values ('E1','C2');
insert into ec values ('E1','C3');
insert into ec values ('E2','C3');
insert into ec values ('E3','C3');
insert into ec values ('E3','C4');
insert into ec values ('E4','C5');
insert into ec values ('E4','C6');
和输出应为以下之一:

+--------+--------+------------+
| EXP_ID | CRM_ID | NETWORK_ID |
+--------+--------+------------+
| E1     | C1     |          1 |
| E1     | C2     |          1 |
| E1     | C3     |          1 |
| E2     | C3     |          1 |
| E3     | C3     |          1 |
| E3     | C4     |          1 |
| E4     | C5     |          2 |
| E4     | C6     |          2 |
+--------+--------+------------+
或:

可视连接如下所示:

我一直在研究递归查询,但我不确定这是否是正确的方法。
那么,递归查询是实现这一点的一种方法吗?我应该多考虑一下?或者还需要其他类似于图形分析的东西?

是的,递归查询可以实现这一点。这是一个概念证明,它确实计算了每条边的可到达边(即网络中的所有边)的传递集,由给定给边的id设置关键帧,然后将最小(该边的id)边作为网络的代表,用于每条边:

WITH RECURSIVE eci AS (
  SELECT row_number() OVER () AS id, * FROM ec
),
networks AS (
  SELECT * FROM eci
UNION
  SELECT LEAST(eci.id, n.id), eci.e, eci.c FROM eci JOIN networks n ON n.e = eci.e OR n.c = eci.c
)
SELECT min(id), ec.e, ec.c FROM ec JOIN networks USING (e, c) GROUP BY e, c;
()


免责声明:我怀疑这是否有效。我尝试过在递归过程中修剪
网络

是的,递归查询可以实现这一点。这是一个概念证明,它确实计算了每条边的可到达边(即网络中的所有边)的传递集,由给定给边的id设置关键帧,然后将最小(该边的id)边作为网络的代表,用于每条边:

WITH RECURSIVE eci AS (
  SELECT row_number() OVER () AS id, * FROM ec
),
networks AS (
  SELECT * FROM eci
UNION
  SELECT LEAST(eci.id, n.id), eci.e, eci.c FROM eci JOIN networks n ON n.e = eci.e OR n.c = eci.c
)
SELECT min(id), ec.e, ec.c FROM ec JOIN networks USING (e, c) GROUP BY e, c;
()


免责声明:我怀疑这是否有效。我尝试过在递归过程中修剪
网络

我一直在玩弄不同的想法,试图减少跨大型网络所需的工作量

我玩数组,我被Recurives CTE阻止,不允许对递归表达式进行聚合或多重引用(不将CTE连接到自身)

我目前的“最佳”尝试试图以递归组合集合的方式来处理这个问题。在以下情况下,一个集合被合并到另一个集合中:

  • 这两个集合共享一个成员(
    c
  • “其他”集合具有“较低”标识符
我希望这意味着最坏的情况是二进制模式;1024行最多需要10个递归深度(1024个集变成512,变成256,等等)

我考虑这个问题的原因是@Bergi中的anser最糟糕的情况是1024个节点需要1023个递归深度

然而,反过来说,我的方法最终需要(我认为)为每次迭代付出更多的努力。我很想知道哪一个比更大的数据集性能更好

  • 我不是说Bergi's不好
  • 我不是说我的更好
  • 我只是说他们不同


编辑:

再加上两次尝试,确定不可能进一步增长的组,并将它们排除在进一步迭代之外

在数据的配置文件上进行数据剥离这可能需要比节省更多的精力(大多数组需要类似的递归深度),或者可能会有所帮助(需要递归深度的较大变化)


我一直在尝试不同的想法,以减少跨大型网络所需的工作量

我玩数组,我被Recurives CTE阻止,不允许对递归表达式进行聚合或多重引用(不将CTE连接到自身)

我目前的“最佳”尝试试图以递归组合集合的方式来处理这个问题。在以下情况下,一个集合被合并到另一个集合中:

  • 这两个集合共享一个成员(
    c
  • “其他”集合具有“较低”标识符
我希望这意味着最坏的情况是二进制模式;1024行最多需要10个递归深度(1024个集变成512,变成256,等等)

我考虑这个问题的原因是@Bergi中的anser最糟糕的情况是1024个节点需要1023个递归深度

然而,反过来说,我的方法最终需要(我认为)为每次迭代付出更多的努力。我很想知道哪一个比更大的数据集性能更好

  • 我不是说Bergi's不好
  • 我不是说我的更好
  • 我只是说他们不同


编辑:

再加上两次尝试,确定不可能进一步增长的组,并将它们排除在进一步迭代之外

在数据的配置文件上进行数据剥离这可能需要比节省更多的精力(大多数组需要类似的递归深度),或者可能会有所帮助(需要递归深度的较大变化)


那么你想找到一个二部图的顶点?我怀疑用一个图算法可以很容易地解决这个问题,但在SQL中很难解决(虽然不是不可能)。我需要从一个巨大的连接顶点对列表中找到连接的组件。那么你想找到一个二部图?我怀疑用一个图算法可以很容易地解决这个问题,但在SQL中很难解决(虽然不是不可能)。我需要从一个巨大的连接顶点对列表中找到连接的组件。谢谢,这会给出想要的结果。将在100k+行数据集上测试它。谢谢,这将提供所需的结果。将在100k+行数据集上测试它。@bergi-我想听听您对这种方法的看法?“我被递归CTE阻止了,不允许聚合或对递归表达式进行多个引用”-这里也是一样,我也尝试使用这些:-)我想您需要实际对它们进行基准测试,没有其他方法可以知道。@bergi-我对您对这种方法的看法感兴趣?“我被递归CTE阻止了,因为它不允许聚合或对递归表达式的多个引用”-这里一样,我也尝试使用这些:-)我想您需要实际对它们进行基准测试,没有其他方法可以知道。
WITH RECURSIVE
  groups AS
(
  SELECT
    e,
    c,
    DENSE_RANK() OVER (ORDER BY e) AS group_id,
    0                              AS search_depth,
    COUNT(*) OVER ()               AS total_changes
  FROM
    ec

  UNION ALL

  SELECT
    e,
    c,
    new_group_id               AS group_id,
    search_depth + 1           AS search_depth,
    SUM(has_changed) OVER ()   AS total_changes
  FROM
  (
    SELECT
      e, c, group_id, search_depth, new_group_id,
      CASE WHEN group_id = new_group_id THEN 0 ELSE 1 END  AS has_changed
    FROM
    (
      SELECT
        e, c, group_id, search_depth,
        MIN(new_group_id) OVER (PARTITION BY group_id) AS new_group_id
      FROM
      (
        SELECT
          e, c, group_id, search_depth,
          MIN(group_id) OVER (PARTITION BY c) AS new_group_id
        FROM
          groups
        WHERE
          total_changes > 0
      )
        combine_by_c
    )
      combine_by_group
  )
    tally_changes
)
SELECT * FROM groups WHERE total_changes = 0