SQL经典实例——检索记录

检索记录

1、检索表中所有的行和列

问题

你有一张表,你想查看表中的所有数据。

解决方案

使用 SELECT 语句来查询表,并使用特殊字符 * 指定返回所有的列。

sql 复制代码
select *
from emp;

在 SQL 中,字符 * 有特殊含义,它会返回指定表中所有的列。由于没有指定 WHERE 子句,因此将返回所有的行。也可以分别列出每一列。

sql 复制代码
select empno,ename,job,sal,mgr,hiredate,comm,deptno
from emp;

在以交互方式执行的临时查询中,使用 SELECT * 更容易。不过,在编写程序代码时,分别指定各列更合适。这两种做法性能相同,但显式指定能让你知道查询将返回哪些列。同理,这种查询对其他人(他们可能知道也可能不知道查询的表中包含哪些列)来说更容易理解。对于代码中的查询,使用 SELECT * 会带来问题,因为查询返回的列可能不符合预期。不管怎样,指定所有列时,如果没有返回其中的一列或多列,则可以跟踪异常以确定缺失了哪些列。

2、从表中检索部分行

问题

你有一张表,你想查看表中满足特定条件的行。

解决方案

使用 WHERE 子句来指定要返回哪些行。例如,要查看部门编号为 10 的所有员工,可以像下面这样做。

sql 复制代码
select *
from emp
where deptno = 10;

3、查找满足多个条件的行

问题

你想返回满足多个条件的行。

解决

方案结合使用 WHERE 子句、OR 子句和 AND 子句。例如,要查找部门编号为 10 的员工、有业务提成的员工以及薪水不超过 2000 美元且部门编号为 20 的员工,可以像下面这样做。

sql 复制代码
select *
from emp
where deptno = 10 
or comm is not null 
or sal <= 2000 and deptno = 20;

要返回满足多个条件的行,可以结合使用 AND、OR 和圆括号。在上述解决方案中,WHERE 子句查找满足下面任何一个条件的行:

  • DEPTNO 为 10;
  • COMM 不为 NULL;
  • 薪水不超过 2000 美元且 DEPTNO 为 20。
  • 圆括号指定将多个条件作为一个整体。

例如,下面是将前 3 个条件放在圆括号内时返回的结果集。

sql 复制代码
select *
from emp
where (
	deptno = 10
	or comm is not null
	or sal <= 2000
) and deptno = 20;

4、从表中检索部分列

问题

你有一张表,你想查看表中特定列(而不是所有列)的值。

解决

方案指定要查看的列。例如,只查看员工的姓名、部门编号和薪水。

sql 复制代码
select ename, deptno, sal 
from emp;

在 SELECT 子句中指定列可以避免返回无关的数据。通过网络检索数据时,这样做非常重要,因为可以避免浪费时间而检索不需要的数据。

5、提供有意义的列名

要修改查询结果中显示的列名,可以使用关键字 AS(original_name AS new_name)​。有些数据库不强制要求使用 AS,但所有数据库都支持这样做。

sql 复制代码
select sal as salary, comm as commision
from emp;

使用关键字 AS 给查询返回的列指定新名称的行为被称为指定别名,而指定的新名称被称为别名。通过指定良好的别名,可以让查询及其返回的结果对他人来说更容易理解。

6、在WHERE子句中使用别名来引用列

问题

在结果集中,你已经使用别名提供了含义更明确的列名,但还想使用 WHERE 子句将某些行排除在外。为此,你在WHERE 子句中引用了别名,但以失败告终。

sql 复制代码
select sal as salary, comm as commission
from emp
where salary < 5000;

# 1054 - Unknown column 'salary' in 'where clause', 

解决:

方案将查询作为内嵌视图来引用列的别名。

sql 复制代码
select *
from (
	select sal as salary, comm as commission
	from emp
) x 
where salary < 5000;

在这个简单的实例中,可以在 WHERE 子句中直接引用COMM 或 SAL,这样就无须使用内嵌视图了。上述解决方案演示了在 WHERE 子句中引用如下内容时,需要做什么。

  • 聚合函数
  • 标量子查询
  • 窗口函数
  • 别名

