mysql - 棘手的 CTE - 递归 sql(编辑我的查询)

标签 mysql sql common-table-expression recursive-query

我想编辑我的查询以获得更棘手的内容。

目标是获得每个客户的审批工作流程,并以这种方式显示该信息:

CLIENT | APPROVER1 | APPROVER2 | APPROVER3 | APPROVER4

以前,我有一个名为实体的表

(12, 'Math Andrew', 308, 'CHAIN1-MathAndrew')
(13, 'John Connor', 308, 'CHAIN2-JohnConnor')
(18, 'ZATCH', 309, null),
(19, 'MAX', 309, null),
(20, 'Ger',310, null),
(21, 'Mar',310, null),
(22, 'Maxwell',311, null),
(23, 'Ryan',312, null),
(24, 'Juy',313, null),
(25, 'Angel',314, null),
(26, 'John',315, null);

请注意:

12 was assigned to Math Andrew... 308 is the number that says that Matt Andrew is a CLIENT

13 was assigned to John Connor... 308 is the number that says that John Connor is a CLIENT

因为 Math Andrew 和 John Connor 是客户(也称为客户),所以他们必须链接到一个或多个批准者

一个客户端可以有 1 个 APPROVER、OR 2 APPROVERS、3 个 APPROVERS 或 4 个 APPROVER,实体表中存在不同的审批人。

当我说客户“可以拥有”1 个或更多批准者时,我的意思是:

CLIENT - APPROVER4 (this is a 1-1 relationship) PS: A CLIENT WILL ALWAYS BE RELATED TO the APPROVER4 IN SOME WAY OR ANOTHER

CLIENT - APPROVER1 - APPROVER4 (in this case there Will be 2 relations.. ONE: CLIENT-APPROVER1 and another APPROVER1-APPROVER4)

CLIENT - APPROVER1 - APPROVER2 - APPROVER4 (in this case there Will be 3 relations.. ONE: CLIENT-APPROVER1, APPROVER1- APPROVER2 AND APPROVER2 - APPROVER4)

等等...(希望您明白)

表 type_entities

(308,'CLIENT'),
(309,'APPROVER1'),
(310,'APPROVER2'),
(311,'APPROVER3'),
(312,'J3 APPROVER4'),
(313,'J4 APPROVER4'),
(314,'J5 APPROVER4'),
(315, 'J6 APPROVER4'),
(316,'J7 APPROVER4');

表类型_关系

(444,'J6 CLIENT-APPROVER4'),
(445,'J3 CLIENT-APPROVER4'),
(446,'J4 CLIENT-APPROVER4'),
(447,'J10 CLIENT-APPROVER4'),
(449,'J5 CLIENT-APPROVER4'),
(453,'J5 CLIENT-APPROVER4'),
(456,'J7 CLIENT-APPROVER4'),
(457,'J8 CLIENT-APPROVER4'),
(458,'CLIENT-APPROVER3'),
(459,'CLIENT-APPROVER1'),
(460,'APPROVER1-APPROVER2'),
(461,'APPROVER1-APPROVER3'),
(462,'J3 APPROVER1-APPROVER4'),
(463,'APPROVER2-APPROVER3'),
(464,'J3 APPROVER3-APPROVER4'),
(465,'J4 APPROVER3-APPROVER4'),
(466,'J5 APPROVER3-APPROVER4'),
(467,'J6 APPROVER3-APPROVER4'),
(468,'J7 APPROVER3-APPROVER4'),
(469,'J8 APPROVER3-APPROVER4'),
(470,'J10 APPROVER3-APPROVER4'),
(471,'CLIENT-APPROVER2');
<小时/>

关系类型:

客户 - 批准者 1:

(459,'CLIENT-APPROVER1') 

客户 - APPROVER2:

(471,'CLIENT-APPROVER2') 

客户 - APPROVER3:

(461,'APPROVER1-APPROVER3')

