sql父子查询

分析sql过程

预热

  1. 分析下面的sql的执行流程
SELECT @ids AS _ids,
		( SELECT @ids := GROUP_CONCAT( id ) FROM chat WHERE FIND_IN_SET( pid, @ids ) ) AS cids,
		@l := @l + 1 AS LEVEL
FROM
    chat, ( SELECT @ids := '1', @l := 0 ) b
WHERE
    @ids IS NOT NULL 

这段SQL语句是一个递归查询,用于在表格 chat
中查找具有父子关系的记录,并计算每个记录的层级(LEVEL)。这里使用了用户自定义的变量(@ids和@l)来执行递归操作。以下是这段SQL语句的执行流程:

  1. FROM 子句:首先,SQL引擎处理 FROM 子句,它从 chat 表中检索数据,并将其与一个子查询((SELECT @ids := ‘1’, @l := 0)
    )联接在一起。这个子查询初始化了两个用户自定义变量,@ids设置为 ‘1’,@l设置为 0。
  2. WHERE 子句:WHERE 子句中的条件 @ids IS NOT NULL 用于控制递归的终止条件。只要 @ids 不为 NULL,查询就会继续执行。
  3. SELECT 子句:SELECT 子句包含了三个部分:
  • @ids AS _ids:将当前的 @ids 值赋给 _ids。
  • (SELECT @ids := GROUP_CONCAT( id ) FROM chat WHERE FIND_IN_SET( pid, @ids ) ) AS cids:在这一部分,GROUP_CONCAT 函数用于将与
    @ids 中的 pid 值相关的 id 值连接成一个逗号分隔的字符串。然后,这个字符串被赋给 @ids,以便在下一次迭代中使用。这将更新
    @ids 变量以包含新的 id 值。
  • @l := @l + 1 AS LEVEL:将 @l 增加 1,并将结果赋给 LEVEL 变量,用于跟踪当前记录的层级。
  1. 执行递归:在每次迭代中,@ids 的值都会更新,通过查找满足 FIND_IN_SET(pid, @ids) 条件的记录,将与 @ids 中的 pid
    值相关的子记录添加到结果集中。这个过程将一直进行,直到不再有满足条件的记录,此时 @ids 变量将为 NULL,查询结束。
  2. 结果集:查询的结果集将包括 _ids(包含每个记录的初始 id 值)、cids(包含每个记录的关联 id 值列表),以及 LEVEL(每个记录的层级)。
    这个SQL查询执行了一种递归操作,用于查找具有父子关系的记录,并构建一个层次结构。在每次迭代中,通过更新 @ids 变量,它查找与当前
    @ids 中的 pid 值相关的子记录。这允许你在结果中获得每个记录的层级信息。

用于分析的数据

chat_summary表数据

id pid branch ask
1 0 0 苏州有几个区0
2 1 1 苏州有几个湖1
3 2 0 苏州有几个县跟着几个湖1来的
4 1 2 苏州有几个湖2
5 1 3 苏州有几个湖3
6 5 0 苏州有哪些美食,跟着有几个湖3来的
7 6 0 有哪些景区,跟着美食来的

sql查询


create table ttt as
SELECT DISTINCT c1.LEVEL - 1 LEVEL,
                c2.id,
                c2.pid,
                c2.ask
FROM (SELECT @ids AS _ids,
		( SELECT @ids := GROUP_CONCAT( id ) FROM chat WHERE FIND_IN_SET( pid, @ids ) ) AS cids,
		@l := @l + 1 AS LEVEL
      FROM
          chat, ( SELECT @ids := '1', @l := 0 ) b
      WHERE
          @ids IS NOT NULL) c1,
     chat_summary c2
WHERE FIND_IN_SET(c2.id, c1._ids)
ORDER BY LEVEL,
         id

查询ttt表结果如下:
LEVEL id pid ask
0 1 0 苏州有几个区0
1 2 1 苏州有几个湖1
1 4 1 苏州有几个湖2
1 5 1 苏州有几个湖3
2 3 2 苏州有几个县跟着几个湖1来的
2 6 5 苏州有哪些美食,跟着有几个湖3来的
3 7 6 有哪些景区,跟着美食来的

sql查询

select max(id), ask, level
from ttt
group by level
查询结果如下:
max(id) ask level
1 苏州有几个区 0
5 苏州有几个湖 1
6 苏州有几个县跟着几个湖1来的 2
7 有哪些景区,跟着美食来的 3

此时已经符合预期!!!

sql查询

select find_in_set("abc", "123,abc,456")
结果如下:
a
2

探寻测试之路

tes表内容如下

id name interests
1 Alice Sports,Travel
2 Bob Music,Reading
3 Charlie Sports,Cooking,Music
4 David Travel,Cooking

sql查询

SELECT *
FROM tes
WHERE FIND_IN_SET('Music', interests) > 0;

查询结果如下:

id name interests
2 Bob Music, Reading
3 Charlie Sports, Cooking, Music

sql查询


SELECT @ids AS _ids,
		( SELECT @ids := GROUP_CONCAT( id ) FROM chat WHERE FIND_IN_SET( pid, @ids ) ) AS cids,
		@l := @l + 1 AS LEVEL
FROM
    chat, ( SELECT @ids := '1', @l := 0 ) b
WHERE
    @ids IS NOT NULL 

查询结果如下:

_ids cids LEVEL
1 2,4,5 1
2,4,5 3,6 2
3,6 7 3
7 NULL 4

sql查询

SELECT @ids := '0', @l := 0

查询结果如下:

@ids := ‘0’ @l := 0
0 0

最终优化sql


select d.*
from (SELECT @ids AS _ids,
@n as maxid,

		@n:=( SELECT @ids := max(id) FROM chat WHERE pid= @ids group by pid) AS cids,
		@l := @l + 1 AS LEVEL
      FROM
          chat, ( SELECT @ids := '1', @l := 0, @n := '1' ) b
      WHERE
          @ids IS NOT NULL
        and @n is not null) c
         left join chat_summary d on c.maxid = d.id

SELECT max(id)
FROM chat
group by pid

最终结果

id pid branch ask
1 0 0 苏州有几个区0
5 1 3 苏州有几个湖3
6 5 0 苏州有哪些美食,跟着有几个湖3来的
7 6 0 有哪些景区,跟着美食来的

你可能感兴趣的:(sql,数据库,java)