将提供别名的查询放在内嵌视图中,就可以在外部查询中引用列的别名。为什么要这样做呢?这是由于 WHERE 子句是在 SELECT 子句之前评估的,因此,对于前面说明问题时列举的查询,在评估其中的 WHERE 子句时,还没有别名 SALARY 和 COMMISSION。这些别名在 WHERE子句处理完毕后才存在。然而,FROM 子句是在 WHERE子句之前评估的。如果将查询放在 FROM 子句中,那么将在最外层的 WHERE 子句执行前生成该查询的结果,这样一来,最外层的 WHERE 子句就能够"看到"别名了。在列名不是太好时,这种技巧很有用。

7、拼接列值

问题

你想将多列的值作为一列返回。例如,你希望对 EMP 表的查询返回如下结果集。

sql 复制代码
CLARK WORKS AS A MANAGER
KING WORKS AS A PRESIDENT
MILLER WORKS AS A CLERK

然而,生成这个结果集所需的数据来自 EMP 表中两个不同的列,即 ENAME 和 JOB。

sql 复制代码
 select ename, job
    from emp
    where deptno = 10

ENAME      JOB
---------- ---------
CLARK      MANAGER
KING       PRESIDENT
MILLER     CLERK

解决方案:

找到并使用 DBMS(数据库管理系统)内置的函数来拼接多列的值。

DB2、Oracle 和 PostgreSQL:这些数据库将双竖线用作拼接运算符。

sql 复制代码
select ename || ' WORKS AS A ' || job as msg 
from emp
where deptno = 10;

            msg            
---------------------------
 CLARK WORKS AS A MANAGER
 KING WORKS AS A PRESIDENT
 MILLER WORKS AS A CLERK

MySQL:该数据库支持函数 CONCAT。

sql 复制代码
select concat(ename, ' WORKS AS A ', job) as msg 
from emp
where deptno = 10;

SQL Server:该数据库使用运算符 + 来执行拼接操作。

sql 复制代码
select ename + ' WORKS AS A ' + job as msg 
from emp
where deptno = 10;

使用函数 CONCAT 可以拼接多列的值。在 DB2、Oracle 和 PostgreSQL 中,函数 CONCAT 的简写为 ||,在SQL Server 中为 +。

8、在SELECT语句中使用条件逻辑

问题

在 SELECT 语句中,你想执行基于值的 IF-ELSE 操作。例如,在生成结果集时,你想在员工的薪水不超过 2000美元时返回消息 UNDERPAID,在员工的薪水不低于4000 美元时返回消息 OVERPAID,在员工的薪水为2000~4000 美元时返回消息 OK。这个结果集如下所示。

sql 复制代码
 ENAME            SAL  STATUS
---------- ----------  ---------
SMITH             800  UNDERPAID
ALLEN            1600  UNDERPAID
WARD             1250  UNDERPAID
JONES            2975  OK
MARTIN           1250  UNDERPAID
BLAKE            2850  OK
CLARK            2450  OK
SCOTT            3000  OK
KING             5000  OVERPAID
TURNER           1500  UNDERPAID
ADAMS            1100  UNDERPAID
JAMES             950  UNDERPAID
FORD             3000  OK
MILLER           1300  UNDERPAID

解决方案:

在 SELECT 语句中直接使用 CASE 表达式来执行条件逻辑。

sql 复制代码
select 
	ename,
	sal,
	case when sal <= 2000 then 'UNDERPAID'
			 when sal > 2000 and sal < 4000 then 'OK'
			 when sal >= 4000 then 'OVERPAID'  
	end as STATUS
from emp;

CASE 表达式能够根据查询返回的值来执行条件逻辑。为了提高结果集的可读性,可以给 CASE 表达式指定别名。上述解决方案给 CASE 表达式的结果指定了别名STATUS。ELSE 子句是可选的。如果省略了 ELSE 子句,那么对于不满足测试条件的行,CASE 表达式将返回NULL。

9、限制返回的行数

问题

你想限制查询中返回的行数。你不关心顺序,只要返回的行数是指定的(n)​。

解决:方案使用数据库提供的内置函数来控制返回的行数。

DB2:在 DB2 中,使用 FETCH FIRST 子句。

sql 复制代码
select *
from emp fetch first 5 rows only

MySQL 和 PostgreSQL:在 MySQL 和 PostgreSQL 中,使用 LIMIT 来限制返回的行数。

