当前位置:首页 > 问答 > 正文

SQL查询 数据库检索:SQL语言中First关键字的用法及数据库查询中的first

SQL查询中的First关键字:从菜鸟到高手的实战指南

"小王盯着屏幕上的客户数据表发愁——老板要他‘找出每个地区最早注册的客户’,但他连‘最早’这个词在SQL里怎么表达都拿不准..." 如果你也遇到过类似困扰,今天我们就用最接地气的方式,彻底讲透SQL中处理"第一条记录"的N种姿势。

为什么我们需要First功能?

想象你正在分析:

  • 电商平台的每日首单客户
  • 每个班级第一名的学生成绩
  • 设备故障的首次报警记录

这些场景都需要锁定"第一条"数据,但有趣的是,标准SQL中其实并没有FIRST()函数(MySQL/MariaDB除外),这就像去餐厅点菜发现菜单上没有"红烧肉",但厨师会说"我们有糖醋排骨啊"。

主流数据库的解决方案

方案1:ROW_NUMBER() 窗口函数(通用解法)

-- 找出每个部门最早入职的员工
WITH ranked_employees AS (
  SELECT 
    employee_name,
    department,
    hire_date,
    ROW_NUMBER() OVER (PARTITION BY department ORDER BY hire_date) AS rn
  FROM employees
)
SELECT * FROM ranked_employees WHERE rn = 1;

原理:先给每个部门的员工按入职日期排序标号,再筛选1号选手,适用于PostgreSQL、SQL Server、Oracle等现代数据库。

方案2:MySQL/MariaDB的专属FIRST_VALUE()

-- 获取每个商品类别的首次上架记录
SELECT DISTINCT
  product_category,
  FIRST_VALUE(product_name) OVER (
    PARTITION BY product_category 
    ORDER BY launch_date
  ) AS first_product
FROM products;

注意:这里必须用DISTINCT去重,否则会返回所有记录。

SQL查询 数据库检索:SQL语言中First关键字的用法及数据库查询中的first

方案3:老牌数据库的GROUP BY技巧

-- SQLite/早期MySQL中找每个用户的首笔订单
SELECT o.*
FROM orders o
JOIN (
  SELECT user_id, MIN(order_date) AS first_order_date
  FROM orders
  GROUP BY user_id
) first ON o.user_id = first.user_id 
       AND o.order_date = first.first_order_date;

缺陷:如果同一用户同秒有多个订单,会全部返回。

实战避坑指南

  1. NULL值陷阱
    当排序字段包含NULL时:

    ORDER BY create_time DESC NULLS LAST  -- PostgreSQL语法
    ORDER BY IFNULL(create_time, '9999-12-31')  -- MySQL写法
  2. 并列第一处理
    RANK()代替ROW_NUMBER()会保留并列记录:

    RANK() OVER (ORDER BY score DESC)  -- 两个100分都排第1
  3. 性能优化
    大数据量时,给分区字段和排序字段加联合索引:

    CREATE INDEX idx_dept_hire ON employees(department, hire_date);

特殊场景解决方案

随机取第一条(抽奖场景)

-- PostgreSQL的TABLESAMPLE用法
SELECT * FROM users TABLESAMPLE SYSTEM(1) LIMIT 1;

按自定义顺序取首条

SQL查询 数据库检索:SQL语言中First关键字的用法及数据库查询中的first

-- 优先显示状态为'active'的记录
SELECT *
FROM (
  SELECT *,
    ROW_NUMBER() OVER (
      ORDER BY CASE status WHEN 'active' THEN 0 ELSE 1 END,
      create_time
    ) AS rn
  FROM tickets
) t WHERE rn = 1;

专家级技巧

  1. LATERAL JOIN黑科技(PostgreSQL)

    -- 查询每个订单的首个操作日志
    SELECT o.order_id, first_log.*
    FROM orders o
    CROSS JOIN LATERAL (
      SELECT * FROM order_logs 
      WHERE order_id = o.order_id
      ORDER BY log_time LIMIT 1
    ) first_log;
  2. DISTINCT ON语法(PostgreSQL独家)

    -- 简洁版分组取首条
    SELECT DISTINCT ON (department) *
    FROM employees
    ORDER BY department, hire_date;

最新实践建议(2025):随着SQL:2023标准的普及,更多数据库开始支持QUALIFY子句,未来可能简化为:

SELECT *
FROM sales
QUALIFY ROW_NUMBER() OVER(PARTITION BY region ORDER BY sale_date) = 1;

没有最好的方法,只有最适合当前数据库版本和数据特征的写法,下次当你需要"第一条"数据时,不妨把这篇文章当作速查手册。

发表评论