客户 - APPROVER4:

(445,'J3 CLIENT-APPROVER4'),
(446,'J4 CLIENT-APPROVER4'),
(449,'J5 CLIENT-APPROVER4'),
(444,'J6 CLIENT-APPROVER4'),
(456,'J7 CLIENT-APPROVER4'),
(457,'J8 CLIENT-APPROVER4'),
(447,'J10 CLIENT-APPROVER4');

批准者 1 -批准者 2:

(460,'APPROVER1-APPROVER2')

批准者 2 - 批准者 3:

(463,'APPROVER2-APPROVER3')

批准者 3 - 批准者 4:

(464,'J3 APPROVER3-APPROVER4'),
(465,'J4 APPROVER3-APPROVER4'),
(466,'J5 APPROVER3-APPROVER4'),
(467,'J6 APPROVER3-APPROVER4'),
(468,'J7 APPROVER3-APPROVER4'),
(469,'J8 APPROVER3-APPROVER4'),
(470,'J10 APPROVER3-APPROVER4');
<小时/>

THIS IS IMPORTANT: when a client is linked to one approver, a NEW RELATION is created inside relationships table.

表关系:

(787,459,12,18),
(788,460,18,20),
(789,463,20,21),
(790,467,21,26);

787 IS THE NUMBER THAT WAS ASSIGNED WHEN THAT ROW WAS CREATED

459 REPRESENTS THE RELATION: CLIENT - APPROVER

12 CHAIN1-MathAndre is the client

18 is the approver

遵循这个想法:

APPROVER1 已链接到 APPROVER2:

(788,460,18,20)

APPROVER2 已链接到 APPROVER3:

(789,463,20,21)

APPROVER3 已链接到 APPROVER4:

(790,467,21,26) ​

所以,我在屏幕上显示这个:

|CLIENT               | APPROVER1 | APPROVER2 | APPROVER3 | APPROVER4|
|CHAIN1-MathAndrew    |   ZATCH   |   Ger     |    Mar    |    John  |
|CHAIN2-JohnConnor    |    MAX    |           |    Mario  |    Steven|
|CHAIN3-MarioShapiro  |    IVAN   |           |           |    John  |

这是我的 fiddle :

fiddle

这是我的查询:

WITH recursive relationships_CTE as (
  select e.id, e.description AS name, 1 col_id, 
    row_number() over (order by e.id) row_id
  from entities e
  where e.description like 'CHAIN%'
    UNION ALL
  select r.description_entitiy_2, e.name, col_id+ 1, row_id
  from relationships_CTE cte
  left join relationships r
    on r.description_entitiy_1 = cte.id
  join entities e 
    on r.description_entitiy_2 = e.id
)
select 
  max(case when col_id = 1 then name end) client,
  max(case when col_id = 2 then name end) approver1,
  max(case when col_id = 3 then name end) approver2,
  max(case when col_id = 4 then name end) approver3,
  max(case when col_id = 5 then name end) approver4
from relationships_CTE
group by row_id
<小时/>

现在,这就是我想做的:

假设我有一个名为 new_table 的新表,并且我稍微修改了表实体:

(12, 'Math Andrew', 308, 45)
(13, 'John Connor', 308, 46)
(18, 'ZATCH', 309, null),
(19, 'MAX', 309, null),
(20, 'Ger',310, null),
(21, 'Mar',310, null),
(22, 'Maxwell',311, null),
(23, 'Ryan',312, null),
(24, 'Juy',313, null),
(25, 'Angel',314, null),
(26, 'John',315, null);

表 new_table

