【问题标题】:How can I create "recursive sql"如何创建“递归 sql”
【发布时间】:2012-10-08 16:28:07
【问题描述】:

我想做“链接”

例如,我有 5 个帖子(id:“1”,id:“2”,id:“3”,id:“4”,id:“5”)

它们有一个序列

{id:"1", nextId:"2"},
{id:"2", nextId:"4"},
{id:"3", nextId:"0"},
{id:"4", nextId:"3"},
{id:"5", nextId:"0"},

当我从“1”搜索时,我得到了一个结果:{id:"1"}, {id:"2"}, {id:"4"}, {id:"3"} 当我从“5”搜索时,我得到了一个结果:{id:"5"}

如何在 ANSI SQL 中找到 All start with {id:"1"}?

select s.id, s.nextId from sample s
join sample ns on ns.id = s.nextId

它从第一个节点到所有节点。

我想启动“{some id}”并且我想使用“limit 10”

帮帮我!

【问题讨论】:

  • 如果使用 Oracle,您有 CONNECT BY 和 START WITH 子句,但它们不是 ANSI SQL
  • 现在我使用的是 HSQLDB,但是当我完成示例时,我可能不得不使用 MySQL!
  • HSQLDB 文档中有一个很好的例子hsqldb.org/doc/2.0/guide/dataaccess-chapt.html#dac_with_clause
  • 如果您可能不得不使用 MySQL,那么您将不得不寻找其他方式 - 其中 mysql 不支持的是 WITH 子句。我会推荐一个合适的数据库:)

标签: sql recursion hsqldb


【解决方案1】:

其他答案清楚地证明了递归问题 - RDBMS 供应商之间的实现不一致。

或者,您可以使用"nested set" 模型,它完全避免了递归,并且应该很容易在与平台无关的 SQL 实现中构建。

【讨论】:

  • 在这个模型中,INSERT 到表中需要一个 PROCEDURE 定义,不同的实现需要不同的语法。
  • 不一定 - 这是示例代码,但您可以在客户端事务中包装的简单 SQL 语句中实现它...
【解决方案2】:
create table links (id integer, nextid integer);

insert into links 
values 
(1, 2),
(2, 4),
(3, 0),
(4, 3),
(5, 0);

commit;

with recursive link_tree as (
   select id, nextid
   from links
   where id = 1  -- change this to change your starting node
   union all 
   select c.id, c.nextid
   from links c
     join link_tree p on p.nextid = c.id
)
select *
from link_tree;

这是 ANSI SQL,适用于 HSQLDB、PostgreSQL、H2、Firebird、DB2、Microsoft SQL Server、Oracle 11.2 和其他几个引擎 - 只是 在 MySQL(不支持任何现代 SQL 功能是当今最先进的)。

【讨论】:

    【解决方案3】:

    这适用于 sql server,也许它会对你的 HSQLDB 有所帮助

    在您的示例中,如果您通知 1,它将返回

    2->4->3->0
    

    如果您想在开头添加 1 或从末尾删除 0,由您决定

    CREATE table test_sequence(
    id int,
    next_id int
    )
    
    insert into test_sequence VALUES(1,2)
    insert into test_sequence VALUES(2,4)
    insert into test_sequence VALUES(3,0)
    insert into test_sequence VALUES(4,3)
    insert into test_sequence VALUES(5,0)
    
    
    
    alter function selectSequence(@id int)
    returns varchar(max)
    begin
        declare @next varchar(max)
        select @next=next_id from test_sequence WHERE id =@id
        if (@next != '') begin
            return @next +'->'+ dbo.selectSequence(@next)
        end else begin
            select @next=''
        end
        return @next
    end
    
    select dbo.selectSequence(1)
    

    【讨论】:

    • 函数是一种可以使用的方法,尤其是在不支持分层查询的数据库中。但是,原样的代码几乎肯定不会在 HSQLDB 中工作。
    • SQL Server 还支持递归 CTE,如果它比存储过程更有效,我不会感到惊讶。
    • 我不知道你们中的哪一个投了反对票,但 Colin 你的代码也不能在 HSQLDB 上工作,所以这不是 DV 和 a_horse_with_no_name 的原因我没有写 CTE,因为它 100% 确定它不会在 HSQLDB 上工作(或任何其他类似结构)可能受支持,因此也没有理由进行 DV
    • HSQLDB 函数语法是标准 SQL。 MySQL 函数语法很接近。两者都不同于 MSSQL。 HSQLDB 在变量和参数名称中没有@。
    • @a_horse_with_no_name 在 cmets 中,OP 说他们可能必须使用 MYSQL。所以 CTE 出来了。
    【解决方案4】:

    我没有 HSQLDB,但应该这样做:

    WITH RECURSIVE chain(seq, me, next) AS (
      VALUES(0, CAST(null AS int), 1) -- start
      UNION ALL
      SELECT seq + 1, id, nextId
      FROM sample, chain
      WHERE id = next
    )
    SELECT * FROM chain WHERE seq > 0;
    

    【讨论】:

      猜你喜欢
      • 2015-03-18
      • 2011-04-25
      • 2021-07-24
      • 1970-01-01
      • 2022-08-22
      • 2020-09-28
      • 2022-01-21
      • 2015-10-16
      • 2021-12-31
      相关资源
      最近更新 更多