《SQL CookBook 》笔记-第一章-检索记录

第一章
shanzm


第一章 检索记录

1.1检索所有行和列

问题:你有一张表,并且想查看表中的所有数据。

解决方案1:

    select * from EMP

解决方案2:

 select empno,ename,job,sal,mgr,hiredate comm,deptno from EMP

说明:

建议使用方案2,因为别人看你的代码的时候不一定知道你查询的表里面的列,所以还是写出查询的具体列更方便阅读。其次从优化的角度来说,尽量避免“ select * ” 的存在,使用具体的列代替*,避免返回多余的列。

【技巧】

  1. 查看SQL语句执行时间:
set statistics time on

select * from EMP  
-- 注释:这里写你要测试执行时间的SQL语句

set statistics time off

运行结束之后,从消息栏,可以查看

SQL Server 执行时间:
CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。

  1. 查看SQL语句查询时对I/0的操作情况
set statistics io on

select * from EMP
-- 注释:这里写你要测试的SQL语句

set statistics io of

运行结束之后,从消息栏,可以查看:

表 ‘EMP’。扫描计数 1,逻辑读取 1 次,物理读取 0 次,
预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。


1.2筛选行

问题:你有一张表,并且只想查看满足指定条件的行。

解决方案:
使用 WHERE 子句指明保留哪些行。使用 WHERE 子句来筛选出我们感兴趣的行。如果 WHERE 子句的表达式针对某一行的判定结果为真,那么就会返回该行的数据。

例如,下面的语句将查找部门编号为 10 的所有员工。

select * from EMP where DEPNO=10;

结果:

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
7782 CLARK MANAGER 7839 1981-06-09 00:00:00.000 2450 NULL 10
7839 KING PRESIDENT NULL 1981-11-17 00:00:00.000 5000 NULL 10
7934 MILLER CLERK 7782 1982-01-23 00:00:00.000 1300 NULL 10


1.3查找满足多个查询条件的行

问题:你想返回满足多个查询条件的行。

解决方案:
使用带有 OR 和 AND 和圆括号()的 WHERE 子句。

例如,如果你想找出部门编号为 10 的所有员工、有奖金的所有员工以及部门编号是 20 且工资低于 2000 美元的所有员工。

【分析】也就是要找满足以下三种情况之一的员工(注意不是要求同时满足)

  • 部门编号=10;
  • 奖金不为Null(注意不是:奖金!=0,因为我们在数据库中,对无奖金的,填写为NULL);
  • 部门编号=20 & 工资<=2000;
select * from EMP
        where DEPTNO=10
                or COMM not NULL
                or SAL<=2000 and DEPTNO=20;

结果:

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
7369 SMITH CLERK 7902 1980-12-17 00:00:00.000 800 NULL 20
7499 ALLEN SALESMAN 7698 1981-02-20 00:00:00.000 1600 300 30
7521 WARD SALESMAN 7698 1981-02-22 00:00:00.000 1250 500 30
7654 MARTIN SALESMAN 7698 1981-09-28 00:00:00.000 1250 1400 30
7782 CLARK MANAGER 7839 1981-06-09 00:00:00.000 2450 NULL 10
7839 KING PRESIDENT NULL 1981-11-17 00:00:00.000 5000 NULL 10
7844 TURNER SALESMAN 7698 1981-09-08 00:00:00.000 1500 0 30
7876 ADAMS CLERK 7788 1983-01-12 00:00:00.000 1100 NULL 20
7934 MILLER CLERK 7782 1982-01-23 00:00:00.000 1300 NULL 10

【补充】检索:20号部门中有奖金的员工和工资不高于2000的员工

SQL语句:

select * from EMP
        where ( 
                or comm is not null
                or sal <= 2000
              )
              and deptno=20;

【分析】以上SQL语句中的where字句的逻辑运算就是

(a|b)&c=(a&c)|(b&c)

where (comm is not null and deptno=20) or (sal <= 2000 and deptno=20)

