基础查询 #

一、SELECT基础 #

1.1 基本语法 #

sql
-- 基本查询语法
SELECT column1, column2, ...
FROM table_name
WHERE condition
ORDER BY column
LIMIT n;

-- 示例表
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name VARCHAR(100) NOT NULL,
    email VARCHAR(100),
    age INT,
    status VARCHAR(20) DEFAULT 'active',
    created_at TIMESTAMP DEFAULT NOW()
);

INSERT INTO users (name, email, age, status) VALUES
    ('Alice', 'alice@example.com', 25, 'active'),
    ('Bob', 'bob@example.com', 30, 'active'),
    ('Carol', 'carol@example.com', 28, 'inactive'),
    ('David', 'david@example.com', 35, 'active'),
    ('Eve', 'eve@example.com', 22, 'pending');

-- 查询所有列
SELECT * FROM users;

-- 查询指定列
SELECT name, email FROM users;

1.2 列别名 #

sql
-- 使用 AS 设置列别名
SELECT 
    name AS user_name,
    email AS email_address,
    age AS user_age
FROM users;

-- 别名可以省略 AS
SELECT name user_name, email email_address
FROM users;

-- 使用表达式别名
SELECT 
    name,
    age,
    age * 2 AS double_age,
    UPPER(name) AS upper_name
FROM users;

1.3 去重查询 #

sql
-- DISTINCT 去重
SELECT DISTINCT status FROM users;

-- DISTINCT 多列
SELECT DISTINCT status, age FROM users;

-- DISTINCT ON (PostgreSQL风格)
SELECT DISTINCT ON (status) *
FROM users
ORDER BY status, age DESC;

二、WHERE条件 #

2.1 比较运算符 #

sql
-- 等于
SELECT * FROM users WHERE status = 'active';

-- 不等于
SELECT * FROM users WHERE status != 'inactive';
SELECT * FROM users WHERE status <> 'inactive';

-- 大于、小于
SELECT * FROM users WHERE age > 25;
SELECT * FROM users WHERE age >= 25;
SELECT * FROM users WHERE age < 30;
SELECT * FROM users WHERE age <= 30;

-- BETWEEN
SELECT * FROM users WHERE age BETWEEN 25 AND 30;

-- NULL 判断
SELECT * FROM users WHERE email IS NULL;
SELECT * FROM users WHERE email IS NOT NULL;

2.2 逻辑运算符 #

sql
-- AND
SELECT * FROM users
WHERE status = 'active' AND age > 25;

-- OR
SELECT * FROM users
WHERE status = 'active' OR status = 'pending';

-- NOT
SELECT * FROM users
WHERE NOT status = 'inactive';

-- 组合使用
SELECT * FROM users
WHERE (status = 'active' OR status = 'pending')
  AND age >= 25;

2.3 IN和NOT IN #

sql
-- IN
SELECT * FROM users
WHERE status IN ('active', 'pending');

-- NOT IN
SELECT * FROM users
WHERE status NOT IN ('inactive', 'deleted');

-- 子查询
SELECT * FROM users
WHERE id IN (
    SELECT user_id FROM orders
);

2.4 LIKE模式匹配 #

sql
-- LIKE 模式匹配
SELECT * FROM users WHERE email LIKE '%@example.com';
SELECT * FROM users WHERE name LIKE 'A%';
SELECT * FROM users WHERE name LIKE '%a%';

-- ILIKE 不区分大小写
SELECT * FROM users WHERE email ILIKE '%@EXAMPLE.COM';

-- 通配符说明
-- %: 匹配任意字符序列
-- _: 匹配单个字符
SELECT * FROM users WHERE name LIKE '_lice';

-- 正则表达式
SELECT * FROM users WHERE name ~ '^A';
SELECT * FROM users WHERE name ~* '^a';  -- 不区分大小写
SELECT * FROM users WHERE name !~ '^A';  -- 不匹配

三、排序 #

3.1 ORDER BY #