sql 复制代码
select *
from emp
limit 5;

Oracle:在 Oracle 中,要限制返回的行数,可以在 WHERE 子句中对 ROWNUM 进行限制。

sql 复制代码
select *
from emp
where rownum <= 5

SQL Server:在 SQL Server 中,使用关键字 TOP 来限制返回的行数。

sql 复制代码
select top 5 *
from emp

很多数据库提供了相关的子句(如 FETCH FIRST 和LIMIT)来指定查询返回的行数。Oracle 与众不同,它要求你使用函数 ROWNUM,对于返回的每一行,该函数都返回一个数字(从 1 开始不断递增)​。

当你使用 ROWNUM <= 5 来返回前 5 行数据时,将发生如下事情。

  1. Oracle 执行查询。
  2. Oracle 取得第 1 行数据,并将编号设置为 1。当前行的编号超过 5 了吗?如果没有,Oracle 就返回它,因为它满足条件"编号不超过 5";否则,Oracle 就不返回它。
  3. Oracle 取得下一行数据并将编号加 1(编号依次为 2、3、4,以此类推)。
  4. 回到第 3 步。

正如上述过程显示的,取得每一行时,都将其编号设置为ROWNUM 返回的值。这一点很重要。为了让查询只返回特定行(如第 5 行)​,很多 Oracle 开发人员会指定条件ROWNUM = 5。

使用 ROWNUM 来指定相等条件并不是一个好主意。使用ROWNUM = 5 来试图返回第 5 行时,将发生如下事情。

  1. Oracle 执行查询
  2. Oracle 取得第 1 行数据,并将编号设置为 1。编号是 5 吗?如果不是,那么 Oracle 将丢弃当前行,因为它不满足条件;如果是,Oracle 将返回它。然而,编号为 5 的情况永远不会发生!
  3. Oracle 取得下一行数据并将编号设置为 1。这是因为查询返回的第 1 行的编号必须为 1。回到第 3 步。

如果仔细研究这个过程,你就会明白使用 ROWNUM = 5无法返回第 5 行的原因。要让编号变为 5,必须先返回 4行数据。

你可能注意到了,使用 ROWNUM = 1 确实能够返回第 1行数据,这看似与前面的解释相互矛盾。使用 ROWNUM =1 为什么能够返回第 1 行数据呢?这是因为为了确定表是否为空,Oracle 必须至少尝试取得一行数据。如果仔细审视上述过程,并将 5 替换为 1,你就会明白为什么使用条件 ROWNUM = 1 可以返回一行数据了。

10、从表中随机返回n行数据

问题

你想从表中随机返回 n 行数据。为此,你想修改下面的语句,使其返回 5 行数据,且每次执行时返回的行都不同。

解决方案

使用 DBMS 提供的返回随机值的内置函数。在 ORDERBY 子句中,使用该内置函数以随机的方式对行进行排 序,然后使用上一节介绍的方法来限制返回的行数。

DB2:结合使用内置函数 RAND、ORDER BY 和 FETCH。

sql 复制代码
select ename,job
from emp
order by rand() fetch first 5 rows only

MySQL:结合使用内置函数 RAND、LIMIT 和 ORDER BY。

sql 复制代码
select ename, job
from emp
order by rand() limit 5;

PostgreSQL:结合使用内置函数 RANDOM、LIMIT 和 ORDER BY。

sql 复制代码
select ename, job
from emp
order by random() limit 5;

Oracle:结合使用(内置包 DBMS_RANDOM 中的)内置函数VALUE、ORDER BY 子句和内置函数 ROWNUM。

sql 复制代码
select *
from (
	select ename, job
	from emp
	order by dbms_random.value()
)
where rownum <= 5

SQL Server:结合使用内置函数 NEWID、TOP 和 ORDER BY 来返回随机的结果集。

sql 复制代码
select top 5 ename,job
from emp
order by newid()

ORDER BY 子句可以根据函数的返回值来调整结果集的排列顺序。这些解决方案都在 ORDER BY 子句中的函数执行后限制返回的行数。即便你使用的不是 Oracle,仔细研究 Oracle 解决方案也会有所帮助,因为它展示了其他解决方案在幕后发生的情况。

