【问题标题】:Linked lists: query first and last element of chained lists stored in SQL table链表:查询存储在 SQL 表中的链表的第一个和最后一个元素
【发布时间】:2020-07-02 14:13:02
【问题描述】:

我有一个 SQL 表,其中的“行”表示链表的元素。 例如,我可以有以下记录:

(id, previous_id)
------------------
(1, NULL)
(2, NULL)
(3, 2)
(4, 3)
(5, NULL)
(6, 4)
(7, 5)

我们在此表中有 3 个列表:

(1,)
(2,3,4,6)
(5,7)

我想查找每个列表的最后一个元素以及列表中的元素数量。 我正在寻找的查询将输出:

last, len
1, 1
6, 4
7, 2

这在 SQL 中可行吗?

【问题讨论】:

    标签: sql postgresql linked-list singly-linked-list recursive-cte


    【解决方案1】:
    WITH RECURSIVE cte AS (
       SELECT id AS first, id AS last, 1 as len
       FROM   lines
       WHERE  previous_id IS NULL
    
       UNION ALL
       SELECT c.first, l.id, len + 1
       FROM   cte   c
       JOIN   lines l ON l.previous_id = c.last
       )
    SELECT DISTINCT ON (first)
           last, len  -- , first -- also?
    FROM   cte
    ORDER  BY first, len DESC;
    

    db小提琴here

    准确地产生你的结果。

    如果你还想要标题状态的第一个元素,那是现成的。

    【讨论】:

      【解决方案2】:

      您可以使用递归 CTE:

      with recursive cte as (
            select l.previous_id as id, id as last
            from lines l
            where not exists (select 1 from lines l2 where l2.previous_id = l.id)
            union all
            select l.previous_id, cte.last
            from cte join
                 lines l
                 on cte.id = l.id
           )
      select cte.last, count(*)
      from cte
      group by cte.last;
      

      Here 是一个 dbfiddle。

      【讨论】:

      • 我的第一个测试表明“列“cte.last”必须出现在 GROUP BY 子句中或用于聚合函数中”。这可能是我的错字。
      【解决方案3】:

      这是 Microsoft SQL Server 2016 db 中的一个实现fiddle

      WITH chain
       AS (SELECT l.id AS [first], 
                  l.id AS [last], 
                  1 AS [len]
           FROM lines AS l
           WHERE l.previous_id IS NULL
           UNION ALL
           SELECT c.[first], 
                  l.id, 
                  c.[len] + 1 AS [len]
           FROM chain AS c
                JOIN lines AS l ON l.previous_id = c.[last]),
       result
       AS (SELECT DISTINCT 
                  c.[first], 
                  c.[last], 
                  c.[len], 
                  ROW_NUMBER() OVER(PARTITION BY c.[first] ORDER BY c.[len] DESC) AS rn
           FROM chain as c)
       SELECT r.[first], 
              r.[last], 
              r.[len]
       FROM result AS r
       WHERE r.rn = 1
       ORDER BY r.[first];
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-18
        • 2023-03-09
        • 1970-01-01
        • 2014-01-11
        • 1970-01-01
        • 2021-06-08
        • 2023-03-16
        • 1970-01-01
        相关资源
        最近更新 更多