结果:

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
7369 SMITH CLERK 7902 1980-12-17 00:00:00.000 800 NULL 20
7876 ADAMS CLERK 7788 1983-01-12 00:00:00.000 1100 NULL 20


1.4筛选列

问题:你有一张表,并且只想查看特定列的值。

解决方案:
select之后指定你想要查询的列。

例如,只查看员工的名字、部门编号和工资。

select ename,deptno,sal from EMP;

结果:

ename deptno sal
SMITH 20 800
ALLEN 30 1600
WARD 30 1250
JONES 20 2975
MARTIN 30 1250
BLAKE 30 2850
CLARK 10 2450
SCOTT 20 3000
KING 10 5000
TURNER 30 1500
ADAMS 20 1100
JAMES 30 950
FORD 20 3000
MILLER 10 1300


1.5创建列的别名

问题:你可能想要修改检索结果的列名,使其更具可读性且更易于理解。考虑下面这个查询,它返回的是每个员工的工资。

select ename,sal from emp

ename是什么吗?sal 指的是什么?显然这不方便阅读查询结果。

检索结果应该让人容易理解,所以我们可以在查询的时候自定义查询结果显示的列名(当然这不会改变数据库中表的列名)。

解决方案:
使用 AS 关键字创建别名,以 original_name AS new_name 的形式来修改检索结果的列名。

对于一些数据库而言, AS 不是必需的,但所有的数据库都支持这个关键字。

【注意】自定义的显示列名(别名),不允许有空格

SQL语句:

select  
        ename as EmployeeName,
        sal as salary
from EMP
where deptno=30;

结果:

EmployeeName salary
ALLEN 1600
WARD 125
MARTIN 1250
BLAKE 2850
TURNER 1500
JAMES 950


1.6 在where子句中引用别名列

问题:根据1.5中,已经为检索结果创建了有意义的列名
现在想要利用where子句来进行数据的过滤
但是你按照下面的SQL语句,则无法成功


select  
        sal as salary ,
        comm as commission
from EMP

where salary<5000

为什么呢?

【注意】
where子句会比select子句先执行
from子句会比where子句先执行

所以你在上面的查询语句的时候,在执行where子句的时候,根本就还没有slaray。

解决方案:
法1.你在where子句中使用原始列名

select  
        sal as salary ,
        comm as commission
from EMP

where sal<5000

法2.把查询包装为一个内嵌视图


select * 
        from
        (
        select 
                sal as salary
                comm as commission
        from EMP
        )
where salary<5000;


1.7 串联多列的值

问题:想要查询多列的值显示在一列上
比如说:

select ename,job
from EMP
where deptno=10

结果:

ename job
CLARK MANAGER
KING PRESIDENT
MILLER CLERK

上面如愿查询到结果,但是想要显示为一列,如下:

msg
CLARK work as a MANAGER
KING work as a PRESIDENT
MILLER work as a CLERK

怎么办呢?

解决方案:

select ename+' work as a ' +job as msg
from EMP 
where deptno=10

结果:如上所希望。


1.8 在select语句里使用条件逻辑

问题:你想在 SELECT 语句中针对查询结果值执行 IF-ELSE 操作。
例如,你想生成类似这样的结果:
如果员工的工资少于 2000 美元,就返回 UNDERPAID ;
如果超过 4000 美元就返回OVERPAID ;
若介于两者之间则返回 OK 。
查询结果如下所示:

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 UNDERPAI

解决方案:
使用case语句

select ename ,sal ,
        case 
                when sal>=4000 then 'OverPaid'
                when sal<=2000 then 'UnderPaid'
                else 'Ok'
        end as Status
from EMP

结果如上所愿!

【说明】
case语句格式如下:

case
        when 限制条件语句1 then '返回值1'
        when 限制条件语句2 then '返回值2'
        ...
        else '返回值'
end as 自定义列名 

【注意】
1.else子句是可选的,若没有它,对于不满足测试条件的行, case 表达式会返回 Null 。