在 ORDER BY 子句中,使用函数和使用数值常量导致的排序方式是不同的,明白这一点很重要。在 ORDER BY子句中指定数值常量时,要求根据 SELECT 子句中相应位置的列进行排序。而在 ORDER BY 子句中指定函数时,要求对每行执行该函数,并根据函数的结果进行排序。

11、查找NULL值

问题:

你想查找特定列为 NULL 的所有行。

解决方案:

要判断一个值是否为 NULL,必须使用 IS NULL。

sql 复制代码
select *
from emp
where comm is null;

由于 NULL 与任何值(包括 NULL 本身)都不相等,也不会相等,因此测试列值是否为 NULL 时,不能使用 = 或!=。要判断列值是否为 NULL,必须使用 IS NULL。也可以使用 IS NOT NULL 来查找给定列不为 NULL 的行。

12、将NULL转换为实际值

问题

有些列为 NULL,但你不想返回 NULL,而想返回非 NULL值。

解决方案

使用函数 COALESCE 将 NULL 值替换为实际值。

sql 复制代码
select coalesce(comm, 0)
from emp;

函数 COALESCE 可以将一个或多个值作为参数,并返回参数列表中的第一个非 NULL 值。在上述解决方案中,如果 COMM 不为 NULL,就返回它,否则就返回 0。

处理 NULL 值时,最好利用 DBMS 提供的内置功能。在很多情况下,有多个函数可以很好地完成这项任务,但COALESCE 在所有 DBMS 中都管用。另外,在所有DBMS 中,都可以使用 CASE 来完成这项任务。

sql 复制代码
select 
	case when comm is not null then comm
			 else 0
	end as comm 
from emp;

13、模式查找

问题

你想返回与特定子串或模式匹配的行。请看下面的查询及其返回的结果集。

sql 复制代码
select ename, job
  from emp
 where deptno in (10,20)

ENAME       JOB
----------  ---------
SMITH       CLERK
JONES       MANAGER
CLARK       MANAGER
SCOTT       ANALYST
KING        PRESIDENT
ADAMS       CLERK
FORD        ANALYST
MILLER      CLERK

在部门编号为 10 和部门编号为 20 的员工中,你只想返回那些姓名包含字母 I 或职位名称以 ER 结尾的员工。

sql 复制代码
ENAME       JOB
----------  ---------
SMITH       CLERK
JONES       MANAGER
CLARK       MANAGER
KING        PRESIDENT
MILLER      CLERK

解决方案:

结合使用 LIKE 运算符和 SQL 通配符(%)​。

sql 复制代码
select ename, job
from emp
where deptno in(10, 20)
	and (ename like '%I%' or job like '%ER');

用于模式匹配运算 LIKE 中时,通配符(%)与任何字符序列都匹配。大多数 SQL 实现还提供了与单个字符匹配的下划线运算符(_)​。通过将搜索模式 I 放在两个 % 之间,可以与任何包含 I 的字符串匹配。在没有将搜索模式放在两个 % 之间的情况下,% 的位置将影响查询结果。如果要查找以 ER 结尾的职位名称,那么可以将 % 放在 ER前面;如果要查找以 ER 开头的职位名称,则需要将 % 放在 ER 后面。

相关推荐
黄焖鸡能干四碗1 小时前
软件系统概要设计说明书模版(Word)
大数据·运维·数据库·架构·需求分析
dust_and_stars1 小时前
为什么ubuntu24 snap install code-server 不需要--classic?
网络·数据库
BomanGe21 小时前
NSK W1406FA系列长行程高速精密丝杠技术指南
运维·服务器·数据库·经验分享·规格说明书
之歆2 小时前
MongoDB 深度解析:从原理到实践的完整指南
数据库·mongodb
一 乐2 小时前
幼儿园管理系统|基于springboot + vue幼儿园管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·幼儿园管理系统
tiancaijiben2 小时前
阿里云日志服务SLS全流程对接与深度使用指南
网络·数据库
云计算磊哥@2 小时前
运维开发宝典028-MySQL04数据库热备
数据库·adb·运维开发
五阿哥永琪2 小时前
正则表达式
数据库·mysql·正则表达式
LaughingZhu2 小时前
Product Hunt 每日热榜 | 2026-06-13
数据库·mysql