(45,'Math Andrew', 'Chain1')
(45,'Math Andrew', 'Chain2')
(46, 'John Connor', 'Chain1')
(46, ''John Connor', 'Chain2')

关系将如下所示:

(787,459,'45-Chain1',18)
(788,460,18,20)
(789,463,20,21)
(790,467,21,26)

所以,我想将表 entities 与表 new_table 连接起来,获取关系 45-Chain1,然后在表关系中找到 45-Chain1 并得到类似的内容(并对所有不同的客户端执行相同的操作):

|CLIENT               | APPROVER1 | APPROVER2 | APPROVER3 | APPROVER4|
|45-Chain1            |   ZATCH   |   Ger     |    Mar    |    John  |

我一直在尝试解决这个问题,但没有成功。

你能帮我一下吗?

最佳答案

我试过了。
并进行了一些额外的标准化,添加了一个chains表。

这是我的尝试:

create table entity_types 
(
 entity_type_id int primary key, 
 entity_type_name varchar(32) not null
);
create table relation_types 
(
 relation_type_id int primary key, 
 relation_type_name varchar(32) not null
);
create table chains 
(
 chain_id int primary key,
 chain_name varchar(30) not null
);
create table entities 
(
 entity_id int primary key,
 entity_name varchar(32) not null, 
 entity_type_id int not null,
 chain_id int,
 foreign key (entity_type_id)
         references entity_types(entity_type_id),
 foreign key (chain_id)
         references chains(chain_id)
);
create table relationships 
(
 relationship_id int primary key, 
 relation_type_id int not null,
 entity_id_1 int not null,
 entity_id_2 int not null,
 foreign key (relation_type_id)
         references relation_types(relation_type_id)
);
create table entity_chains 
(
 entity_id int not null,
 chain_id int not null,
 primary key (entity_id, chain_id),
 foreign key (chain_id)
         references chains(chain_id),
 foreign key (entity_id) 
         references entities(entity_id)
);
INSERT INTO entity_types
(entity_type_id, entity_type_name) VALUES
(308,'CLIENT'),
(309,'APPROVER1'),
(310,'APPROVER2'),
(311,'APPROVER3'),
(312,'J3 APPROVER4'),
(313,'J4 APPROVER4'),
(314,'J5 APPROVER4'),
(315,'J6 APPROVER4'),
(316,'J7 APPROVER4');
INSERT INTO relation_types
(relation_type_id, relation_type_name) VALUES
(444,'J6 CLIENT-APPROVER4'),
(445,'J3 CLIENT-APPROVER4'),
(446,'J4 CLIENT-APPROVER4'),
(447,'J10 CLIENT-APPROVER4'),
(448,'J4 CLIENT-APPROVER4'),
(449,'J5 CLIENT-APPROVER4'),
(450,'J10 CLIENT-APPROVER4'),
(451,'J3 CLIENT-APPROVER4'),
(452,'J8 CLIENT-APPROVER4'),
(453,'J5 CLIENT-APPROVER4'),
(454,'J6 CLIENT-APPROVER4'),
(455,'J7 CLIENT-APPROVER4'),
(456,'J7 CLIENT-APPROVER4'),
(457,'J8 CLIENT-APPROVER4'),
(458,'CLIENT-APPROVER3'),
(459,'CLIENT-APPROVER1'),
(460,'APPROVER1-APPROVER2'),
(461,'APPROVER1-APPROVER3'),
(462,'J3 APPROVER1-APPROVER4'),
(463,'APPROVER2-APPROVER3'),
(464,'J3 APPROVER3-APPROVER4'),
(465,'J4 APPROVER3-APPROVER4'),
(466,'J5 APPROVER3-APPROVER4'),
(467,'J6 APPROVER3-APPROVER4'),
(468,'J7 APPROVER3-APPROVER4'),
(469,'J8 APPROVER3-APPROVER4'),
(470,'J10 APPROVER3-APPROVER4'),
(471,'CLIENT-APPROVER2');
insert into chains 
(chain_id, chain_name) values
(45,'Chain1'),
(46,'Chain2');
INSERT INTO entities 
(entity_id, entity_name, 
 entity_type_id, chain_id) VALUES
(12, 'Math Andrew', 308, 45),
(13, 'John Connor', 308, 46),
(18, 'ZATCH', 309, null),
(19, 'MAX', 309, null),
(20, 'Ger',310, null),
(21, 'Mar',310, null),
(22, 'Maxwell',311, null),
(23, 'Ryan',312, null),
(24, 'Juy',313, null),
(25, 'Angel',314, null),
(26, 'John',315, null);
INSERT INTO relationships 
(relationship_id, relation_type_id,
 entity_id_1, entity_id_2) VALUES
(787,459,12,18),
(788,460,18,20),
(789,463,20,21),
(790,467,21,26);
insert into entity_chains 
(entity_id, chain_id) values
(12, 45),
(12, 46),
(13, 45),
(13, 46);
WITH RECURSIVE RCTE AS
(
  SELECT
   ent.chain_id,
   entch.entity_id as entity_id_0,
   0 as lvl,
   0 as entity_id_1,
   entch.entity_id as entity_id_2,
   0 as relation_type_id
  FROM entities ent
  JOIN entity_chains entch
    ON entch.chain_id = ent.chain_id

  UNION ALL

  SELECT 
  cte.chain_id,
  cte.entity_id_0,
  lvl+1,
  rel.entity_id_1,
  rel.entity_id_2,
  rel.relation_type_id
  FROM RCTE cte
  JOIN relationships rel
    ON rel.entity_id_1 = cte.entity_id_2
),
CTE AS
(
  SELECT
  rcte.*,
  chains.chain_name,
  ent0.entity_name as entity_name_0,
  -- reltype.relation_type_name,
  -- enttype2.entity_type_name as entity_type_name_2,
  -- ent1.entity_name as entity_name_1,
  ent2.entity_name as entity_name_2
  FROM RCTE rcte
  JOIN chains ON chains.chain_id = rcte.chain_id
  JOIN entities ent0 ON ent0.entity_id = rcte.entity_id_0
  JOIN entities ent2 ON ent2.entity_id = rcte.entity_id_2
  -- LEFT JOIN entity_types enttype2 ON enttype2.entity_type_id = ent2.entity_type_id
  -- LEFT JOIN relation_types reltype ON reltype.relation_type_id = rcte.relation_type_id
  -- LEFT JOIN entities ent1 ON ent1.entity_id = rcte.entity_id_1
)
/*
SELECT * FROM CTE WHERE lvl > 0
ORDER BY chain_name, entity_id_0, lvl;
*/
SELECT 
REPLACE(CONCAT(entity_name_0,'-',chain_name),' ','') as chain_client,
max(case when lvl=1 then entity_name_2 end) as approver1,
max(case when lvl=2 then entity_name_2 end) as approver2,
max(case when lvl=3 then entity_name_2 end) as approver3,
max(case when lvl=4 then entity_name_2 end) as approver4
FROM CTE cte
WHERE lvl > 0
GROUP BY chain_name, entity_name_0
ORDER BY chain_client;
chain_client      | approver1 | approver2 | approver3 | approver4
:---------------- | :-------- | :-------- | :-------- | :--------
MathAndrew-Chain1 | ZATCH     | Ger       | Mar       | John     
MathAndrew-Chain2 | ZATCH     | Ger       | Mar       | John     

db<> fiddle here

关于mysql - 棘手的 CTE - 递归 sql(编辑我的查询),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59021115/

相关文章:

Mysql使用高级正则表达式选择数据

C# SQL null convert to-from,这有什么问题吗?

sql - 从sql server获取windows用户登录名

postgresql - PostgreSQL 中的公用表表达式

MYSQL:不能/如何使用子查询作为完全限定的 CTE

php - MySQL更新记录,但页面显示不显示新数据

android - 在 SQL Server 上使用参数和通配符

php - MySQL 5.7+,嵌套路径中的 JSON_SET 值

sql - 删除域对象时获取 'Referential integrity constraint violation'

sql - SQL Server 2005 中 CTE 的评估