PostgreSQL教程FG014-PG简单查询:SELECT语句与基础过滤/排序
本文详细介绍PostgreSQL数据库中SELECT语句的基本用法,包括查询指定字段、过滤数据、排序结果等操作,以及这些操作的语法、使用方法和实战案例。风哥教程参考PostgreSQL官方文档Queries部分。
from oracle:www.itpux.com
本文档风哥主要介绍PostgreSQL教程014相关内容。风哥教程参考PostgreSQL官方文档Server Administration, SQL Language内容编写,适合DBA人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。
Part01-基础概念与理论知识
1.1 SELECT语句概述
SELECT语句是PostgreSQL中用于查询数据的最基本也是最常用的语句,它允许用户从一个或多个表中检索数据,并可以对结果进行过滤、排序和分组等操作。学习交流加群风哥微信: itpux-com
1.2 查询语句结构
一个完整的SELECT语句通常包含以下几个部分:
- SELECT:指定要查询的字段
- FROM:指定要查询的表
- WHERE:过滤条件
- ORDER BY:排序条件
- LIMIT/OFFSET:限制结果集大小和偏移量
Part02-基本查询操作
2.1 查询所有字段
使用SELECT *可以查询表中的所有字段。
CREATE TABLE fgedu_employees (
employee_id SERIAL PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
department VARCHAR(50) NOT NULL,
position VARCHAR(50) NOT NULL,
salary NUMERIC(10, 2) NOT NULL,
hire_date DATE NOT NULL
);
— 插入测试数据
INSERT INTO fgedu_employees (first_name, last_name, department, position, salary, hire_date) VALUES
(‘张’, ‘三’, ‘技术部’, ‘软件工程师’, 8000.00, ‘2023-01-15’),
(‘李’, ‘四’, ‘销售部’, ‘销售经理’, 12000.00, ‘2022-03-20’),
(‘王’, ‘五’, ‘技术部’, ‘高级软件工程师’, 10000.00, ‘2021-07-10’),
(‘赵’, ‘六’, ‘人事部’, ‘人事专员’, 6000.00, ‘2023-05-01’),
(‘孙’, ‘七’, ‘技术部’, ‘测试工程师’, 7000.00, ‘2022-11-01’),
(‘周’, ‘八’, ‘市场部’, ‘市场专员’, 7500.00, ‘2023-02-15’);
— 查询所有字段
SELECT * FROM fgedu_employees;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
(6 rows)
2.2 查询指定字段
可以在SELECT语句中指定要查询的字段,多个字段之间用逗号分隔。
SELECT first_name, last_name, department, salary FROM fgedu_employees;
first_name | last_name | department | salary
————+———–+————+——–
张 | 三 | 技术部 | 8000.00
李 | 四 | 销售部 | 12000.00
王 | 五 | 技术部 | 10000.00
赵 | 六 | 人事部 | 6000.00
孙 | 七 | 技术部 | 7000.00
周 | 八 | 市场部 | 7500.00
(6 rows)
2.3 使用别名
可以使用AS关键字为字段或表指定别名,使查询结果更易读。
SELECT
first_name AS “名字”,
last_name AS “姓氏”,
department AS “部门”,
salary AS “薪资”
FROM fgedu_employees;
名字 | 姓氏 | 部门 | 薪资
——+——+——–+———-
张 | 三 | 技术部 | 8000.00
李 | 四 | 销售部 | 12000.00
王 | 五 | 技术部 | 10000.00
赵 | 六 | 人事部 | 6000.00
孙 | 七 | 技术部 | 7000.00
周 | 八 | 市场部 | 7500.00
(6 rows)
— 使用表别名
SELECT
e.first_name,
e.last_name,
e.department,
e.salary
FROM fgedu_employees AS e;
first_name | last_name | department | salary
————+———–+————+——–
张 | 三 | 技术部 | 8000.00
李 | 四 | 销售部 | 12000.00
王 | 五 | 技术部 | 10000.00
赵 | 六 | 人事部 | 6000.00
孙 | 七 | 技术部 | 7000.00
周 | 八 | 市场部 | 7500.00
(6 rows)
2.4 去除重复记录
可以使用DISTINCT关键字去除查询结果中的重复记录。
SELECT department FROM fgedu_employees;
department
————
技术部
销售部
技术部
人事部
技术部
市场部
(6 rows)
— 查询所有部门(去除重复)
SELECT DISTINCT department FROM fgedu_employees;
department
————
技术部
销售部
人事部
市场部
(4 rows)
— 基于多个字段去除重复
SELECT DISTINCT department, position FROM fgedu_employees;
department | position
————+—————-
技术部 | 软件工程师
销售部 | 销售经理
技术部 | 高级软件工程师
人事部 | 人事专员
技术部 | 测试工程师
市场部 | 市场专员
(6 rows)
Part03-数据过滤
3.1 WHERE子句基础
WHERE子句用于过滤查询结果,只返回符合条件的记录。
SELECT * FROM fgedu_employees WHERE department = ‘技术部’;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
(3 rows)
3.2 比较运算符
PostgreSQL支持多种比较运算符,用于比较值的大小或相等性。
SELECT * FROM fgedu_employees WHERE position = ‘软件工程师’;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+————+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
(1 row)
— 不等于(<> 或 !=)
SELECT * FROM fgedu_employees WHERE department <> ‘技术部’;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+————+——–+————
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
(3 rows)
— 大于(>)
SELECT * FROM fgedu_employees WHERE salary > 9000;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
(2 rows)
— 小于(<)
SELECT * FROM fgedu_employees WHERE salary < 8000;
employee_id | first_name | last_name | department | position | salary | hire_date
-------------+------------+-----------+------------+------------+--------+------------
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
(3 rows)
-- 大于等于(>=)
SELECT * FROM fgedu_employees WHERE hire_date >= ‘2023-01-01’;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+————+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
(3 rows)
— 小于等于(<=) SELECT * FROM fgedu_employees WHERE hire_date <= '2022-12-31'; employee_id | first_name | last_name | department | position | salary | hire_date -------------+------------+-----------+------------+----------------+--------+------------ 2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20 3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10 5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01 (3 rows)
3.3 逻辑运算符
可以使用逻辑运算符(AND、OR、NOT)组合多个条件。
SELECT * FROM fgedu_employees WHERE department = ‘技术部’ AND salary > 8000;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
(1 row)
— OR运算符(满足任一条件)
SELECT * FROM fgedu_employees WHERE department = ‘技术部’ OR salary > 10000;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
(4 rows)
— NOT运算符(不满足条件)
SELECT * FROM fgedu_employees WHERE NOT department = ‘技术部’;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+————+——–+————
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
(3 rows)
— 组合逻辑运算符
SELECT * FROM fgedu_employees WHERE (department = ‘技术部’ OR department = ‘销售部’) AND salary >= 8000;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
(3 rows)
3.4 IN和BETWEEN运算符
IN运算符用于检查值是否在指定的列表中,BETWEEN运算符用于检查值是否在指定的范围内。
SELECT * FROM fgedu_employees WHERE department IN (‘技术部’, ‘销售部’);
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
(4 rows)
— NOT IN运算符
SELECT * FROM fgedu_employees WHERE department NOT IN (‘技术部’, ‘销售部’);
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+————+——–+————
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
(2 rows)
— BETWEEN运算符(包括边界值)
SELECT * FROM fgedu_employees WHERE salary BETWEEN 7000 AND 10000;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
(4 rows)
— NOT BETWEEN运算符
SELECT * FROM fgedu_employees WHERE salary NOT BETWEEN 7000 AND 10000;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+————+——–+————
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
(2 rows)
— BETWEEN用于日期
SELECT * FROM fgedu_employees WHERE hire_date BETWEEN ‘2022-01-01’ AND ‘2022-12-31’;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
(2 rows)
3.5 LIKE和ILIKE运算符
LIKE运算符用于模糊匹配字符串,ILIKE运算符用于不区分大小写的模糊匹配。
SELECT * FROM fgedu_employees WHERE first_name LIKE ‘张%’;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+————+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
(1 row)
— ILIKE运算符(不区分大小写)
SELECT * FROM fgedu_employees WHERE position ILIKE ‘%工程师%’;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
(3 rows)
— 使用通配符%(匹配任意字符)
SELECT * FROM fgedu_employees WHERE position LIKE ‘%经理%’;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+————+——–+————
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
(1 row)
— 使用通配符_(匹配单个字符)
SELECT * FROM fgedu_employees WHERE first_name LIKE ‘张_’;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+————+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
(1 row)
— 转义字符\(匹配特殊字符)
SELECT * FROM fgedu_employees WHERE position LIKE ‘%\%%’ ESCAPE ‘\’;
— 这个查询会匹配包含%字符的职位名称
Part04-数据排序
4.1 ORDER BY子句
ORDER BY子句用于对查询结果进行排序。
SELECT * FROM fgedu_employees ORDER BY salary;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
(6 rows)
4.2 升序和降序
可以使用ASC关键字指定升序排序(默认),或使用DESC关键字指定降序排序。
SELECT * FROM fgedu_employees ORDER BY salary ASC;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
(6 rows)
— 降序排序
SELECT * FROM fgedu_employees ORDER BY salary DESC;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
(6 rows)
4.3 多字段排序
可以按多个字段进行排序,排序顺序依次生效。
SELECT * FROM fgedu_employees ORDER BY department ASC, salary DESC;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
(6 rows)
— 按入职日期降序,薪资升序排序
SELECT * FROM fgedu_employees ORDER BY hire_date DESC, salary ASC;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+————+——–+————
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
(6 rows)
4.4 NULL值排序
默认情况下,NULL值在升序排序中排在最后,在降序排序中排在最前。可以使用NULLS FIRST或NULLS LAST关键字改变NULL值的排序位置。
CREATE TABLE fgedu_test (
id SERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL,
score INTEGER
);
— 插入测试数据
INSERT INTO fgedu_test (name, score) VALUES
(‘风哥1号’, 85),
(‘风哥2号’, NULL),
(‘王五’, 92),
(‘赵六’, 78),
(‘孙七’, NULL);
— 默认排序(NULL值在最后)
SELECT * FROM fgedu_test ORDER BY score ASC;
id | name | score
—-+——+——-
4 | 赵六 | 78
1 | 风哥1号 | 85
3 | 王五 | 92
2 | 风哥2号 | NULL
5 | 孙七 | NULL
(5 rows)
— NULLS FIRST(NULL值排在最前)
SELECT * FROM fgedu_test ORDER BY score ASC NULLS FIRST;
id | name | score
—-+——+——-
2 | 风哥2号 | NULL
5 | 孙七 | NULL
4 | 赵六 | 78
1 | 风哥1号 | 85
3 | 王五 | 92
(5 rows)
— NULLS LAST(NULL值排在最后)
SELECT * FROM fgedu_test ORDER BY score DESC NULLS LAST;
id | name | score
—-+——+——-
3 | 王五 | 92
1 | 风哥1号 | 85
4 | 赵六 | 78
2 | 风哥2号 | NULL
5 | 孙七 | NULL
(5 rows)
Part05-限制结果集
5.1 LIMIT子句
LIMIT子句用于限制查询结果的数量。
SELECT * FROM fgedu_employees ORDER BY salary DESC LIMIT 3;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
(3 rows)
— 查询技术部的前2名员工
SELECT * FROM fgedu_employees WHERE department = ‘技术部’ LIMIT 2;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
(2 rows)
5.2 OFFSET子句
OFFSET子句用于跳过指定数量的记录。
SELECT * FROM fgedu_employees ORDER BY salary DESC OFFSET 2;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+————+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
(4 rows)
5.3 LIMIT和OFFSET结合使用
LIMIT和OFFSET可以结合使用,实现分页查询。
SELECT * FROM fgedu_employees ORDER BY salary DESC LIMIT 2 OFFSET 0;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+—————-+——–+————
2 | 李 | 四 | 销售部 | 销售经理 | 12000.00 | 2022-03-20
3 | 王 | 五 | 技术部 | 高级软件工程师 | 10000.00 | 2021-07-10
(2 rows)
— 第2页,每页2条记录
SELECT * FROM fgedu_employees ORDER BY salary DESC LIMIT 2 OFFSET 2;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+————+——–+————
1 | 张 | 三 | 技术部 | 软件工程师 | 8000.00 | 2023-01-15
6 | 周 | 八 | 市场部 | 市场专员 | 7500.00 | 2023-02-15
(2 rows)
— 第3页,每页2条记录
SELECT * FROM fgedu_employees ORDER BY salary DESC LIMIT 2 OFFSET 4;
employee_id | first_name | last_name | department | position | salary | hire_date
————-+————+———–+————+————+——–+————
5 | 孙 | 七 | 技术部 | 测试工程师 | 7000.00 | 2022-11-01
4 | 赵 | 六 | 人事部 | 人事专员 | 6000.00 | 2023-05-01
(2 rows)
Part06-生产案例与实战讲解
下面是一个综合实战案例,展示如何在实际项目中使用SELECT语句进行数据查询和分析。
CREATE TABLE fgedu_products (
product_id SERIAL PRIMARY KEY,
product_name VARCHAR(100) NOT NULL,
category VARCHAR(50) NOT NULL,
price NUMERIC(10, 2) NOT NULL,
stock_quantity INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
— 创建订单表
CREATE TABLE fgedu_orders (
order_id SERIAL PRIMARY KEY,
customer_id INTEGER NOT NULL,
order_date TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
total_amount NUMERIC(12, 2) NOT NULL,
order_status VARCHAR(20) DEFAULT ‘pending’
);
— 创建订单详情表
CREATE TABLE fgedu_order_items (
order_item_id SERIAL PRIMARY KEY,
order_id INTEGER NOT NULL REFERENCES fgedu_orders(order_id),
product_id INTEGER NOT NULL REFERENCES fgedu_products(product_id),
quantity INTEGER NOT NULL CHECK (quantity > 0),
unit_price NUMERIC(10, 2) NOT NULL,
subtotal NUMERIC(12, 2) NOT NULL
);
— 插入产品数据
INSERT INTO fgedu_products (product_name, category, price, stock_quantity) VALUES
(‘PostgreSQL数据库实战’, ‘计算机图书’, 89.90, 100),
(‘Python编程基础’, ‘计算机图书’, 59.90, 200),
(‘Java核心技术’, ‘计算机图书’, 139.90, 150),
(‘数据结构与算法’, ‘计算机图书’, 79.90, 80),
(‘机器学习实战’, ‘人工智能’, 99.90, 60),
(‘深度学习入门’, ‘人工智能’, 129.90, 50),
(‘大数据处理’, ‘大数据’, 119.90, 70),
(‘云计算导论’, ‘云计算’, 109.90, 90);
— 插入订单数据
INSERT INTO fgedu_orders (customer_id, total_amount, order_status) VALUES
(1, 239.70, ‘shipped’),
(2, 159.80, ‘pending’),
(3, 269.80, ‘delivered’),
(4, 109.90, ‘shipped’),
(5, 359.60, ‘pending’);
— 插入订单详情数据
INSERT INTO fgedu_order_items (order_id, product_id, quantity, unit_price, subtotal) VALUES
(1, 1, 1, 89.90, 89.90),
(1, 4, 2, 79.90, 159.80),
(2, 2, 2, 59.90, 119.80),
(2, 5, 1, 99.90, 99.90),
(3, 3, 2, 139.90, 279.80),
(4, 7, 1, 119.90, 119.90),
(5, 6, 2, 129.90, 259.80),
(5, 8, 1, 109.90, 109.90);
— 1. 查询所有产品信息,按价格降序排序
SELECT product_id, product_name, category, price, stock_quantity FROM fgedu_products ORDER BY price DESC;
product_id | product_name | category | price | stock_quantity
————+———————-+————+——–+—————-
3 | Java核心技术 | 计算机图书 | 139.90 | 150
6 | 深度学习入门 | 人工智能 | 129.90 | 50
7 | 大数据处理 | 大数据 | 119.90 | 70
8 | 云计算导论 | 云计算 | 109.90 | 90
5 | 机器学习实战 | 人工智能 | 99.90 | 60
1 | PostgreSQL数据库实战 | 计算机图书 | 89.90 | 100
4 | 数据结构与算法 | 计算机图书 | 79.90 | 80
2 | Python编程基础 | 计算机图书 | 59.90 | 200
(8 rows)
— 2. 查询价格在100元以上的产品,按类别分组
SELECT category, COUNT(*) AS product_count FROM fgedu_products WHERE price > 100 GROUP BY category;
category | product_count
————+—————
计算机图书 | 1
人工智能 | 1
大数据 | 1
云计算 | 1
(4 rows)
— 3. 查询已发货的订单,按订单日期降序排序
SELECT order_id, customer_id, order_date, total_amount FROM fgedu_orders WHERE order_status = ‘shipped’ ORDER BY order_date DESC;
order_id | customer_id | order_date | total_amount
———-+————-+——————————-+————–
4 | 4 | 2026-04-02 19:30:00.123456+08 | 109.90
1 | 1 | 2026-04-02 19:30:00.123456+08 | 239.70
(2 rows)
— 4. 查询每个订单的订单详情
SELECT
o.order_id, o.customer_id, o.order_date, o.total_amount, o.order_status,
p.product_id, p.product_name, p.category, i.quantity, i.unit_price, i.subtotal
FROM fgedu_orders o
JOIN fgedu_order_items i ON o.order_id = i.order_id
JOIN fgedu_products p ON i.product_id = p.product_id
ORDER BY o.order_id, i.order_item_id;
order_id | customer_id | order_date | total_amount | order_status | product_id | product_name | category | quantity | unit_price | subtotal
———-+————-+——————————-+————–+————–+————+———————-+————+———-+————+———-
1 | 1 | 2026-04-02 19:30:00.123456+08 | 239.70 | shipped | 1 | PostgreSQL数据库实战 | 计算机图书 | 1 | 89.9 | 89.9
1 | 1 | 2026-04-02 19:30:00.123456+08 | 239.70 | shipped | 4 | 数据结构与算法 | 计算机图书 | 2 | 79.9 | 159.8
2 | 2 | 2026-04-02 19:30:00.123456+08 | 159.80 | pending | 2 | Python编程基础 | 计算机图书 | 2 | 59.9 | 119.8
2 | 2 | 2026-04-02 19:30:00.123456+08 | 159.80 | pending | 5 | 机器学习实战 | 人工智能 | 1 | 99.9 | 99.9
3 | 3 | 2026-04-02 19:30:00.123456+08 | 269.80 | delivered | 3 | Java核心技术 | 计算机图书 | 2 | 139.9 | 279.8
4 | 4 | 2026-04-02 19:30:00.123456+08 | 109.90 | shipped | 7 | 大数据处理 | 大数据 | 1 | 119.9 | 119.9
5 | 5 | 2026-04-02 19:30:00.123456+08 | 359.60 | pending | 6 | 深度学习入门 | 人工智能 | 2 | 129.9 | 259.8
5 | 5 | 2026-04-02 19:30:00.123456+08 | 359.60 | pending | 8 | 云计算导论 | 云计算 | 1 | 109.9 | 109.9
(8 rows)
— 5. 查询最受欢迎的产品(按销售数量排序)
SELECT
p.product_id, p.product_name, p.category, SUM(i.quantity) AS total_quantity
FROM fgedu_products p
JOIN fgedu_order_items i ON p.product_id = i.product_id
GROUP BY p.product_id, p.product_name, p.category
ORDER BY total_quantity DESC LIMIT 3;
product_id | product_name | category | total_quantity
————+———————-+————+—————-
2 | Python编程基础 | 计算机图书 | 2
3 | Java核心技术 | 计算机图书 | 2
4 | 数据结构与算法 | 计算机图书 | 2
6 | 深度学习入门 | 人工智能 | 2
(4 rows)
— 6. 查询每个类别的平均价格和最高价格
SELECT
category,
AVG(price) AS average_price,
MAX(price) AS max_price
FROM fgedu_products
GROUP BY category
ORDER BY average_price DESC;
category | average_price | max_price
————+———————–+———–
人工智能 | 114.9000000000000000 | 129.90
计算机图书 | 92.3500000000000000 | 139.90
云计算 | 109.9000000000000000 | 109.90
大数据 | 119.9000000000000000 | 119.90
(4 rows)
Part07-风哥经验总结与分享
1. SELECT语句使用建议:
- 尽量只查询需要的字段,避免使用SELECT *
- 为查询条件中的字段创建索引,提高查询效率
- 使用别名使查询结果更易读
- 在处理大量数据时,使用LIMIT限制结果集大小
2. 数据过滤建议:
- 使用适当的比较运算符和逻辑运算符组合条件
- 对于范围查询,使用BETWEEN运算符比使用多个比较运算符更高效
- 对于列表查询,使用IN运算符比使用多个OR运算符更高效
- 在使用LIKE进行模糊匹配时,避免在模式开头使用%,否则会导致索引失效
3. 数据排序建议:
- 为排序字段创建索引,提高排序效率
- 避免对大结果集进行排序,否则会消耗大量内存
- 在需要分页查询时,使用LIMIT和OFFSET结合使用
- 注意NULL值的排序位置,根据实际需求使用NULLS FIRST或NULLS LAST
4. 性能优化建议:
- 使用EXPLAIN命令分析查询执行计划
- 为频繁查询的字段创建索引
- 避免在WHERE子句中使用函数或表达式
- 使用JOIN代替子查询,提高查询效率
- 在处理大量数据时,考虑使用分批查询
5. 数据安全建议:
- 使用参数化查询避免SQL注入攻击
- 限制用户的查询权限,只授予必要的权限
- 对敏感数据进行加密或脱敏处理
- 定期审计查询日志,监控异常查询
更多视频教程www.fgedu.net.cn
更多学习教程公众号风哥教程itpux_com
from PostgreSQL:www.itpux.com
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
