选择需要的字段
从一张表中取出指定列,避免无目的地返回所有字段。
SELECT column_a, column_b
FROM table_name;通过真实业务数据,练习产品分析 SQL。
SQL REFERENCE
把高频 SQL 写法整理成可搜索、可复制的参考卡片。这里使用的是通用占位符, 不绑定某一套业务数据。
table_name、column_name、:param 都需要替换成你当前数据库中的真实表名、字段名和参数。 复制后请根据数据库类型调整日期函数和分页语法。当前显示 21 / 21 条写法
从一张表中取出指定列,避免无目的地返回所有字段。
SELECT column_a, column_b
FROM table_name;只返回满足条件的记录。多个条件可以用 AND 或 OR 连接。
SELECT *
FROM table_name
WHERE status = 'active'
AND amount >= 100;使用 ASC 升序或 DESC 降序排列结果。
SELECT column_a, column_b
FROM table_name
ORDER BY column_b DESC, column_a ASC;返回某个字段或字段组合的不重复结果。
SELECT DISTINCT category
FROM table_name;统计不同用户、客户或订单的数量。
SELECT COUNT(DISTINCT user_id) AS unique_users
FROM table_name;先为每个对象内部排序,再过滤出序号为 1 的记录。
WITH ranked_rows AS (
SELECT
t.*,
ROW_NUMBER() OVER (
PARTITION BY entity_id
ORDER BY updated_at DESC, record_id DESC
) AS row_num
FROM table_name AS t
)
SELECT *
FROM ranked_rows
WHERE row_num = 1;按一个或多个维度汇总记录数、金额或其他指标。
SELECT
category,
COUNT(*) AS record_count,
SUM(amount) AS total_amount
FROM table_name
GROUP BY category;使用 HAVING 筛选分组后的结果,不能用 WHERE 代替。
SELECT
category,
COUNT(*) AS record_count
FROM table_name
GROUP BY category
HAVING COUNT(*) >= 10;INNER JOIN 适合只分析存在对应关系的数据。
SELECT
a.entity_id,
b.detail_name
FROM table_a AS a
INNER JOIN table_b AS b
ON a.entity_id = b.entity_id;左表没有匹配记录时,右表字段会显示为 NULL。
SELECT
a.entity_id,
b.detail_name
FROM table_a AS a
LEFT JOIN table_b AS b
ON a.entity_id = b.entity_id;判断 NULL 必须使用 IS NULL 或 IS NOT NULL。
SELECT *
FROM table_name
WHERE closed_at IS NULL;COALESCE 从左到右返回第一个非 NULL 值。
SELECT
entity_id,
COALESCE(owner_name, '未分配') AS owner_name
FROM table_name;把原始数值或状态转换成更容易理解的业务标签。
SELECT
entity_id,
CASE
WHEN amount >= 1000 THEN 'high'
WHEN amount >= 100 THEN 'medium'
ELSE 'low'
END AS amount_level
FROM table_name;先命名中间结果,再在后续查询中复用,提升可读性。
WITH filtered_rows AS (
SELECT *
FROM table_name
WHERE status = 'active'
)
SELECT category, COUNT(*) AS record_count
FROM filtered_rows
GROUP BY category;适合数据量较小或需要快速查看第几页结果的场景。
SELECT *
FROM table_name
ORDER BY record_id
LIMIT :page_size OFFSET :offset;记录上一页最后一个 ID,避免大 OFFSET 越翻页越慢。
SELECT *
FROM table_name
WHERE record_id > :last_record_id
ORDER BY record_id ASC
LIMIT :page_size;ROW_NUMBER 为每一行生成唯一序号,即使并列也不会重复。
SELECT
entity_id,
score,
ROW_NUMBER() OVER (ORDER BY score DESC, entity_id) AS row_num
FROM table_name;RANK 会跳号,DENSE_RANK 不跳号;两者都会让并列记录获得相同名次。
SELECT
entity_id,
score,
RANK() OVER (ORDER BY score DESC) AS rank_num,
DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rank_num
FROM table_name;先按分组生成窗口排名,再在外层筛选名次。
WITH ranked_rows AS (
SELECT
group_name,
entity_id,
score,
ROW_NUMBER() OVER (
PARTITION BY group_name
ORDER BY score DESC, entity_id
) AS row_num
FROM table_name
)
SELECT *
FROM ranked_rows
WHERE row_num <= 3;使用左闭右开区间,避免结束日期带时间时遗漏或重复数据。
SELECT *
FROM table_name
WHERE event_time >= :start_time
AND event_time < :next_period_start;先把时间转换成日、周或月,再进行分组统计。
SELECT
date_column AS period,
COUNT(*) AS record_count
FROM table_name
GROUP BY date_column
ORDER BY period;