外观
PostgreSQL SQL基础
SQL(Structured Query Language)是用于管理关系数据库的标准语言。PostgreSQL完全支持SQL标准,并提供了许多扩展功能。本文将介绍PostgreSQL SQL的基础知识。
SQL概述
SQL类型
SQL可以分为以下几类:
- 数据查询语言(DQL):用于查询数据,主要是SELECT语句
- 数据操作语言(DML):用于修改数据,包括INSERT、UPDATE、DELETE语句
- 数据定义语言(DDL):用于定义数据库对象,包括CREATE、ALTER、DROP语句
- 数据控制语言(DCL):用于控制数据访问权限,包括GRANT、REVOKE语句
- 事务控制语言(TCL):用于控制事务,包括BEGIN、COMMIT、ROLLBACK语句
PostgreSQL SQL扩展
PostgreSQL提供了许多SQL标准之外的扩展功能:
- 数组类型支持
- JSON/JSONB支持
- 范围类型支持
- 高级索引类型
- 窗口函数
- 递归查询
- 通用表表达式(CTE)
基本查询(SELECT)
简单查询
基本SELECT语句用于从表中检索数据:
sql
-- 检索表中的所有列
SELECT * FROM users;
-- 检索特定列
SELECT username, email FROM users;
-- 检索并别名列
SELECT username AS user_name, email FROM users;WHERE子句
WHERE子句用于过滤数据:
sql
-- 等值条件
SELECT * FROM users WHERE id = 1;
-- 比较条件
SELECT * FROM products WHERE price > 100;
SELECT * FROM products WHERE price BETWEEN 50 AND 100;
SELECT * FROM products WHERE price IN (50, 100, 150);
-- 字符串匹配
SELECT * FROM users WHERE username LIKE 'a%'; -- 以a开头的用户名
SELECT * FROM users WHERE username LIKE '%a%'; -- 包含a的用户名
SELECT * FROM users WHERE username LIKE 'a__'; -- 以a开头,长度为3的用户名
-- 空值检查
SELECT * FROM users WHERE email IS NULL;
SELECT * FROM users WHERE email IS NOT NULL;
-- 逻辑运算符
SELECT * FROM products WHERE price > 100 AND category_id = 1;
SELECT * FROM products WHERE price < 50 OR category_id = 2;
SELECT * FROM products WHERE NOT (price > 100);ORDER BY子句
ORDER BY子句用于排序结果:
sql
-- 升序排序(默认)
SELECT * FROM products ORDER BY price;
-- 降序排序
SELECT * FROM products ORDER BY price DESC;
-- 多列排序
SELECT * FROM products ORDER BY category_id, price DESC;
-- 使用列别名排序
SELECT username AS user_name FROM users ORDER BY user_name;LIMIT和OFFSET子句
LIMIT和OFFSET子句用于分页查询:
sql
-- 限制结果数量
SELECT * FROM products ORDER BY price LIMIT 10;
-- 分页查询(每页10条,第2页)
SELECT * FROM products ORDER BY price LIMIT 10 OFFSET 10;
-- PostgreSQL扩展:FETCH子句
SELECT * FROM products ORDER BY price FETCH FIRST 10 ROWS ONLY;
SELECT * FROM products ORDER BY price OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;DISTINCT子句
DISTINCT子句用于去除重复行:
sql
-- 去除重复值
SELECT DISTINCT category_id FROM products;
-- 多列去重
SELECT DISTINCT category_id, price FROM products;数据操作(DML)
插入数据(INSERT)
INSERT语句用于向表中插入数据:
sql
-- 插入单行数据
INSERT INTO users (username, email, password_hash) VALUES ('john', 'john@example.com', 'hashed_password');
-- 插入多行数据
INSERT INTO users (username, email, password_hash) VALUES
('jane', 'jane@example.com', 'hashed_password_1'),
('bob', 'bob@example.com', 'hashed_password_2');
-- 插入查询结果
INSERT INTO users_archive SELECT * FROM users WHERE created_at < '2023-01-01';
-- 使用DEFAULT关键字
INSERT INTO users (username, email, created_at) VALUES ('alice', 'alice@example.com', DEFAULT);更新数据(UPDATE)
UPDATE语句用于更新表中的数据:
sql
-- 更新单行数据
UPDATE users SET email = 'new_email@example.com' WHERE id = 1;
-- 更新多行数据
UPDATE products SET price = price * 1.1 WHERE category_id = 1;
-- 更新多列数据
UPDATE users SET username = 'new_username', email = 'new_email@example.com' WHERE id = 1;
-- 使用RETURNING子句返回更新的数据
UPDATE products SET price = price * 1.1 WHERE category_id = 1 RETURNING id, price;删除数据(DELETE)
DELETE语句用于删除表中的数据:
sql
-- 删除单行数据
DELETE FROM users WHERE id = 1;
-- 删除多行数据
DELETE FROM users WHERE created_at < '2023-01-01';
-- 删除所有数据(谨慎使用)
DELETE FROM users;
-- 使用RETURNING子句返回删除的数据
DELETE FROM products WHERE category_id = 5 RETURNING id, name;数据定义(DDL)
创建表(CREATE TABLE)
CREATE TABLE语句用于创建新表:
sql
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
description TEXT,
price DECIMAL(10, 2) NOT NULL,
category_id INTEGER REFERENCES categories(id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);修改表(ALTER TABLE)
ALTER TABLE语句用于修改现有表的结构:
sql
-- 添加列
ALTER TABLE products ADD COLUMN active BOOLEAN DEFAULT TRUE;
-- 修改列
ALTER TABLE products ALTER COLUMN price TYPE DECIMAL(12, 2);
ALTER TABLE products ALTER COLUMN description SET NOT NULL;
-- 删除列
ALTER TABLE products DROP COLUMN active;
-- 添加约束
ALTER TABLE products ADD CONSTRAINT products_name_unique UNIQUE (name);
-- 删除约束
ALTER TABLE products DROP CONSTRAINT products_name_unique;删除表(DROP TABLE)
DROP TABLE语句用于删除表:
sql
-- 删除表
DROP TABLE IF EXISTS products;
-- 级联删除(删除依赖对象)
DROP TABLE products CASCADE;表连接(JOIN)
表连接用于从多个表中检索数据:
INNER JOIN
返回两个表中匹配的行:
sql
SELECT users.username, orders.order_number, orders.total_amount
FROM users
INNER JOIN orders ON users.id = orders.user_id;LEFT JOIN
返回左表中的所有行,以及右表中匹配的行:
sql
SELECT users.username, orders.order_number
FROM users
LEFT JOIN orders ON users.id = orders.user_id;RIGHT JOIN
返回右表中的所有行,以及左表中匹配的行:
sql
SELECT users.username, orders.order_number
FROM users
RIGHT JOIN orders ON users.id = orders.user_id;FULL JOIN
返回两个表中的所有行,匹配的行合并,不匹配的行用NULL填充:
sql
SELECT users.username, orders.order_number
FROM users
FULL JOIN orders ON users.id = orders.user_id;CROSS JOIN
返回两个表的笛卡尔积:
sql
SELECT users.username, products.name
FROM users
CROSS JOIN products;自连接
表与自身连接:
sql
SELECT e1.name AS employee, e2.name AS manager
FROM employees e1
LEFT JOIN employees e2 ON e1.manager_id = e2.id;聚合函数
聚合函数用于对数据进行汇总计算:
常用聚合函数
sql
-- COUNT:计算行数
SELECT COUNT(*) FROM users;
SELECT COUNT(DISTINCT category_id) FROM products;
-- SUM:计算总和
SELECT SUM(price) FROM products;
SELECT SUM(price) FROM products WHERE category_id = 1;
-- AVG:计算平均值
SELECT AVG(price) FROM products;
-- MAX:计算最大值
SELECT MAX(price) FROM products;
-- MIN:计算最小值
SELECT MIN(price) FROM products;
-- GROUP_CONCAT:连接字符串(PostgreSQL中使用STRING_AGG)
SELECT category_id, STRING_AGG(name, ', ') FROM products GROUP BY category_id;GROUP BY子句
GROUP BY子句用于分组数据:
sql
SELECT category_id, COUNT(*) AS product_count, AVG(price) AS avg_price
FROM products
GROUP BY category_id;
SELECT category_id, active, COUNT(*) AS product_count
FROM products
GROUP BY category_id, active;HAVING子句
HAVING子句用于过滤分组后的结果:
sql
SELECT category_id, COUNT(*) AS product_count
FROM products
GROUP BY category_id
HAVING COUNT(*) > 10;
SELECT category_id, AVG(price) AS avg_price
FROM products
GROUP BY category_id
HAVING AVG(price) > 100;子查询
子查询是嵌套在其他SQL语句中的查询:
WHERE子句中的子查询
sql
-- 单行子查询
SELECT * FROM products WHERE price > (SELECT AVG(price) FROM products);
-- 多行子查询
SELECT * FROM products WHERE category_id IN (SELECT id FROM categories WHERE name IN ('Electronics', 'Clothing'));
-- EXISTS子查询
SELECT * FROM users WHERE EXISTS (SELECT 1 FROM orders WHERE orders.user_id = users.id);FROM子句中的子查询
sql
SELECT p.category_id, p.avg_price
FROM (
SELECT category_id, AVG(price) AS avg_price
FROM products
GROUP BY category_id
) AS p
WHERE p.avg_price > 100;SELECT子句中的子查询
sql
SELECT
id,
name,
(SELECT COUNT(*) FROM orders WHERE orders.product_id = products.id) AS order_count
FROM products;事务控制
事务是一组原子性的SQL操作,要么全部执行成功,要么全部失败:
sql
-- 开始事务
BEGIN;
-- 执行SQL语句
INSERT INTO orders (user_id, total_amount) VALUES (1, 100);
UPDATE inventory SET quantity = quantity - 1 WHERE product_id = 1;
-- 提交事务
COMMIT;
-- 或者回滚事务
-- ROLLBACK;常用PostgreSQL扩展
LIMIT和OFFSET
sql
SELECT * FROM products ORDER BY price LIMIT 10 OFFSET 5;RETURNING子句
sql
INSERT INTO users (username, email) VALUES ('new_user', 'new_user@example.com') RETURNING id, created_at;
UPDATE products SET price = price * 1.1 WHERE id = 1 RETURNING id, price;
DELETE FROM users WHERE id = 1 RETURNING *;字符串函数
sql
-- 字符串连接
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users;
SELECT first_name || ' ' || last_name AS full_name FROM users;
-- 字符串长度
SELECT LENGTH(username) FROM users;
-- 大小写转换
SELECT UPPER(username) FROM users;
SELECT LOWER(username) FROM users;
-- 字符串截取
SELECT SUBSTRING(email FROM 1 FOR 5) FROM users;
SELECT LEFT(email, 5) FROM users;
SELECT RIGHT(email, 10) FROM users;日期时间函数
sql
-- 当前日期时间
SELECT NOW();
SELECT CURRENT_TIMESTAMP;
SELECT CURRENT_DATE;
SELECT CURRENT_TIME;
-- 日期时间计算
SELECT NOW() + INTERVAL '1 day' AS tomorrow;
SELECT NOW() - INTERVAL '1 hour' AS one_hour_ago;
-- 日期时间提取
SELECT EXTRACT(YEAR FROM created_at) AS year FROM users;
SELECT EXTRACT(MONTH FROM created_at) AS month FROM users;
SELECT EXTRACT(DAY FROM created_at) AS day FROM users;
-- 日期格式化
SELECT TO_CHAR(created_at, 'YYYY-MM-DD HH24:MI:SS') AS formatted_date FROM users;最佳实践
使用参数化查询
防止SQL注入
限制SELECT *的使用
只选择需要的列,减少网络传输和CPU开销
使用合适的数据类型
提高存储效率和查询性能
为频繁查询的列创建索引
提高查询速度
使用事务处理
确保数据完整性,遵循ACID特性
编写清晰的SQL语句
使用适当的缩进和注释,提高可维护性
避免在WHERE子句中使用函数
影响索引使用,降低查询性能
使用EXPLAIN分析查询计划
优化查询性能,识别瓶颈
常见问题(FAQ)
如何防止SQL注入?
- 使用参数化查询
- 避免直接拼接SQL语句
- 对用户输入进行验证和转义
SELECT *和SELECT column1, column2有什么区别?
- SELECT *返回所有列,可能包含不需要的数据
- SELECT column1, column2只返回指定列,减少网络传输和CPU开销
- 推荐使用SELECT column1, column2
什么是事务?
- 事务是一组原子性的SQL操作,要么全部执行成功,要么全部失败
- 事务具有ACID特性:原子性、一致性、隔离性、持久性
INNER JOIN和LEFT JOIN有什么区别?
- INNER JOIN只返回两个表中匹配的行
- LEFT JOIN返回左表中的所有行,以及右表中匹配的行
什么时候使用GROUP BY?
- 当需要对数据进行分组并计算聚合函数时
- GROUP BY后面的列必须出现在SELECT列表中(除非使用聚合函数)
总结
本文介绍了PostgreSQL SQL的基础知识,包括基本查询、数据操作、数据定义、表连接、聚合函数、子查询和事务控制等内容。掌握这些基础知识是使用PostgreSQL进行数据库开发的基础。
要深入学习PostgreSQL SQL,建议继续学习高级SQL特性,如窗口函数、递归查询、通用表表达式等。