sql
-- 升序排序 (默认)
SELECT * FROM users ORDER BY age;
SELECT * FROM users ORDER BY age ASC;

-- 降序排序
SELECT * FROM users ORDER BY age DESC;

-- 多列排序
SELECT * FROM users
ORDER BY status ASC, age DESC;

-- 使用表达式排序
SELECT * FROM users
ORDER BY LENGTH(name) DESC;

-- 使用列号排序
SELECT name, age FROM users
ORDER BY 2 DESC;  -- 按第二列排序

-- NULL 排序
SELECT * FROM users
ORDER BY email NULLS FIRST;

SELECT * FROM users
ORDER BY email NULLS LAST;

3.2 排序性能 #

text
排序性能优化
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   1. 使用索引                                               │
│   ├── ORDER BY 列有索引                                    │
│   └── 避免排序操作                                         │
│                                                             │
│   2. 限制结果集                                             │
│   ├── 使用 LIMIT                                           │
│   └── 减少排序数据量                                       │
│                                                             │
│   3. 避免 SELECT *                                          │
│   ├── 只选择需要的列                                       │
│   └── 减少数据传输                                         │
│                                                             │
│   4. 使用覆盖索引                                           │
│   ├── 索引包含所有查询列                                   │
│   └── 避免回表                                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

四、分页 #

4.1 LIMIT和OFFSET #

sql
-- LIMIT 限制返回行数
SELECT * FROM users LIMIT 5;

-- LIMIT + OFFSET 分页
SELECT * FROM users
ORDER BY created_at DESC
LIMIT 10 OFFSET 0;   -- 第1页

SELECT * FROM users
ORDER BY created_at DESC
LIMIT 10 OFFSET 10;  -- 第2页

SELECT * FROM users
ORDER BY created_at DESC
LIMIT 10 OFFSET 20;  -- 第3页

4.2 键集分页 #

sql
-- 键集分页 (更高效)
-- 第一页
SELECT * FROM users
ORDER BY created_at DESC, id
LIMIT 10;

-- 下一页 (使用上一页最后一条记录的值)
SELECT * FROM users
WHERE (created_at, id) < ('2024-01-01 00:00:00', 'last-uuid')
ORDER BY created_at DESC, id
LIMIT 10;

-- 键集分页优点:
-- 1. 不需要扫描跳过的行
-- 2. 性能稳定,不受偏移量影响
-- 3. 适合大数据量分页

4.3 分页最佳实践 #

text
分页最佳实践
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   LIMIT/OFFSET:                                             │
│   ├── 简单易用                                             │
│   ├── 适合小数据量                                         │
│   └── 大偏移量性能差                                       │
│                                                             │
│   键集分页:                                                 │
│   ├── 性能稳定                                             │
│   ├── 适合大数据量                                         │
│   └── 需要唯一排序列                                       │
│                                                             │
│   建议:                                                     │
│   ├── 小数据量: LIMIT/OFFSET                               │
│   ├── 大数据量: 键集分页                                   │
│   └── 避免大偏移量                                         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

五、聚合函数 #

5.1 基本聚合 #

sql
-- COUNT
SELECT COUNT(*) FROM users;
SELECT COUNT(email) FROM users;  -- 不计算NULL
SELECT COUNT(DISTINCT status) FROM users;

-- SUM
SELECT SUM(age) FROM users;

-- AVG
SELECT AVG(age) FROM users;

-- MAX/MIN
SELECT MAX(age), MIN(age) FROM users;

-- 组合使用
SELECT 
    COUNT(*) AS total,
    COUNT(email) AS with_email,
    AVG(age) AS avg_age,
    MAX(age) AS max_age,
    MIN(age) AS min_age
FROM users;

5.2 GROUP BY #

sql
-- 基本分组
SELECT status, COUNT(*) as count
FROM users
GROUP BY status;

-- 多列分组
SELECT status, age, COUNT(*) as count
FROM users
GROUP BY status, age;

