MySQL 8.0 中具有动态 table 名称的递归查询

Recursive query in MySQL 8.0 with dynamic table names

我有两个表,一个是sections,这个有一个id,一个parent_table和一个parent_id,另一个是pages有一个 idstatus (和其他)列。一个部分的父级可以是另一个部分或页面,具有相应的 parent_table 值。我如何使用 window 函数找出给定部分是否在 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);

如果没有 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 之间

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

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