【问题标题】:Recursive query in MySQL 8.0 with dynamic table namesMySQL 8.0 中具有动态表名的递归查询
【发布时间】:2020-02-25 05:58:32
【问题描述】:

我有两张表,一张是sections,这有一个id,一个parent_table和一个parent_id,另一个是pages,它有一个idstatus(以及其他) 列。一个节的父级可以是另一个节或页面,具有相应的parent_table 值。如何使用窗口函数找出给定部分是否在 status = 1 页面上? (使用 MySQL 8.0(或 MariaDB 10.2),但在必要时我可以转换为 postgresql)。

示例数据:

部分

id|parent_table|parent_id
1 |pages       |1
2 |sections    |1
3 |pages       |2
4 |sections    |2

页面

id|status
 1|1
 2|0

要重新创建示例数据:

create table pages (id int not null primary key, status int not null) collate utf8mb4_general_ci;
create table sections (id int not null primary key, parent_table varchar(20), parent_id int not null) collate utf8mb4_general_ci;
insert into pages values (1,1),(2,0);
insert into sections values (1,'pages',1),(2,'sections',1),(3,'pages',2),(4,'sections',2);

【问题讨论】:

    标签: mysql window-functions mysql-8.0


    【解决方案1】:

    要获取所有section对应的页面状态,可以使用如下递归查询:

    with recursive r as (
      select s.id as section_id, s.parent_id, s.parent_table
      from sections s
      union all
      select r.section_id, s.parent_id, s.parent_table
      from r
      join sections s on s.id = r.parent_id and r.parent_table = 'sections'
    )
    select r.section_id, p.id as page_id, p.status
    from r
    join pages p on p.id = r.parent_id
    where r.parent_table = 'pages';
    

    结果:

    | section_id | page_id | status |
    | ---------- | ------- | ------ |
    | 1          | 1       | 1      |
    | 2          | 1       | 1      |
    | 4          | 1       | 1      |
    | 3          | 2       | 0      |
    

    View on DB Fiddle

    递归遍历树从任何部分到它的根部分。这样,您可以将结果限制为内部查询中的单个部分。例如。如果您只想知道第 3 节的状态,您可以在 RCTE 的第一个 UNION 部分使用 WHERE 子句:

    with recursive r as (
      select s.id as section_id, s.parent_id, s.parent_table
      from sections s
      where s.id = 3 -- limit to a single section
      union all
      select r.section_id, s.parent_id, s.parent_table
      from r
      join sections s on s.id = r.parent_id and r.parent_table = 'sections'
    )
    select r.section_id, p.id as page_id, p.status
    from r
    join pages p on p.id = r.parent_id
    where r.parent_table = 'pages';
    

    结果:

    | section_id | page_id | status |
    | ---------- | ------- | ------ |
    | 3          | 2       | 0      |
    

    View on DB Fiddle

    【讨论】:

      【解决方案2】:

      没有 Windows 函数的 SQL 查询将是这样的

      SQL 查询:

      SELECT *
      FROM sections WHERE parent_table = 'pages'  and parent_id IN
      (SELECT id FROM pages WHERE pages.status= 1)
      

      使用 Windows 功能,代码将如下所示:

      declare @parent_table varchar(5)
      declare @status int
      set @status=1;
      set @parent_table='pages';
      with pages as (
      /* Anchor member */
      select s.id, s.parent_table, s.parent_id 
      from sections s
      where s.parent_table=@parent_table
      UNION ALL
      /* Recursive Member */
      select s.id, s.parent_table, s.parent_id, 
      from sections s
      join pages on
          s.parent_table=@parent_table and s.parent_id=pages.id)
      select status from pages where status=1
      option(MAXRECURSION 500)
      

      我们可以将 MAXRECURSION 设置在 1 到 32767 之间

      【讨论】:

      • 这是 SQL Server 代码,我删除了 DECLARE 和选项,它仍然给了我Unknown column 'Level' in 'field list'
      • 是的!考虑到以前的查询和添加的级别,级别是一个不存在的字段,因此不需要。是的,我们可以删除 declare,但当您决定将此查询转换为函数或过程时,它会很好地工作。可重用性是我们不能错过的。
      猜你喜欢
      • 2015-05-05
      • 1970-01-01
      • 2013-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-29
      • 2023-03-12
      • 2011-04-11
      相关资源
      最近更新 更多