第一章练习答案
本页包含第一章所有练习的答案和详细解释。
01-setup
练习 1:安装与连接
答案:
安装 PostgreSQL(macOS):
bash
brew install postgresql@16
brew services start postgresql@16
psql --version连接:
bash
psql -U postgres练习 2:创建数据库
答案:
sql
-- 创建数据库
CREATE DATABASE practice;
-- 创建用户
CREATE USER myuser WITH PASSWORD 'mypassword';
-- 授予权限
GRANT ALL PRIVILEGES ON DATABASE practice TO myuser;
-- 连接到新数据库
\c practice
-- PostgreSQL 15+ 需要额外授予 schema 权限
GRANT ALL ON SCHEMA public TO myuser;练习 3:创建商品表
答案:
sql
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10, 2),
stock INT,
category VARCHAR(50)
);练习 4:插入数据
答案:
sql
INSERT INTO products (name, price, stock, category) VALUES
('iPhone 15', 999.99, 50, 'Electronics'),
('MacBook Pro', 2499.99, 20, 'Electronics'),
('Desk Chair', 299.99, 100, 'Furniture'),
('Coffee Maker', 89.99, 30, 'Appliances'),
('Notebook', 5.99, 500, 'Stationery'),
('Wireless Mouse', 29.99, 150, 'Electronics');练习 5:查看数据
答案:
sql
SELECT * FROM products;输出:
text
id | name | price | stock | category
----+---------------+---------+-------+-------------
1 | iPhone 15 | 999.99 | 50 | Electronics
2 | MacBook Pro | 2499.99 | 20 | Electronics
3 | Desk Chair | 299.99 | 100 | Furniture
4 | Coffee Maker | 89.99 | 30 | Appliances
5 | Notebook | 5.99 | 500 | Stationery
6 | Wireless Mouse| 29.99 | 150 | Electronics02-select
练习 1:选择特定列
答案:
sql
SELECT name, email FROM users;输出:
text
name | email
---------+---------------------
Alice | alice@example.com
Bob | bob@example.com
Charlie | charlie@example.com
Diana | diana@example.com
Eve | eve@example.com练习 2:使用别名
答案:
sql
SELECT name AS full_name, age AS years_old FROM users;输出:
text
full_name | years_old
-----------+-----------
Alice | 30
Bob | 25
Charlie | 35
Diana | 28
Eve |练习 3:字符串拼接
答案:
PostgreSQL:
sql
SELECT name || ': ' || email AS contact_info FROM users;MySQL:
sql
SELECT CONCAT(name, ': ', email) AS contact_info FROM users;输出:
text
contact_info
--------------------------------
Alice: alice@example.com
Bob: bob@example.com
Charlie: charlie@example.com
Diana: diana@example.com
Eve: eve@example.com练习 4:年龄计算
答案:
sql
SELECT name, age, age + 5 AS age_in_5_years FROM users;输出:
text
name | age | age_in_5_years
---------+-----+----------------
Alice | 30 | 35
Bob | 25 | 30
Charlie | 35 | 40
Diana | 28 | 33
Eve | |注意:Eve 的年龄是 NULL,NULL + 5 仍然是 NULL。
练习 5:函数应用
答案:
sql
SELECT name, UPPER(name) AS name_upper, LENGTH(name) AS name_length FROM users;输出:
text
name | name_upper | name_length
---------+------------+-------------
Alice | ALICE | 5
Bob | BOB | 3
Charlie | CHARLIE | 7
Diana | DIANA | 5
Eve | EVE | 3练习 6:常量列
答案:
sql
SELECT name, email, 'China' AS country FROM users;输出:
text
name | email | country
---------+---------------------+---------
Alice | alice@example.com | China
Bob | bob@example.com | China
Charlie | charlie@example.com | China
Diana | diana@example.com | China
Eve | eve@example.com | China练习 7:当前时间
答案:
sql
SELECT NOW() AS current_time, CURRENT_DATE AS today;输出(示例):
text
current_time | today
-------------------------+------------
2026-09-20 15:30:45.123 | 2026-09-2003-where
练习 1:简单过滤
答案:
sql
SELECT name, age FROM users WHERE age >= 30;输出:
text
name | age
---------+-----
Alice | 30
Charlie | 35练习 2:范围查询
答案:
sql
SELECT name, age FROM users WHERE age BETWEEN 25 AND 30;或:
sql
SELECT name, age FROM users WHERE age >= 25 AND age <= 30;输出:
text
name | age
-------+-----
Alice | 30
Bob | 25
Diana | 28练习 3:逻辑组合
答案:
sql
SELECT name, age FROM users WHERE age < 26 OR age > 32;输出:
text
name | age
---------+-----
Bob | 25
Charlie | 35练习 4:NULL 处理
答案:
查询年龄为 NULL 的用户:
sql
SELECT name, age FROM users WHERE age IS NULL;输出:
text
name | age
------+-----
Eve |查询年龄不为 NULL 的用户:
sql
SELECT name, age FROM users WHERE age IS NOT NULL;输出:
text
name | age
---------+-----
Alice | 30
Bob | 25
Charlie | 35
Diana | 28练习 5:IN 操作
答案:
sql
SELECT name FROM users WHERE name IN ('Alice', 'Bob', 'Diana');输出:
text
name
-------
Alice
Bob
Diana练习 6:模式匹配
答案:
sql
SELECT name FROM users WHERE name LIKE 'C%';输出:
text
name
---------
Charlie练习 7:复杂条件
答案:
PostgreSQL:
sql
SELECT name, age
FROM users
WHERE age BETWEEN 25 AND 35
AND LOWER(name) LIKE '%a%';或使用 ILIKE(PostgreSQL):
sql
SELECT name, age
FROM users
WHERE age BETWEEN 25 AND 35
AND name ILIKE '%a%';输出:
text
name | age
-------+-----
Alice | 30
Diana | 28练习 8:边界测试
答案:
sql
SELECT name, age
FROM users
WHERE age IS NOT NULL
AND (age < 25 OR age > 30);或使用 NOT BETWEEN:
sql
SELECT name, age
FROM users
WHERE age NOT BETWEEN 25 AND 30;输出:
text
name | age
---------+-----
Charlie | 35注意:NOT BETWEEN 会自动排除 NULL。
04-order-limit
练习 1:基本排序
答案:
sql
SELECT name, age FROM users ORDER BY age ASC;输出:
text
name | age
---------+-----
Bob | 25
Diana | 28
Alice | 30
Charlie | 35
Eve |练习 2:降序排序
答案:
sql
SELECT name, age FROM users ORDER BY age DESC;输出:
text
name | age
---------+-----
Eve |
Charlie | 35
Alice | 30
Diana | 28
Bob | 25练习 3:多列排序
答案:
sql
SELECT name, age FROM users ORDER BY age DESC, name ASC;输出:
text
name | age
---------+-----
Eve |
Charlie | 35
Alice | 30
Diana | 28
Bob | 25练习 4:前 N 行
答案:
sql
SELECT name, age
FROM users
WHERE age IS NOT NULL
ORDER BY age ASC
LIMIT 2;输出:
text
name | age
-------+-----
Bob | 25
Diana | 28练习 5:分页查询
答案:
sql
SELECT name, age
FROM users
WHERE age IS NOT NULL
ORDER BY age DESC
LIMIT 2 OFFSET 2;输出:
text
name | age
-------+-----
Diana | 28
Bob | 25练习 6:按表达式排序
答案:
sql
SELECT name, LENGTH(name) AS name_length
FROM users
ORDER BY LENGTH(name) DESC, name ASC;输出:
text
name | name_length
---------+-------------
Charlie | 7
Alice | 5
Diana | 5
Bob | 3
Eve | 3练习 7:NULL 处理
答案:
PostgreSQL:
sql
SELECT name, age FROM users ORDER BY age ASC NULLS FIRST;MySQL:
sql
SELECT name, age FROM users ORDER BY age IS NOT NULL, age ASC;输出:
text
name | age
---------+-----
Eve |
Bob | 25
Diana | 28
Alice | 30
Charlie | 35练习 8:实际场景
答案:
sql
SELECT name, age, created_at
FROM users
WHERE age > 25
ORDER BY created_at DESC
LIMIT 3;输出(假设 created_at 按插入顺序):
text
name | age | created_at
---------+-----+------------------------
Charlie | 35 | 2026-09-20 10:30:00
Alice | 30 | 2026-09-20 10:30:00
Diana | 28 | 2026-09-20 10:30:0005-distinct
练习 1:基本去重
答案:
使用 orders 表:
sql
SELECT DISTINCT product FROM orders;输出:
text
product
------------
Laptop
Mouse
Keyboard
Monitor
Headphones
USB Cable练习 2:多列去重
答案:
sql
SELECT DISTINCT customer_name, product FROM orders;输出:
text
customer_name | product
---------------+------------
Alice | Laptop
Bob | Mouse
Alice | Keyboard
Charlie | Monitor
Bob | Headphones
Alice | USB Cable练习 3:统计去重
答案:
sql
SELECT COUNT(DISTINCT customer_name) AS unique_customers FROM orders;输出:
text
unique_customers
------------------
3练习 4:去重后排序
答案:
sql
SELECT DISTINCT customer_name FROM orders ORDER BY customer_name;输出:
text
customer_name
---------------
Alice
Bob
Charlie练习 5:理解差异
答案:
两个查询结果相同,都返回不重复的客户名称:
sql
-- 使用 DISTINCT
SELECT DISTINCT customer_name FROM orders;
-- 使用 GROUP BY
SELECT customer_name FROM orders GROUP BY customer_name;差异:
- DISTINCT 专注于去重
- GROUP BY 通常配合聚合函数使用,功能更强大
示例(GROUP BY 的优势):
sql
SELECT customer_name, COUNT(*) AS order_count
FROM orders
GROUP BY customer_name;输出:
text
customer_name | order_count
---------------+-------------
Alice | 3
Bob | 2
Charlie | 1练习 6:DISTINCT ON(PostgreSQL)
答案:
sql
SELECT DISTINCT ON (customer_name)
customer_name, product, amount
FROM orders
ORDER BY customer_name, amount DESC;输出:
text
customer_name | product | amount
---------------+----------+---------
Alice | Laptop | 1200.00
Bob | Headphones| 50.00
Charlie | Monitor | 300.00这返回每个客户金额最大的订单。
练习 7:性能对比
答案:
创建大表:
sql
CREATE TABLE large_orders AS
SELECT
id,
'Customer' || (id % 100) AS customer_name,
'Product' || (id % 50) AS product
FROM generate_series(1, 10000) AS id;比较性能:
sql
-- 无 DISTINCT
EXPLAIN ANALYZE SELECT customer_name FROM large_orders;
-- 有 DISTINCT
EXPLAIN ANALYZE SELECT DISTINCT customer_name FROM large_orders;观察执行时间和操作(Sort 或 HashAggregate)。
练习 8:实际场景
答案:
sql
SELECT DISTINCT customer_name
FROM orders
ORDER BY customer_name;输出:
text
customer_name
---------------
Alice
Bob
Charlie复习要点
第一章关键概念
- SELECT 结构:SELECT → FROM → WHERE → ORDER BY → LIMIT
- NULL 处理:使用 IS NULL / IS NOT NULL,不能用 = NULL
- 执行顺序:FROM → WHERE → SELECT → DISTINCT → ORDER BY → LIMIT
- 别名:WHERE 不能用别名,ORDER BY 可以
- DISTINCT:作用于所有选中的列,不是单列
常见陷阱
- ❌
WHERE age = NULL→ ✅WHERE age IS NULL - ❌ 字符串用双引号 → ✅ 字符串用单引号
- ❌ 没有 ORDER BY 就用 LIMIT → ✅ 总是配合 ORDER BY
- ❌ 以为 DISTINCT 只作用于第一列 → ✅ 作用于整行