-- 使用表达式分组
SELECT 
    CASE 
        WHEN age < 25 THEN 'young'
        WHEN age < 35 THEN 'middle'
        ELSE 'senior'
    END AS age_group,
    COUNT(*) as count
FROM users
GROUP BY 
    CASE 
        WHEN age < 25 THEN 'young'
        WHEN age < 35 THEN 'middle'
        ELSE 'senior'
    END;

5.3 HAVING #

sql
-- HAVING 过滤分组结果
SELECT status, COUNT(*) as count
FROM users
GROUP BY status
HAVING COUNT(*) > 1;

-- HAVING vs WHERE
-- WHERE: 过滤行 (分组前)
-- HAVING: 过滤分组 (分组后)

SELECT status, AVG(age) as avg_age
FROM users
WHERE email IS NOT NULL  -- 先过滤行
GROUP BY status
HAVING AVG(age) > 25;    -- 再过滤分组

5.4 聚合函数列表 #

函数 说明
COUNT(*) 总行数
COUNT(col) 非NULL行数
COUNT(DISTINCT col) 不同值数量
SUM(col) 总和
AVG(col) 平均值
MAX(col) 最大值
MIN(col) 最小值
STRING_AGG(col, sep) 字符串连接
ARRAY_AGG(col) 数组聚合

六、表达式和函数 #

6.1 算术运算 #

sql
-- 算术运算符
SELECT 
    age,
    age + 5 AS age_plus_5,
    age - 5 AS age_minus_5,
    age * 2 AS age_double,
    age / 2 AS age_half,
    age % 3 AS age_mod
FROM users;

-- 数学函数
SELECT 
    ABS(-5) AS abs_val,
    ROUND(3.14159, 2) AS rounded,
    FLOOR(3.9) AS floored,
    CEIL(3.1) AS ceiled,
    POWER(2, 3) AS power_val,
    SQRT(16) AS sqrt_val;

6.2 字符串函数 #

sql
-- 字符串函数
SELECT 
    name,
    UPPER(name) AS upper_name,
    LOWER(name) AS lower_name,
    LENGTH(name) AS name_length,
    LEFT(name, 3) AS first_3,
    RIGHT(name, 3) AS last_3,
    SUBSTRING(name, 1, 3) AS substr,
    CONCAT(name, ' - ', email) AS full_info,
    name || ' (' || email || ')' AS formatted
FROM users;

-- 字符串处理
SELECT 
    TRIM('  hello  ') AS trimmed,
    LTRIM('  hello  ') AS ltrimmed,
    RTRIM('  hello  ') AS rtrimmed,
    REPLACE('hello world', 'world', 'CockroachDB') AS replaced,
    SPLIT_PART('a,b,c', ',', 2) AS part;

6.3 日期时间函数 #

sql
-- 当前时间
SELECT 
    NOW() AS current_time,
    CURRENT_DATE AS current_date,
    CURRENT_TIMESTAMP AS current_timestamp;

-- 日期提取
SELECT 
    created_at,
    EXTRACT(YEAR FROM created_at) AS year,
    EXTRACT(MONTH FROM created_at) AS month,
    EXTRACT(DAY FROM created_at) AS day,
    EXTRACT(HOUR FROM created_at) AS hour,
    EXTRACT(DOW FROM created_at) AS day_of_week
FROM users;

-- 日期计算
SELECT 
    created_at,
    created_at + INTERVAL '1 day' AS tomorrow,
    created_at - INTERVAL '1 week' AS last_week,
    created_at + INTERVAL '1 month' AS next_month,
    AGE(created_at) AS age
FROM users;

-- 日期格式化
SELECT 
    created_at,
    TO_CHAR(created_at, 'YYYY-MM-DD') AS date_str,
    TO_CHAR(created_at, 'YYYY-MM-DD HH24:MI:SS') AS datetime_str
FROM users;

6.4 条件表达式 #

