1.设计表
表名:genealogy(族谱)
字段:1.id(编号),2.name(姓名),3.parent_id(父亲编号,没有父亲值为-1)
sql: CREATE TABLE `genealogy` (
`id` int NOT NULL AUTO_INCREMENT ,
`name` varchar(255) NOT NULL ,
`parent_id` int NOT NULL DEFAULT -1 ,
PRIMARY KEY (`id`)
)
2.录入模拟数据
模拟数据:
id | name | parent_id |
---|---|---|
1 | 张宗主 | -1 |
2 | 张大 | 1 |
3 | 张小 | 1 |
4 | 张大傻 | 2 |
5 | 张小傻 | 3 |
6 | 张大傻傻 | 4 |
sql:INSERT INTO genealogy (id, NAME, parent_id)
VALUES
(1, '张宗主' ,- 1),
(2, '张大', 1),
(3, '张小', 1),
(4, '张大傻', 2),
(5, '张小傻', 3),
(6, '张大傻傻', 4)
3.编写sql
最终sql,以张大傻傻为例:
SELECT
genealogy.*
FROM
genealogy,
(
SELECT
@id AS id,
(
SELECT
@id := parent_id
FROM
genealogy
WHERE
id =@id
) AS parent_id
FROM
genealogy,
(SELECT @id := 6) tab
WHERE
@id !=- 1
) temp
WHERE
temp.id = genealogy.id;
4.分析sql
1.需要一个可变的查询条件id
id 6 查出父亲 parent_id 4 这是第一次查询,需要做递归查询,第二次查询id值为4
sql中定义变量,并能在select中语句使用---特殊临时表 (SELECT @id := 6) tab
其中@id:=?为赋值。
2.如何使用临时表tab,跟族谱表做关联查询,join两张表,且是full join:
SELECT
@id AS id,
(
SELECT
@id := parent_id
FROM
genealogy
WHERE
id =@id
) AS parent_id
FROM
genealogy,
(SELECT @id := 6) tab
@id的值就是当次查询的编号id,所以@id AS id,而@id值需要更改,在做完当次查询后,再做一次字段查询,
嗯,这里是最纠结的地方,原谅我不想查资料。
(无从查起,不知道咋提问,去官网翻文档?哦的天,茫茫资料海,想想生畏,还是算了)
给个大胆的猜测,@id的工作原理是逐行执行,并在执行时,保留瞬时值,而不是在得到整个表结果的时候,
一次性替换它的最终值,最终值没有意义肯定是-1。
那么在这个大前提下,流程就简单了,full join操作提供了循环次数,为genealogy的记录数,
每行数据的生成应该是这样的,读下当前@id值,写入id值,再执行字段查询得出parent_id值,
并覆盖掉原来的@id值,单次循环结束,以此类推。
所以在没有加where id!=-1前,查出的记录数肯定同genealogy的记录数相等,并且无效的记录的id值必然为-1。
其实到了这步接下来的操作就无需解释了,嗯,那下面略。