with查询有点像临时表,一般用在复杂查询中,需要多次使用到这个查询结果时.
with还有个用处是递归查询.oracle 11gR2开始也支持了.
PG中的DML也可以使用with语句.我们来依次看看.
db01=> with t as (
select * from t_insert
)
select count(*) from t;
count
-------
7
(1 row)
只是作为最简单的示例:)
db01=> select * from generate_series(1,5,2);
generate_series
-----------------
1
3
5
(3 rows)
db01=> with recursive t(n) as (
db01(> values(1)
db01(> union all
db01(> select n+2 from t where n<4
db01(> )select * from t;
n
---
1
3
5
(3 rows)
这里大致说一下递归的原理
也可以叫做层级查询
db01=> create table t_recursive(id int ,parent_id int ,name varchar(30));
CREATE TABLE
db01=> insert into t_recursive values(1,null,'boss');
INSERT 0 1
db01=> insert into t_recursive values(2,1,'jack'),(3,1,'joe');
INSERT 0 2
db01=> insert into t_recursive values(4,2,'emp1'),(5,2,'emp2'),(6,2,'emp3');
INSERT 0 3
db01=> insert into t_recursive values(7,3,'emp4'),(8,3,'emp5'),(9,3,'emp6');
INSERT 0 3
db01=> insert into t_recursive values(10,8,'emptest');
INSERT 0 1
db01=> select * from t_recursive;
id | parent_id | name
----+-----------+---------
1 | | boss
2 | 1 | jack
3 | 1 | joe
4 | 2 | emp1
5 | 2 | emp2
6 | 2 | emp3
7 | 3 | emp4
8 | 3 | emp5
9 | 3 | emp6
10 | 8 | emptest
(10 rows)
查找jack及其下的所有员工
db01=> with recursive t(id,parent_id,name,path) as (
select r1.*,'/'||r1.name path from t_recursive r1 where name='jack'
union all
select r.*,path||'/'||r.name from t_recursive r,t where r.parent_id = t.id
)select * from t;
id | parent_id | name | path
----+-----------+------+------------
2 | 1 | jack | /jack
4 | 2 | emp1 | /jack/emp1
5 | 2 | emp2 | /jack/emp2
6 | 2 | emp3 | /jack/emp3
(4 rows)
最外层对字段path排序,可以将结果从默认的广度优先变成深度优先
查找emptest的上上级老板(他要越级告状去)
db01=> with recursive t(id,parent_id,name,path,lvl) as (
select r1.*,'/'||r1.name path,1 lvl from t_recursive r1 where name='emptest'
union all
select r.*,path||'/'||r.name,lvl + 1 from t_recursive r,t where r.id = t.parent_id --这里要注意是往上找了
)select * from t where lvl = 3; --它自己是1级
id | parent_id | name | path | lvl
----+-----------+------+-------------------+-----
3 | 1 | joe | /emptest/emp5/joe | 3
(1 row)
日志迁移语句
db01=> create table t_recursive_hist(id int,parent_id int,name varchar(30),log_when date);
CREATE TABLE
db01=> with t as (
delete from t_recursive where id = 10
returning *)
insert into t_recursive_hist
select t.*,current_date from t;
INSERT 0 1
db01=> select from t_recursive where id = 10;
--
(0 rows)
db01=> select * from t_recursive_hist;
id | parent_id | name | log_when
----+-----------+---------+------------
10 | 8 | emptest | 2015-02-24
(1 row)
with子句中的dml语句只有带returning才能让外层的语句'可见'
递归里面不能带DML语句,当然递归外层的DML可以关联递归的输出结果.
Oracle中只有在pl/sql里才能使用returning
需要注意使用returning语句返回的结果才能被外层的查询使用
也就是说外层直接使用with内dml操作过的表是看不到结果的
db01=> with t as (
db01(> update t_recursive_hist set name='name1'
db01(> ) select * from t_recursive_hist;
id | parent_id | name | log_when
----+-----------+---------+------------
10 | 8 | emptest | 2015-02-14
(1 row)
db01=> select * from t_recursive_hist;
id | parent_id | name | log_when
----+-----------+-------+------------
10 | 8 | name1 | 2015-02-14
(1 row)
db01=> with t as (
update t_recursive_hist set name='name2' returning *
) select * from t;
id | parent_id | name | log_when
----+-----------+-------+------------
10 | 8 | name2 | 2015-02-14
(1 row)
PG中的with语句很好很强大,既可以作为一般的临时表,也可以作为递归查询,还可带上DML语句.
oracle的with只支持查询,从11gR2开始with语句也开始支持递归查询,之前的递归都是通过start with … connect by来实现.
//END