1. Introduction
When there is a hierarchical relationship, the parent_id field is usually added when designing the table structure to indicate the parent node.
The query of the tree table is different from the regular table. In most cases, querying the data of the parent node must recursively query its child nodes, and deleting the parent node will also recursively delete the child nodes.
Due to the limitations of SQL statements, it is impossible to write recursive statements directly, unless it is a function or stored procedure.
POSTGRE database engine provides WITH RECURSIVE to solve the above problems.
For details, please refer to official information: https://www.postgresql.org/docs/current/queries-with.html
For example, the following tree structure:
二、WITH
WITH provides a way to write auxiliary statements for use in larger queries.
These statements are usually called common table expressions (commontableexpression) or cte,
It can be thought of as defining a temporary table that exists only for one query.
Each auxiliary statement in the WITH clause can be SELECT, INSERT, UPDATE or DELETE;
The WITH clause itself is attached to the main statement, which can also be SELECT, INSERT, UPDATE, or DELETE.
For example, the following SQL statement:
with T as ( select * from template_info where parent_id=-1 ) select * from T
All the first-level nodes are queried, and the contents detected by the statement in parentheses are stored in the temporary table T, and then all are queried from T.
You can define multiple WITH clauses, separated by commas, so that you can query multiple tables, query in parallel, and then query the collection of temporary tables.
Three, RECURSIVE
The optional RECURSIVE recursive modifier has been changed from a simple syntax to a feature that can accomplish things that are impossible in standard SQL.
Using recursion, WITH queries can refer to their own output.
with RECURSIVE t as (select * from template_info where id =18 union all (select d.* from t inner join template_info d on t.id=d.parent_id) ) select * from t
The logic of the query is:
1. Calculate non-recursive items, that is, select * from template_info where id =18. This row finds out the root node and stores the result in temporary table B;
2. Calculate the recursive term, that is, select d.* from t inner join template_info d on t.id=d.parent_id, join the temporary table B and template_info to obtain C, and merge BC to obtain D;
3. Keep calculating the recursive items and merging the result sets until all C is empty, ending the iteration process;
4. Query the result set to get the final result.
Note: Strictly speaking, this process is iterative rather than recursive, but recursion is the term chosen by the SQL Standards Committee.
Steps to further disassemble:
1. Query one
select * from template_info where id =18
2. Merger
with RECURSIVE t as (select * from template_info where id =18 union (select d.* from t inner join template_info d on t.id=d.parent_id where t.id=18) ) select * from t
3. Remerge
with RECURSIVE t as (select * from template_info where id =18 union (select d.* from t inner join template_info d on t.id=d.parent_id where t.id=18) ) select * from t union ( with RECURSIVE t2 as ( (select d.* from t inner join template_info d on t.id=d.parent_id where t.id=19) ) select * from t2 )
4. Merge again, no more, end the query.
with RECURSIVE t as (select * from template_info where id =18 union (select d.* from t inner join template_info d on t.id=d.parent_id where t.id=18) ) select * from t union ( with RECURSIVE t2 as ( (select d.* from t inner join template_info d on t.id=d.parent_id where t.id=20) ) select * from t2 )
Fourth, WITH
mid-UPDATE
WITH t AS ( UPDATE products SET price = price * 1.05 RETURNING * ) SELECT * FROM t;
Five, DELETE and INSERT in WITH
This query actually products
moves from the row to products_log
. WITH
The DELETE
delete products
in the specified line from,
RETURNING
Return their content in its clauses, and then the main query reads the output and inserts it products_log
.
WITH moved_rows AS ( DELETE FROM products WHERE "date" >= '2010-10-01' AND "date" < '2010-11-01' RETURNING * ) INSERT INTO products_log SELECT * FROM moved_rows;