sql
-- CASE 表达式
SELECT 
    name,
    age,
    CASE 
        WHEN age < 25 THEN 'Young'
        WHEN age < 35 THEN 'Middle'
        ELSE 'Senior'
    END AS age_group
FROM users;

-- 简单 CASE
SELECT 
    status,
    CASE status
        WHEN 'active' THEN 'Active User'
        WHEN 'inactive' THEN 'Inactive User'
        ELSE 'Other'
    END AS status_desc
FROM users;

-- COALESCE 返回第一个非NULL值
SELECT 
    name,
    email,
    COALESCE(email, 'No email') AS email_or_default
FROM users;

-- NULLIF 如果相等返回NULL
SELECT 
    name,
    NULLIF(age, 0) AS age_non_zero
FROM users;

-- GREATEST/LEAST
SELECT 
    GREATEST(1, 2, 3) AS max_val,
    LEAST(1, 2, 3) AS min_val;

七、子查询 #

7.1 标量子查询 #

sql
-- 标量子查询 (返回单个值)
SELECT 
    name,
    (SELECT COUNT(*) FROM orders WHERE user_id = users.id) AS order_count
FROM users;

-- 在WHERE中使用
SELECT * FROM users
WHERE age > (SELECT AVG(age) FROM users);

7.2 列表子查询 #

sql
-- IN 子查询
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders);

-- EXISTS 子查询
SELECT * FROM users u
WHERE EXISTS (
    SELECT 1 FROM orders o
    WHERE o.user_id = u.id
);

-- NOT EXISTS
SELECT * FROM users u
WHERE NOT EXISTS (
    SELECT 1 FROM orders o
    WHERE o.user_id = u.id
);

7.3 派生表 #

sql
-- 派生表 (FROM中的子查询)
SELECT u.name, o.order_count
FROM users u
JOIN (
    SELECT user_id, COUNT(*) as order_count
    FROM orders
    GROUP BY user_id
) o ON u.id = o.user_id;

-- WITH 子句 (CTE)
WITH user_orders AS (
    SELECT user_id, COUNT(*) as order_count
    FROM orders
    GROUP BY user_id
)
SELECT u.name, uo.order_count
FROM users u
LEFT JOIN user_orders uo ON u.id = uo.user_id;

八、查询性能 #

8.1 查看执行计划 #

sql
-- 基本执行计划
EXPLAIN SELECT * FROM users WHERE status = 'active';

-- 详细执行计划
EXPLAIN ANALYZE SELECT * FROM users WHERE status = 'active';

-- 执行计划示例
EXPLAIN SELECT name, email FROM users WHERE age > 25;

-- 输出示例:
--                                              │
--        • scan                               │
--          table: users@primary               │
--          spans: FULL SCAN                   │
--          filter: age > 25                   │

8.2 查询优化建议 #

text
查询优化建议
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   1. 使用索引                                               │
│   ├── WHERE 条件使用索引列                                 │
│   └── ORDER BY 使用索引列                                  │
│                                                             │
│   2. 避免 SELECT *                                          │
│   ├── 只选择需要的列                                       │
│   └── 减少数据传输                                         │
│                                                             │
│   3. 使用覆盖索引                                           │
│   ├── 索引包含所有查询列                                   │
│   └── 避免回表                                             │
│                                                             │
│   4. 合理使用 LIMIT                                         │
│   ├── 限制结果集大小                                       │
│   └── 提高查询效率                                         │
│                                                             │
│   5. 避免 OR                                                │
│   ├── 使用 UNION 或 IN 代替                                │
│   └── 提高索引利用率                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

九、总结 #

SELECT 语句要点:

类型 说明
基本查询 列选择、别名、去重
WHERE 条件过滤
ORDER BY 结果排序
LIMIT/OFFSET 分页查询
聚合函数 COUNT、SUM、AVG等
GROUP BY 分组聚合
子查询 标量、列表、派生表

下一步,让我们学习多表连接查询!

最后更新:2026-03-27