2.case语句就是相当于一个列,所以自己给他定义了一个列名(在end后使用as关键字),同样因此用逗号和其他列名隔开。

3.注意返回值是使用单引号,SQL中字符串使用单引号引起


1.9 限定返回行数

问题:想要限定返回结果的行数,而且不在意排序。

例如:返回查询结果的前5行。

解决方案:使用 TOP 关键字限定返回行数。


select top 5 *
from EMP

结果是返回EMP表的前5行


1.10 随机返回若干行记录

问题:希望从表中获取特定数量的随机记录。

解决方案:利用order by newid()与top子句配合,实现在记录集中获取N条随机记录

select top 5 *
from EMP
order by newid()

结果是随机的在EMP表中选取5行。

【说明】
在MS SQL中函数newid()

  1. newid()函数产生一个全球唯一的标识,该标识是由网卡号、CPU时钟组成。从而保证该函数调用的返回值是唯一的。

  2. 该函数的返回值类型为uniqueidentifier类型,该类型必须与newid函数配合使用。

newid函数的用途:

正是由于uniqueidentifier的唯一性,我们通常用uniqueidentifier类型作为表的主键类型通过newid函数为该类型的字段新增或者更新值。

【举例】

create table test

(
        id uniqueidentifier primary key,

        name varchar(20)

)

插入新的数据:

insert into test values ( newid() , '小明' )


1.11 查找 Null 值

问题:你想查找特定列的值为 Null 的所有行。

注意:NULL是指无值(no value),它与字段包含 0、空字符串或仅仅包含空格不同。

解决方案:判断一个值是否为 Null ,必须使用 IS Null

select * from EMP
where comm is NULL

结果就是EMP表中comm列值是NULL的所有数据。

【说明】毫无疑问,查找特定列的值是非NULL的方式就是使用is not null


1.12 把 Null 值转换为实际值

问题:有一些行包含 Null 值,但是你想在查询的返回结果里将其替换为非 Null 值。

注意:只是把你查询的结果中的NULL换成其他的值,并不是修改数据库的表。

解决方案1:使用使用 coalesce() 函数将 Null 值替代为实际值。

例如:如果EMP表中的comm列的值是NULL,则返回0,若非NULL则返回comm值

select coalesce(comm,0)
from EMP

【说明】
coalesce 动词,合并的意思,读作[,koə’lɛs]

COALESCE(expression_1, expression_2, …,expression_n)依次参考各参数表达式,遇到非null值即停止并返回该值。如果所有的表达式都是空值,最终将返回一个空值

解决方案2:使用case语句,但是没有coalesce()函数简洁

顺便说一句主流数据库都自带coalesce()函数。

select 
        case
                when comm is not null then comm
                else 0
        end as comm
from EMP


1.13 查找匹配项

问题:你想返回匹配某个特定字符串或模式的行。

例如:你想从编号为 10 和 20 的两个部门中找到名字中含有字母 I 或职位以 ER 结尾的人。

解决方案:使用通配符%配合like 操作符

select ename, job
from emp
where deptno in (10,20)
      and (ename like '%I%' or job like '%ER')

【说明】

  1. 最常使用的通配符是百分号( % ),所有DBMS皆支持。在搜索串中, % 表示任何字符出现任意次数

  2. 通配符 % 看起来像是可以匹配任何东西,但有个例外,这就是 NULL 。子句 WHERE name LIKE ‘%’ 不会匹配产品名称为 NULL 的行。

  3. MS SQL还有通配符[],此处不详述了。

【注意】通配符不利于SQL优化

SQL 的通配符很有用。但这种功能是有代价的,即通配符搜
索一般比前面讨论的其他搜索要耗费更长的处理时间。

用通配符时要记住的技巧。

  • 不要过度使用通配符。如果其他操作符能达到相同的目的,应该使用其他操作符。
  • 在确实需要使用通配符时,也尽量不要把它们用在搜索模式的开始处。把通配符置于开始处,搜索起来是最慢的