PostgreSQL WITH 子句
在 PostgreSQL 中,WITH 子句提供了一种编写辅助语句的方法,以便在更大的查询中使用。
WITH 子句有助于将复杂的大型查询分解为更简单的表单,便于阅读。
这些语句通常称为通用表表达式,也可当做一个为查询而存在的临时表。
通用表表达式:Common Table Express, CTE
WITH 子句是在多次执行子查询时特别有用,允许我们在查询中通过它的名称(可能是多次)引用它。
WITH 子句在使用前必须先定义。
//WITH 查询的基础语法如下:
WITH
name_for_summary_data AS (
SELECT Statement)
SELECT columns
FROM name_for_summary_data
WHERE conditions <=> (
SELECT column
FROM name_for_summary_data)
[ORDER BY columns]
//name_for_summary_data 是 WITH 子句的名称,
//name_for_summary_data 可以与现有的表名相同,并且具有优先级。
//可以在 WITH 中使用数据 INSERT, UPDATE 或 DELETE 语句,允许您在同一个查询中执行多个不同的操作。
WITH 递归
在 WITH 子句中 可以使用自身输出的数据。
通用表表达式 (CTE) 具有一个重要的优点,那就是能够引用其自身,从而创建递归 CTE。递归 CTE 是一个重复执行初始 CTE 以返回数据子集直到获取完整结果集的公用表表达式。
实例:
mydb=# select * from company;
id | name | age | address | salary | join_date
----+-------+-----+----------------------------------------------------+--------+------------
4 | Mark | 25 | Rich-Mond | 65000 | 2007-12-13
5 | David | 27 | Texas | 85000 | 2007-12-13
3 | Teddy | 23 | Norway | 20000 |
2 | Allen | 25 | Texas | | 2007-12-13
1 | Paul | 32 | California | 20000 | 2001-07-13
8 | Paul | 24 | Houston | 20000 |
6 | pasl | 24 | Hou | 20000 |
7 | lili | 23 | hy | 10000 |
9 | James | 44 | Norway | 5000 |
10 | James | 45 | Texas | 5000 |
(10 行记录)
//将使用 WITH 子句在上表中查询数据:
mydb=# With CTE AS
mydb-# (Select
mydb(# ID
mydb(# , NAME
mydb(# , AGE
mydb(# , ADDRESS
mydb(# , SALARY
mydb(# FROM COMPANY )
mydb-# Select * From CTE;
id | name | age | address | salary
----+-------+-----+----------------------------------------------------+--------
4 | Mark | 25 | Rich-Mond | 65000
5 | David | 27 | Texas | 85000
3 | Teddy | 23 | Norway | 20000
2 | Allen | 25 | Texas |
1 | Paul | 32 | California | 20000
8 | Paul | 24 | Houston | 20000
6 | pasl | 24 | Hou | 20000
7 | lili | 23 | hy | 10000
9 | James | 44 | Norway | 5000
10 | James | 45 | Texas | 5000
(10 行记录)
//接下来让我们使用 RECURSIVE 关键字和 WITH 子句编写一个查询,查找 SALARY(工资) 字段小于 20000 的数据并计算它们的和:
mydb=# WITH RECURSIVE t(n) AS (
mydb(# VALUES (0)
mydb(# UNION ALL
mydb(# SELECT SALARY FROM COMPANY WHERE SALARY < 20000
mydb(# )
mydb-# SELECT sum(n) FROM t;
sum
-------
20000
(1 行记录)
//下面我们建立一张和 COMPANY 表相似的 COMPANY1 表,
//注意:两个表的必须有相同的列,且列字段与类型一致
mydb=# CREATE TABLE COMPANY1(
mydb(# ID INT PRIMARY KEY NOT NULL,
mydb(# NAME TEXT NOT NULL,
mydb(# AGE INT NOT NULL,
mydb(# ADDRESS CHAR(50),
mydb(# SALARY REAL,
mydb(# JOIN_DATE DATE
mydb(# );
CREATE TABLE
mydb=# select * from company1;
id | name | age | address | salary | join_date
----+------+-----+---------+--------+-----------
(0 行记录)
//使用 DELETE 语句和 WITH 子句删除 COMPANY 表中 SALARY(工资) 字段小于10000 的数据,
//并将删除的数据插入 COMPANY1 表,实现将 COMPANY 表数据转移到 COMPANY1 表中:
mydb=# WITH moved_rows AS (
mydb(# DELETE FROM COMPANY
mydb(# WHERE
mydb(# SALARY < 10000
mydb(# RETURNING *
mydb(# )
mydb-# INSERT INTO COMPANY1 (SELECT * FROM moved_rows);
INSERT 0 2
mydb=# select * from company1;
id | name | age | address | salary | join_date
----+-------+-----+----------------------------------------------------+--------+-----------
9 | James | 44 | Norway | 5000 |
10 | James | 45 | Texas | 5000 |
(2 行记录)
mydb=# select * from company;
id | name | age | address | salary | join_date
----+-------+-----+----------------------------------------------------+--------+------------
4 | Mark | 25 | Rich-Mond | 65000 | 2007-12-13
5 | David | 27 | Texas | 85000 | 2007-12-13
3 | Teddy | 23 | Norway | 20000 |
2 | Allen | 25 | Texas | | 2007-12-13
1 | Paul | 32 | California | 20000 | 2001-07-13
8 | Paul | 24 | Houston | 20000 |
6 | pasl | 24 | Hou | 20000 |
7 | lili | 23 | hy | 10000 |
(6 行记录)
PostgreSQL HAVING 子句:筛选分组后的各组数据
HAVING 子句可以让我们筛选分组后的各组数据。
WHERE 子句与 HAVING 子句的区别:
- WHERE 子句:在所选列上设置条件,
- HAVING 子句:在由 GROUP BY 子句创建的分组上设置条件。
//下面是 HAVING 子句在 SELECT 查询中的位置:
SELECT
FROM
WHERE
GROUP BY
HAVING
ORDER BY
//HAVING 子句必须放置于 GROUP BY 子句后面,ORDER BY 子句前面
//下面是 HAVING 子句在 SELECT 语句中基础语法:
SELECT column1, column2
FROM table1, table2
WHERE [ conditions ]
GROUP BY column1, column2
HAVING [ conditions ]
ORDER BY column1, column2
实例
//删除company表中数据
mydb=# delete from company;
DELETE 6
mydb=# select *from company
mydb-# ;
id | name | age | address | salary | join_date
----+------+-----+---------+--------+-----------
(0 行记录)
//向company表中添加数据
mydb=# INSERT INTO COMPANY VALUES (1,'Paul',32,'California',20000),(2,'Allen',25,'Texas',15000),
(3,'Teddy',23,'Norway',20000),(4,'Mark',25,'Rich-Mond',65000),(5,'David',27,'South-Hall',85000),
(6,'Kim',22,'South-Hall',45000),(7,'James',24,'Houston',1000);
INSERT 0 7
mydb=# select *from company;
id | name | age | address | salary | join_date
----+-------+-----+----------------------------------------------------+--------+-----------
1 | Paul | 32 | California | 20000 |
2 | Allen | 25 | Texas | 15000 |
3 | Teddy | 23 | Norway | 20000 |
4 | Mark | 25 | Rich-Mond | 65000 |
5 | David | 27 | South-Hall | 85000 |
6 | Kim | 22 | South-Hall | 45000 |
7 | James | 24 | Houston | 1000 |
(7 行记录)
//将找出根据 NAME 字段值进行分组,并且 name(名称) 字段的计数少于 2 数据:
mydb=# SELECT NAME FROM COMPANY GROUP BY name HAVING count(name) < 2;
name
-------
James
Teddy
Kim
Mark
Allen
David
Paul
(7 行记录)
//往company表里添加几条数据:
mydb=# INSERT INTO COMPANY VALUES (8, 'Paul', 24, 'Houston', 20000.00),(9, 'James', 44, 'Norway', 5000.00),(10, 'James', 45, 'Texas', 5000.00);
INSERT 0 3
mydb=# select * from company;
id | name | age | address | salary | join_date
----+-------+-----+----------------------------------------------------+--------+-----------
1 | Paul | 32 | California | 20000 |
2 | Allen | 25 | Texas | 15000 |
3 | Teddy | 23 | Norway | 20000 |
4 | Mark | 25 | Rich-Mond | 65000 |
5 | David | 27 | South-Hall | 85000 |
6 | Kim | 22 | South-Hall | 45000 |
7 | James | 24 | Houston | 1000 |
8 | Paul | 24 | Houston | 20000 |
9 | James | 44 | Norway | 5000 |
10 | James | 45 | Texas | 5000 |
(10 行记录)
//将找出根据 NAME 字段值进行分组,并且 name(名称) 字段的计数少于 2 数据:
mydb=# SELECT NAME FROM COMPANY GROUP BY name HAVING count(name) < 2;
name
-------
Mark
Allen
David
Teddy
Kim
(5 行记录)
//将找出根据 name 字段值进行分组,并且名称的计数大于 1 数据:
mydb=# SELECT NAME FROM COMPANY GROUP BY name HAVING count(name) > 1;
name
-------
Paul
James
(2 行记录)
PostgreSQL DISTINCT 关键字:去除重复记录,只获取唯一的记录
在 PostgreSQL 中,DISTINCT 关键字与 SELECT 语句一起使用,用于去除重复记录,只获取唯一的记录。
我们平时在操作数据时,有可能出现一种情况,在一个表中有多个重复的记录,当提取这样的记录时,DISTINCT 关键字就显得特别有意义,它只获取唯一一次记录,而不是获取重复记录。
//用于去除重复记录的 DISTINCT 关键字的基本语法如下:
SELECT DISTINCT column1, column2,.....columnN
FROM table_name
WHERE [condition]
实例
mydb=# SELECT name FROM COMPANY;
name
-------
Paul
Allen
Teddy
Mark
David
Kim
James
Paul
James
James
(10 行记录)
//在 SELECT 语句中使用 DISTINCT 子句:
mydb=# SELECT DISTINCT name FROM COMPANY;
name
-------
Allen
David
James
Kim
Mark
Paul
Teddy
(7 行记录)
———