SQL基础操作_1_检索数据
目录
7.1.1 数据集
见如下SQL,以Oracle为例:
-- 1 Oracle版本
-- DROP TABLE EMP;
-- DROP TABLE DEPT;
-- DROP TABLE BONUS;
-- DROP TABLE SALGRADE;
CREATE TABLE DEPT
(DEPTNO NUMBER(2) NOT NULL CONSTRAINT pk_dept_deptno primary key,
DNAME VARCHAR2(14),
LOC VARCHAR2(13) );
comment on table DEPT is '部门表';
comment on column DEPT.DEPTNO is '表示部门编号,由两位数字所组成';
comment on column DEPT.DNAME is '部门名称,最多由14个字符所组成';
comment on column DEPT.LOC is '部门所在的位置';
INSERT INTO DEPT VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO DEPT VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO DEPT VALUES (30, 'SALES', 'CHICAGO');
INSERT INTO DEPT VALUES (40, 'OPERATIONS', 'BOSTON');
CREATE TABLE EMP
(EMPNO NUMBER(4) NOT NULL CONSTRAINT pk_emp_empno primary key,
ENAME VARCHAR2(10),
JOB VARCHAR2(9),
MGR NUMBER(4),
HIREDATE DATE,
SAL NUMBER(7, 2),
COMM NUMBER(7, 2),
DEPTNO NUMBER(2) constraint dept_deptno_ref references dept(deptno)
);
comment on table EMP is '雇员表';
comment on column EMP.EMPNO is '雇员的编号,由四位数字所组成';
comment on column EMP.ENAME is '雇员的姓名,由10位字符所组成';
comment on column EMP.JOB is '雇员的职位';
comment on column EMP.MGR is '雇员对应的领导编号,领导也是雇员';
comment on column EMP.HIREDATE is '雇员的雇佣日期';
comment on column EMP.SAL is '基本工资,其中有两位小数,五倍整数,一共是七位';
comment on column EMP.COMM is '奖金,佣金';
comment on column EMP.DEPTNO is '雇员所在的部门编号';
INSERT INTO EMP VALUES(7369, 'SMITH', 'CLERK', 7902,TO_DATE('17-DEC-1980', 'DD-MON-YYYY'), 800, NULL, 20);
INSERT INTO EMP VALUES(7499, 'ALLEN', 'SALESMAN', 7698,TO_DATE('20-FEB-1981', 'DD-MON-YYYY'), 1600, 300, 30);
INSERT INTO EMP VALUES(7521, 'WARD', 'SALESMAN', 7698,TO_DATE('22-FEB-1981', 'DD-MON-YYYY'), 1250, 500, 30);
INSERT INTO EMP VALUES(7566, 'JONES', 'MANAGER', 7839,TO_DATE('2-APR-1981', 'DD-MON-YYYY'), 2975, NULL, 20);
INSERT INTO EMP VALUES(7654, 'MARTIN', 'SALESMAN', 7698,TO_DATE('28-SEP-1981', 'DD-MON-YYYY'), 1250, 1400, 30);
INSERT INTO EMP VALUES(7698, 'BLAKE', 'MANAGER', 7839,TO_DATE('1-MAY-1981', 'DD-MON-YYYY'), 2850, NULL, 30);
INSERT INTO EMP VALUES(7782, 'CLARK', 'MANAGER', 7839,TO_DATE('9-JUN-1981', 'DD-MON-YYYY'), 2450, NULL, 10);
INSERT INTO EMP VALUES(7788, 'SCOTT', 'ANALYST', 7566,TO_DATE('09-DEC-1982', 'DD-MON-YYYY'), 3000, NULL, 20);
INSERT INTO EMP VALUES(7839, 'KING', 'PRESIDENT', NULL,TO_DATE('17-NOV-1981', 'DD-MON-YYYY'), 5000, NULL, 10);
INSERT INTO EMP VALUES(7844, 'TURNER', 'SALESMAN', 7698,TO_DATE('8-SEP-1981', 'DD-MON-YYYY'), 1500, 0, 30);
INSERT INTO EMP VALUES(7876, 'ADAMS', 'CLERK', 7788,TO_DATE('12-JAN-1983', 'DD-MON-YYYY'), 1100, NULL, 20);
INSERT INTO EMP VALUES(7900, 'JAMES', 'CLERK', 7698,TO_DATE('3-DEC-1981', 'DD-MON-YYYY'), 950, NULL, 30);
INSERT INTO EMP VALUES(7902, 'FORD', 'ANALYST', 7566,TO_DATE('3-DEC-1981', 'DD-MON-YYYY'), 3000, NULL, 20);
INSERT INTO EMP VALUES(7934, 'MILLER', 'CLERK', 7782,TO_DATE('23-JAN-1982', 'DD-MON-YYYY'), 1300, NULL, 10);
CREATE TABLE BONUS
(ENAME VARCHAR2(10),
JOB VARCHAR2(9),
SAL NUMBER,
COMM NUMBER);
comment on table BONUS is '奖金表';
comment on column BONUS.ENAME is '雇员姓名';
comment on column BONUS.JOB is '雇员职位';
comment on column BONUS.SAL is '雇员的工资';
comment on column BONUS.COMM is '雇员的奖金';
CREATE TABLE SALGRADE
(GRADE NUMBER,
LOSAL NUMBER,
HISAL NUMBER);
comment on table SALGRADE is '工资等级表';
comment on column SALGRADE.GRADE is '工资的等级';
comment on column SALGRADE.LOSAL is '此等级的最低工资';
comment on column SALGRADE.HISAL is '此等级的最高工资';
INSERT INTO SALGRADE VALUES (1, 700, 1200);
INSERT INTO SALGRADE VALUES (2, 1201, 1400);
INSERT INTO SALGRADE VALUES (3, 1401, 2000);
INSERT INTO SALGRADE VALUES (4, 2001, 3000);
INSERT INTO SALGRADE VALUES (5, 3001, 9999);
COMMIT;
-- 2 Mysql 版本
DROP TABLE IF EXISTS emp;
DROP TABLE IF EXISTS dept;
DROP TABLE IF EXISTS bonus;
DROP TABLE IF EXISTS salgrade;
create table dept(
deptno int unsigned auto_increment COMMENT '部门编号',
dname varchar(15) COMMENT '部门名称',
loc varchar(50) COMMENT '部门所在位置',
primary key(deptno)
) COMMENT='部门表';
INSERT INTO dept VALUES (10,'ACCOUNTING','NEW YORK');
INSERT INTO dept VALUES (20,'RESEARCH','DALLAS');
INSERT INTO dept VALUES (30,'SALES','CHICAGO');
INSERT INTO dept VALUES (40,'OPERATIONS','BOSTON');
create table emp(
empno int unsigned auto_increment COMMENT '雇员编号',
ename varchar(15) COMMENT '雇员姓名',
job varchar(10) COMMENT '雇员职位',
mgr int unsigned COMMENT '雇员对应的领导的编号',
hiredate date COMMENT '雇员的雇佣日期',
sal decimal(7,2) COMMENT '雇员的基本工资',
comm decimal(7,2) COMMENT '奖金',
deptno int unsigned COMMENT '所在部门',
primary key(empno),
foreign key(deptno) references dept(deptno)
) COMMENT='雇员表';
INSERT INTO emp VALUES (7369,'SMITH','CLERK',7902,'1980-12-17',800,NULL,20);
INSERT INTO emp VALUES (7499,'ALLEN','SALESMAN',7698,'1981-2-20',1600,300,30);
INSERT INTO emp VALUES (7521,'WARD','SALESMAN',7698,'1981-2-22',1250,500,30);
INSERT INTO emp VALUES (7566,'JONES','MANAGER',7839,'1981-4-2',2975,NULL,20);
INSERT INTO emp VALUES (7654,'MARTIN','SALESMAN',7698,'1981-9-28',1250,1400,30);
INSERT INTO emp VALUES (7698,'BLAKE','MANAGER',7839,'1981-5-1',2850,NULL,30);
INSERT INTO emp VALUES (7782,'CLARK','MANAGER',7839,'1981-6-9',2450,NULL,10);
INSERT INTO emp VALUES (7788,'SCOTT','ANALYST',7566,'87-7-13',3000,NULL,20);
INSERT INTO emp VALUES (7839,'KING','PRESIDENT',NULL,'1981-11-17',5000,NULL,10);
INSERT INTO emp VALUES (7844,'TURNER','SALESMAN',7698,'1981-9-8',1500,0,30);
INSERT INTO emp VALUES (7876,'ADAMS','CLERK',7788,'87-7-13',1100,NULL,20);
INSERT INTO emp VALUES (7900,'JAMES','CLERK',7698,'1981-12-3',950,NULL,30);
INSERT INTO emp VALUES (7902,'FORD','ANALYST',7566,'1981-12-3',3000,NULL,20);
INSERT INTO emp VALUES (7934,'MILLER','CLERK',7782,'1982-1-23',1300,NULL,10);
create table salgrade(
grade int unsigned COMMENT '工资等级',
losal int unsigned COMMENT '此等级的最低工资',
hisal int unsigned COMMENT '此等级的最高工资'
) COMMENT='工资等级表';
INSERT INTO salgrade VALUES (1,700,1200);
INSERT INTO salgrade VALUES (2,1201,1400);
INSERT INTO salgrade VALUES (3,1401,2000);
INSERT INTO salgrade VALUES (4,2001,3000);
INSERT INTO salgrade VALUES (5,3001,9999);
create table bonus(
ename varchar(10) COMMENT '雇员姓名',
job varchar(9) COMMENT '雇员职位',
sal decimal(7,2) COMMENT '雇员工资',
comm decimal(7,2) COMMENT '雇员资金'
) COMMENT='奖金表';
-- 3 SQL Server版本
IF EXISTS(Select 1 From Sysobjects Where Name='emp') --查询表名costSeparateConfig是否存在
DROP table emp; --存在则删除
IF EXISTS(Select 1 From Sysobjects Where Name='dept')
DROP table dept;
IF EXISTS(Select 1 From Sysobjects Where Name='bonus')
DROP table bonus ;
IF EXISTS(Select 1 From Sysobjects Where Name='salgrade')
DROP table salgrade;
GO
create table dept(
deptno int IDENTITY(1,1) NOT NULL,
dname varchar(15),
loc varchar(50),
primary key(deptno)
);
EXECUTE sp_addextendedproperty N'MS_Description', N'部门表', N'user', N'dbo', N'table', N'dept', NULL, NULL
EXECUTE sp_addextendedproperty N'MS_Description', N'部门编号', N'user', N'dbo', N'table', N'dept', N'column', N'deptno'
EXECUTE sp_addextendedproperty N'MS_Description', N'部门名称', N'user', N'dbo', N'table', N'dept', N'column', N'dname'
EXECUTE sp_addextendedproperty N'MS_Description', N'部门所在位置', N'user', N'dbo', N'table', N'dept', N'column', N'loc'
-- set IDENTITY_INSERT dept on
SET IDENTITY_INSERT dbo.dept ON;
INSERT INTO dept(deptno,dname,loc) VALUES (10,'ACCOUNTING','NEW YORK');
INSERT INTO dept(deptno,dname,loc) VALUES (20,'RESEARCH','DALLAS');
INSERT INTO dept(deptno,dname,loc) VALUES (30,'SALES','CHICAGO');
INSERT INTO dept(deptno,dname,loc) VALUES (40,'OPERATIONS','BOSTON');
set IDENTITY_INSERT dbo.dept OFF;
create table emp(
empno int IDENTITY(1,1) NOT NULL,
ename varchar(15),
job varchar(10),
mgr int ,
hiredate date,
sal decimal(7,2),
comm decimal(7,2),
deptno int,
primary key(empno),
foreign key(deptno) references dept(deptno)
);
EXECUTE sp_addextendedproperty N'MS_Description', N'雇员表', N'user', N'dbo', N'table', N'emp', NULL, NULL
EXECUTE sp_addextendedproperty N'MS_Description', N'雇员编号', N'user', N'dbo', N'table', N'emp', N'column', N'empno'
EXECUTE sp_addextendedproperty N'MS_Description', N'雇员名称', N'user', N'dbo', N'table', N'emp', N'column', N'ename'
EXECUTE sp_addextendedproperty N'MS_Description', N'雇员职位', N'user', N'dbo', N'table', N'emp', N'column', N'job'
EXECUTE sp_addextendedproperty N'MS_Description', N'雇员对应的领导的编号', N'user', N'dbo', N'table', N'emp', N'column', N'mgr'
EXECUTE sp_addextendedproperty N'MS_Description', N'雇员的雇佣日期', N'user', N'dbo', N'table', N'emp', N'column', N'hiredate'
EXECUTE sp_addextendedproperty N'MS_Description', N'雇员的基本工资', N'user', N'dbo', N'table', N'emp', N'column', N'sal'
EXECUTE sp_addextendedproperty N'MS_Description', N'奖金', N'user', N'dbo', N'table', N'emp', N'column', N'comm'
EXECUTE sp_addextendedproperty N'MS_Description', N'所在部门', N'user', N'dbo', N'table', N'emp', N'column', N'deptno'
set IDENTITY_INSERT emp on;
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7369,'SMITH','CLERK',7902,'1980-12-17',800,NULL,20);
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7499,'ALLEN','SALESMAN',7698,'1981-2-20',1600,300,30);
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7521,'WARD','SALESMAN',7698,'1981-2-22',1250,500,30);
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7566,'JONES','MANAGER',7839,'1981-4-2',2975,NULL,20);
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7654,'MARTIN','SALESMAN',7698,'1981-9-28',1250,1400,30);
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7698,'BLAKE','MANAGER',7839,'1981-5-1',2850,NULL,30);
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7782,'CLARK','MANAGER',7839,'1981-6-9',2450,NULL,10);
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7788,'SCOTT','ANALYST',7566,'1987-7-13',3000,NULL,20);
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7839,'KING','PRESIDENT',NULL,'1981-11-17',5000,NULL,10);
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7844,'TURNER','SALESMAN',7698,'1981-9-8',1500,0,30);
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7876,'ADAMS','CLERK',7788,'1987-7-13',1100,NULL,20);
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7900,'JAMES','CLERK',7698,'1981-12-3',950,NULL,30);
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7902,'FORD','ANALYST',7566,'1981-12-3',3000,NULL,20);
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (7934,'MILLER','CLERK',7782,'1982-1-23',1300,NULL,10);
SET IDENTITY_INSERT emp OFF;
create table salgrade(
grade int,
losal int,
hisal int
) ;
EXECUTE sp_addextendedproperty N'MS_Description', N'工资等级表', N'user', N'dbo', N'table', N'salgrade', NULL, NULL
EXECUTE sp_addextendedproperty N'MS_Description', N'工资等级', N'user', N'dbo', N'table', N'salgrade', N'column', N'grade'
EXECUTE sp_addextendedproperty N'MS_Description', N'此等级的最低工资', N'user', N'dbo', N'table', N'salgrade', N'column', N'losal'
EXECUTE sp_addextendedproperty N'MS_Description', N'此等级的最高工资', N'user', N'dbo', N'table', N'salgrade', N'column', N'hisal'
INSERT INTO salgrade VALUES (1,700,1200);
INSERT INTO salgrade VALUES (2,1201,1400);
INSERT INTO salgrade VALUES (3,1401,2000);
INSERT INTO salgrade VALUES (4,2001,3000);
INSERT INTO salgrade VALUES (5,3001,9999);
create table bonus(
ename varchar(10),
job varchar(9),
sal decimal(7,2),
comm decimal(7,2)
);
EXECUTE sp_addextendedproperty N'MS_Description', N'奖金表', N'user', N'dbo', N'table', N'bonus', NULL, NULL
EXECUTE sp_addextendedproperty N'MS_Description', N'雇员姓名', N'user', N'dbo', N'table', N'bonus', N'column', N'ename'
EXECUTE sp_addextendedproperty N'MS_Description', N'雇员职位', N'user', N'dbo', N'table', N'bonus', N'column', N'job'
EXECUTE sp_addextendedproperty N'MS_Description', N'雇员工资', N'user', N'dbo', N'table', N'bonus', N'column', N'sal'
EXECUTE sp_addextendedproperty N'MS_Description', N'雇员资金', N'user', N'dbo', N'table', N'bonus', N'column', N'comm'
员工关系表
7.2.1 从表中查询所有行和列
需求:检索表里所有行的数据。
解决方法:通过SQL的关键字*来匹配到所有行和列,结合SELECT FROM 即可满足需求。
Oracle、Sql server、Mysql:
SELECT *
FROM emp;
等价于:
SELECT empno,ename,job,mgr,hiredate,sal,comm,deptno FROM emp;
执行结果:
empno | ename | job | mgr | hiredate | sal | comm | deptno |
7369 | SMITH | CLERK | 7902 | 1980/12/17 0:00:00 | 800.00 | 20 | |
7499 | ALLEN | SALESMAN | 7698 | 1981/2/20 0:00:00 | 1600.00 | 300.00 | 30 |
7521 | WARD | SALESMAN | 7698 | 1981/2/22 0:00:00 | 1250.00 | 500.00 | 30 |
7566 | JONES | MANAGER | 7839 | 1981/4/2 0:00:00 | 2975.00 | 20 | |
7654 | MARTIN | SALESMAN | 7698 | 1981/9/28 0:00:00 | 1250.00 | 1400.00 | 30 |
7698 | BLAKE | MANAGER | 7839 | 1981/5/1 0:00:00 | 2850.00 | 30 | |
7782 | CLARK | MANAGER | 7839 | 1981/6/9 0:00:00 | 2450.00 | 10 | |
7788 | SCOTT | ANALYST | 7566 | 1987/7/13 0:00:00 | 3000.00 | 20 | |
7839 | KING | PRESIDENT | 1981/11/17 0:00:00 | 5000.00 | 10 | ||
7844 | TURNER | SALESMAN | 7698 | 1981/9/8 0:00:00 | 1500.00 | 0.00 | 30 |
7876 | ADAMS | CLERK | 7788 | 1987/7/13 0:00:00 | 1100.00 | 20 | |
7900 | JAMES | CLERK | 7698 | 1981/12/3 0:00:00 | 950.00 | 30 | |
7902 | FORD | ANALYST | 7566 | 1981/12/3 0:00:00 | 3000.00 | 20 | |
7934 | MILLER | CLERK | 7782 | 1982/1/23 0:00:00 | 1300.00 | 10 |
7.2.2 从表中查询部分行
需求:查询雇员表emp里员工号是7782的员工的详细信息。
解决方法:先找出emp表的员工号的字段名,再结合SELECT FROM WHERE来实现。其中这里通过where关键字来限制检索的行。
Oracle、Sql server、Mysql:
SELECT *
FROM emp
WHERE empno = 7782;
执行结果:
empno | ename | job | mgr | hiredate | sal | comm | deptno |
7782 | CLARK | MANAGER | 7839 | 1981/6/9 0:00:00 | 2450.00 | 10 |
7.2.3 查询满足某个条件行
需求:查询雇员表emp中所有的部门号等于10的行。
解决方法:先找出emp表的部门号的字段名,再结合SELECT FROM WHERE来实现。其中的WHERE即是在加过滤条件,多部门表进行筛选,只取部门号为10的数据。
Oracle、Sql server、Mysql:
SELECT *
FROM emp
WHERE deptno = 10;
执行结果:
empno | ename | job | mgr | hiredate | sal | comm | deptno |
7782 | CLARK | MANAGER | 7839 | 1981/6/9 0:00:00 | 2450.00 | 10 | |
7839 | KING | PRESIDENT | 1981/11/17 0:00:00 | 5000.00 | 10 | ||
7934 | MILLER | CLERK | 7782 | 1982/1/23 0:00:00 | 1300.00 | 10 |
注:
1 这里字段的判断支持诸如不等于(“<>”)、等于(“=”),大于(“>”)、小于(“<”) 、,
大于等于(“>=”)、小于等于(“<=”),不等(“!”)等关系比较符。
2 上述的比较符对表字段的类型有要求,一般适用于数值类型。
3 当然我们也可以在where之后结合其它条件再过滤,后面会有案例。
7.2.4 从表中查询部分列
需求:查询雇员表emp中所有的员工编号、员工名称、职位情况。
解决方法:先找出emp表的工编号、员工名称、职位对应的字段名,再结合SELECT FROM 即可满足需求。
Oracle、Sql server、Mysql:
SELECT empno,ename,job
FROM emp;
执行结果:
empno | ename | job |
7369 | SMITH | CLERK |
7499 | ALLEN | SALESMAN |
7521 | WARD | SALESMAN |
7566 | JONES | MANAGER |
7654 | MARTIN | SALESMAN |
7698 | BLAKE | MANAGER |
7782 | CLARK | MANAGER |
7788 | SCOTT | ANALYST |
7839 | KING | PRESIDENT |
7844 | TURNER | SALESMAN |
7876 | ADAMS | CLERK |
7900 | JAMES | CLERK |
7902 | FORD | ANALYST |
7934 | MILLER | CLERK |
7.2.5 给字段取个有意义的名字
需求:查询雇员表emp里部门编号是10的员工编号、员工名称、职位情况,并给员工编号起个别名“员工号”,给员工名称起个别名“员工名”,给职位起个名字“职位名”。
解决方法:先找出emp表的工编号、员工名称、职位对应的字段名,再结合SELECT column as “别名”FROM table的方式解决。
Oracle、Sql server、Mysql:
SELECT empno as "员工号",ename as"员工名",job as"职位名"
FROM emp
WHERE deptno =10;
也可以省略掉as写成如下的:
SELECT empno "员工号",ename "员工名",job "职位名"
FROM emp
WHERE deptno =10;
执行结果:
员工号 | 员工名 | 职位名 |
7782 | CLARK | MANAGER |
7839 | KING | PRESIDENT |
7934 | MILLER | CLERK |
注: 这里为了演示,将字段名起个别名是中文, 一般情况下不会这么做。因为表名或者字段是用英文定义的,如果名字比较长了或者不好理解,可以起个别名代替。比如有个表叫employee,可以起个别名emp,这个表里有个字段叫salary,可以起个别名叫sal。
一般我们这么写:
SELECT empno as id,sal salary,comm commission
FROM emp
WHERE deptno = 10;
7.2.6 结合where使用别名
需求:查询雇员表emp里工资大于3000的员工编号、员工名称、职位、工资情况,并以工资的别名“salary”进行过滤。
解决方法:先找出emp表的工编号、员工名称、职位、工资对应的字段名分别为empno、ename、job、sal,结合SELECT column as “别名”FROM table的方式给字段sal起个别名salary,这里需要用个只是,内敛表,即将查询的结果集用“()”包裹起来起个别名,也可以理解成用个虚拟的表。再在这个内敛表的基础上过滤salary大于3000的记录即可。
Oracle、Sql server、Mysql:
SELECT * FROM
(
SELECT empno,ename,job,sal salary
FROM emp
)X
WHERE salary>3000
执行结果:
empno | ename | job | salary |
7839 | KING | PRESIDENT | 5000.00 |
7.2.7 拼接列的值
需求:查询雇员表emp里部门编号是10员工信息,以员工名称“’job title is”职位的形式输出。示例:KING’s job title is PRESIDENT
解决方法:首先定位到emp表和涉及到字段员工名称、职位,再考虑两列的拼接,选择字符串函数或则“+”完成,最后加上where条件过滤部门编号等于10。这里不同的数据库实现方法不同。以下分别来讲。
Mysql:
SELECT concat(ename,"'s job title is:",job) as EnameConn
FROM emp
WHERE deptno =10;
Sql server:
SELECT ename+'''s job title is:'+job as EnameConn
FROM emp
Oracle:
SELECT ename||'''s job title is:'||job as EnameConn
FROM emp
执行结果:
EnameConn |
CLARK's job title is:MANAGER |
KING's job title is:PRESIDENT |
MILLER's job title is:CLERK |
7.2.8 查询语句里执行条件判断
需求:查询雇员表emp里的员工名称、工资、工资分类状态。这里的工资分类状态按照以下规则显示:如果工资小于等于2000则显示UNDERPAID(即报酬比较低的),如果工资大于4000时显示OVERPAID(即报酬较高),其它情况显示NORMAL(正常水平)。
解决方法:首先定位到emp表和涉及到字段员工名称、工资,再考虑考虑到工资状态是个计算出来的列,所以先梳理工资分类状态这个“列”的逻辑,跟表里的工资字段有关,这里是做 if else判断,注意到纯SQL里没有if else,但有case when,所以我们选取这个关键字。case when 条件1 then value1 case when 条件2 then value2 else value3 end as 别名。
Mysql、SQL server、Oracle:
SELECT ENAME,SAL,
CASE WHEN SAL <=2000 THEN 'UNDERPAID'
WHEN SAL > 2000 THEN 'OVERPAID'
ELSE 'NORMAL' END AS STATUS
FROM emp
执行结果:
ENAME | SAL | STATUS |
SMITH | 800.00 | UNDERPAID |
ALLEN | 1600.00 | UNDERPAID |
WARD | 1250.00 | UNDERPAID |
JONES | 2975.00 | OVERPAID |
MARTIN | 1250.00 | UNDERPAID |
BLAKE | 2850.00 | OVERPAID |
CLARK | 2450.00 | OVERPAID |
SCOTT | 3000.00 | OVERPAID |
KING | 5000.00 | OVERPAID |
TURNER | 1500.00 | UNDERPAID |
ADAMS | 1100.00 | UNDERPAID |
JAMES | 950.00 | UNDERPAID |
FORD | 3000.00 | OVERPAID |
MILLER | 1300.00 | UNDERPAID |
注:case when还可以如下方式编写:
select ename,sal,job,
case job when 'CLERK' then '小职员'
when 'SALESMAN' then '销售员'
when 'MANAGER' then '经理'
when 'ANALYST' then '分析师'
when 'PRESIDENT' then '董事长'
else "其它"
end as jobtitle
from emp
执行结果:
ename | sal | job | jobtitle |
SMITH | 800.00 | CLERK | 小职员 |
ALLEN | 1600.00 | SALESMAN | 销售员 |
WARD | 1250.00 | SALESMAN | 销售员 |
JONES | 2975.00 | MANAGER | 经理 |
MARTIN | 1250.00 | SALESMAN | 销售员 |
BLAKE | 2850.00 | MANAGER | 经理 |
CLARK | 2450.00 | MANAGER | 经理 |
SCOTT | 3000.00 | ANALYST | 分析师 |
KING | 5000.00 | PRESIDENT | 董事长 |
TURNER | 1500.00 | SALESMAN | 销售员 |
ADAMS | 1100.00 | CLERK | 小职员 |
JAMES | 950.00 | CLERK | 小职员 |
FORD | 3000.00 | ANALYST | 分析师 |
MILLER | 小职员 |
这种case 字段A when value1的方式适合字段有可穷举的情况,而case when 字段条件A则比这种更灵活。
7.2.9 返回的字段在某个范围内的数据
需求:查询雇员表emp里部门编号在10和30的部门编号、雇员名称、职位名称。
解决方法:使用数据库里IN关键字来限制员工表里的deptno。
Mysql、Sql server、Oracle:
SELECT ename,job
FROM emp
WHERE deptno IN (20,30)
执行结果:
ename | job | deptno |
SMITH | CLERK | 20 |
ALLEN | SALESMAN | 30 |
WARD | SALESMAN | 30 |
JONES | MANAGER | 20 |
MARTIN | SALESMAN | 30 |
BLAKE | MANAGER | 30 |
SCOTT | ANALYST | 20 |
TURNER | SALESMAN | 30 |
ADAMS | CLERK | 20 |
JAMES | CLERK | 30 |
FORD | ANALYST | 20 |
7.2.10 通过多条件组合返回数据
需求:查询雇员表emp里部门编号在10和30且职位是经理“MANAGER”的的雇员名称、职位名称。
解决方法:使用数据库里IN关键字来限制员工表里的deptno。
Mysql、Sql server、Oracle:
SELECT ename,job
FROM emp
WHERE deptno IN (20,30) AND job='MANAGER'
执行结果:
ename | job |
JONES | MANAGER |
BLAKE | MANAGER |
注: 这里字段的逻辑条件里常用的有and、or,注意这里的优先级,如果想改变优先级,可以通过“()”来改变。
7.2.11 限制返回的行数
需求:查询5条雇员表emp里的雇员信息。
解决方法:使用数据库里内置的限制行数返回的函数来解决。
Mysql:
SELECT *
FROM emp limit 5;
Sql server:
SELECT TOP 5 *
FROM emp;
Oracle:
SELECT *
FROM emp
WHERE rownum <=5
执行结果:
empno | ename | job | mgr | hiredate | sal | comm | deptno |
7369 | SMITH | CLERK | 7902 | 1980/12/17 0:00:00 | 800.00 | 20 | |
7499 | ALLEN | SALESMAN | 7698 | 1981/2/20 0:00:00 | 1600.00 | 300.00 | 30 |
7521 | WARD | SALESMAN | 7698 | 1981/2/22 0:00:00 | 1250.00 | 500.00 | 30 |
7566 | JONES | MANAGER | 7839 | 1981/4/2 0:00:00 | 2975.00 | 20 | |
7654 | MARTIN | SALESMAN | 7698 | 1981/9/28 0:00:00 | 1250.00 | 1400.00 | 30 |
7.2.12 从表中随机返回N条记录
需求:从雇员表emp里随机查询5条雇员的名称和工资信息。
解决方法:使用数据库里内置的限制行数函数结合随机函数来解决。
Mysql:
SELECT ename,sal
FROM emp
order by rand() limit 5;
Sql server:
SELECT TOP 5 ename,sal
FROM emp
ORDER BY NEWID()
注: newid是SQL Server里的内置函数,因为newid()返回的是uniqueidentifier类型的唯一值,而且每次生成的值都不一样,所以能达到随机的效果。
Oracle:
SELECT * FROM
(
SELECT ename,sal
FROM emp
ORDER BY Dbms_Random.value()
)
WHERE rownum <=5
注: dbms_random是一个可以生成随机数值或者字符串的程序包。这个包有initialize()、seed()、terminate()、value()、normal()、random()、string()等几个函数,但返回随机值的函数value()是最常用的。
你可以直接访问这个随机数字的函数,它返回个0到1之间的一个小数。
SELECT Dbms_Random.value() AS RAND_VALUE
FROM DUAL;
执行结果:
RAND_VALUE |
0.151493981662762 |
如果想生成1-100之间的随机数,你可以这么做:
SELECT TRUNC(Dbms_Random.value()*100)AS RAND_VALUE
FROM DUAL;
执行结果:
RAND_VALUE |
42 |
7.2.13 从表中查询空值
需求:从雇员表emp里查询所有奖金为空的员工名称、工资信息和奖金信息。
解决方法:首先找到该段逻辑的涉及到的表名和字段名,emp表,字段ename,sal,comm,使用IS NULL关键字来来解决,这里的NULL是描述数据的特殊值,即不明确该值是什么,区别于空字符串“''”,空字符串不等于NULL。
Mysql、Sql server、Oracle:
SELECT ename,sal,comm
FROM emp
WHERE comm IS NULL
执行结果:
ename | sal | comm |
SMITH | 800.00 | |
JONES | 2975.00 | |
BLAKE | 2850.00 | |
CLARK | 2450.00 | |
SCOTT | 3000.00 | |
KING | 5000.00 | |
ADAMS | 1100.00 | |
JAMES | 950.00 | |
FORD | 3000.00 | |
MILLER | 1300.00 |
7.2.14 返回不重复的记录
需求:从雇员表emp里查询所有不重复的职位信息。
解决方法:这里用到SQL的DISTINCT关键字,即对重复的记录进行去重。
Mysql、Sql server、Oracle:
SELECT DISTINCT JOB
FROM emp
执行结果:
JOB |
CLERK |
SALESMAN |
MANAGER |
ANALYST |
PRESIDENT |
7.2.15 将空值转成其它值
需求:从雇员表emp里查询所有奖金为空的员工名称、工资信息和奖金信息。这里如果奖金为空则转为0。
解决方法:首先找到该段逻辑的涉及到的表名和字段名,emp表,字段ename,sal,comm,使用IS NULL关键字来来解决,如果comm为null则转为0 如果不是null则返回本身。
Mysql、Sql Server、Oracle:
SELECT ename,sal,
case WHEN comm IS NULL THEN 0
ELSE comm
END AS comm
FROM emp
WHERE comm IS NULL
执行结果:
ename | sal | comm |
SMITH | 800.00 | 0 |
JONES | 2975.00 | 0 |
BLAKE | 2850.00 | 0 |
CLARK | 2450.00 | 0 |
SCOTT | 3000.00 | 0 |
KING | 5000.00 | 0 |
ADAMS | 1100.00 | 0 |
JAMES | 950.00 | 0 |
FORD | 3000.00 | 0 |
MILLER | 1300.00 | 0 |
或者用下面的方法,这里每个数据库里的函数名各不同:
Mysql:
SELECT ename,sal,
ROUND(IFNULL(comm,0))as comm
FROM emp
WHERE comm IS NULL
Sql Server:
SELECT ename,sal,
ISNULL(comm,0)AS comm
FROM emp
WHERE comm IS NULL
Oracle:
SELECT ename,sal,
NVL(comm,0) AS comm
FROM emp
WHERE comm IS NULL
7.2.16 按照某个模式搜索
需求:从雇员表emp里查询部门号是10或者20的员工名称,职位信息,他们要么员工名称里含有“I”要么他们的职位以“ER”结尾。
解决方法:这里用到SQL的关键字“%”,注意如果字段里以“%匹配关键字%”则会匹配“匹配关键字”在字段里的任何地方,同理如果是“匹配关键字%”则是以“匹配关键字”开头来匹配字段,而“%匹配关键字”则是匹配以“匹配关键字”结尾来匹配字段。
Mysql、Sqlserver、Oracle:
SELECT ename,job
FROM emp
WHERE deptno IN(10,20)
AND (ename LIKE '%I%' OR job LIKE '%ER')
执行结果:
ename | job |
SMITH | CLERK |
JONES | MANAGER |
CLARK | MANAGER |
KING | PRESIDENT |
MILLER | CLERK |
7.2.17 按照指定的次序返回查询结果
需求:从雇员表emp里查询所有的员工名称,职位,奖金信息,这里要求奖金不为空的排在前面。
解决方法:这里用到SQL的关键字 ORDER BY 以及ASC和DESC,order by是指定以某个或者某些字段排序,asc是指代以字母顺序排列而desc则是以字母降序排列。
Mysql、SqlServer:
SELECT ename,job,comm
FROM emp
order by comm
执行结果:
ename | job | comm |
SMITH | CLERK | |
JONES | MANAGER | |
BLAKE | MANAGER | |
CLARK | MANAGER | |
SCOTT | ANALYST | |
KING | PRESIDENT | |
ADAMS | CLERK | |
JAMES | CLERK | |
FORD | ANALYST | |
MILLER | CLERK | |
TURNER | SALESMAN | 0.00 |
ALLEN | SALESMAN | 300.00 |
WARD | SALESMAN | 500.00 |
MARTIN | SALESMAN | 1400.00 |
Oracle:
SELECT ename,job,comm
FROM emp
order by comm
执行结果:
ENAME | JOB | COMM |
TURNER | SALESMAN | 0.00 |
ALLEN | SALESMAN | 300.00 |
WARD | SALESMAN | 500.00 |
MARTIN | SALESMAN | 1400.00 |
SCOTT | ANALYST | |
KING | PRESIDENT | |
ADAMS | CLERK | |
JAMES | CLERK | |
FORD | ANALYST | |
MILLER | CLERK | |
BLAKE | MANAGER | |
JONES | MANAGER | |
SMITH | CLERK | |
CLARK | MANAGER |
注:因为Sql Server和Mysql默认以NULL的排在前面,而Oralce则默认以NULL的排在后面。
7.2.18 按照多个字段排序查询结果
需求:从雇员表emp里查询所有的部门编号,员工名称,职位,工资信息,这里要求先以部门编号排序再以工资从高到低排序显示。
解决方法:这里用到SQL的关键字 ORDER BY 以及ASC和DESC,order by是指定以字段deptno字符排序,以工资降序排列。
Mysql、Sql server、Oracle:
SELECT deptno,ename,job,sal
FROM emp
order by deptno,comm desc
执行结果:
deptno | ename | job | sal |
10 | CLARK | MANAGER | 2450.00 |
10 | KING | PRESIDENT | 5000.00 |
10 | MILLER | CLERK | 1300.00 |
20 | SMITH | CLERK | 800.00 |
20 | JONES | MANAGER | 2975.00 |
20 | SCOTT | ANALYST | 3000.00 |
20 | ADAMS | CLERK | 1100.00 |
20 | FORD | ANALYST | 3000.00 |
30 | MARTIN | SALESMAN | 1250.00 |
30 | WARD | SALESMAN | 1250.00 |
30 | ALLEN | SALESMAN | 1600.00 |
30 | TURNER | SALESMAN | 1500.00 |
30 | BLAKE | MANAGER | 2850.00 |
30 | JAMES | CLERK | 950.00 |
7.2.19 按照字符串对结果排序
需求:从雇员表emp里查询所有的部门编号,员工名称,职位,工资信息,职位的后两位信息,这里要求截取job字段里的最后两位来排序。
解决方法:这里用到SQL的字符串截取函数再结合order by来对结果进行排序。
Mysql:
SELECT deptno,ename,job,sal,substring(job,length(job)-1) AS last2word
FROM emp
order by last2word
Oracle:
SELECT deptno,ename,job,sal,substr(job,length(job)-1) AS last2word
FROM emp
order by last2word
Sql serer:
SELECT deptno,ename,job,sal,substring(job,len(job)-1,2) AS last2word
FROM emp
order by last2word
执行结果:
deptno | ename | job | sal | last2word |
30 | ALLEN | SALESMAN | 1600.00 | AN |
30 | WARD | SALESMAN | 1250.00 | AN |
30 | MARTIN | SALESMAN | 1250.00 | AN |
30 | TURNER | SALESMAN | 1500.00 | AN |
20 | JONES | MANAGER | 2975.00 | ER |
30 | BLAKE | MANAGER | 2850.00 | ER |
10 | CLARK | MANAGER | 2450.00 | ER |
10 | KING | PRESIDENT | 5000.00 | NT |
20 | SMITH | CLERK | 800.00 | RK |
20 | ADAMS | CLERK | 1100.00 | RK |
30 | JAMES | CLERK | 950.00 | RK |
10 | MILLER | CLERK | 1300.00 | RK |
20 | SCOTT | ANALYST | 3000.00 | ST |
20 | FORD | ANALYST | 3000.00 | ST |
7.2.20 按照字符串数字组合的排序
需求:假设我们从雇员表emp里创建个视图,这里仅有一个字段,该字段叫data由员工名称和部门号拼接而成,我们想实现一个查询可以按照原来的部门编号逆序排序筛选出数据。
解决方法:这里没有真正创建视图,因为用户权限问题,而是建了个表叫做tmp_v。字段拼接生成新字段见上面章节。这里要通过数据库里的translate和repacle结合来实现这个功能。
注:SQL Server、Mysql里参照网上实现了translate函数,详细见下。
Oracle:
create table tmp_v
as SELECT ename||' '|| deptno as data
from emp;
SELECT data,replace(translate(data,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','@@@@@@@@@@@@@@@@@@@@@@@@@@'),'@','') as deptno FROM tmp_v
order by replace(translate(data,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','@@@@@@@@@@@@@@@@@@@@@@@@@@'),'@','') desc
执行结果:
DATA | DEPTNO |
BLAKE 30 | 30 |
TURNER 30 | 30 |
ALLEN 30 | 30 |
MARTIN 30 | 30 |
WARD 30 | 30 |
JAMES 30 | 30 |
SCOTT 20 | 20 |
JONES 20 | 20 |
SMITH 20 | 20 |
ADAMS 20 | 20 |
FORD 20 | 20 |
KING 10 | 10 |
MILLER 10 | 10 |
注:
1 因为我们的ename里的名字都是大写的,所以这里translate函数里的第二个参数都是大写的,如果data里是小写的这里自然是小写。
2 translate函数有三个参数,第一个一般是字段名或则字符串的值,第二个是要匹配的字符组合,第三个是要装换成的字符。
3 replace函数一般有三个参数,第一个一般是字段名或则字符串的值,第二个要替换的字段,第三个是要替换成的值。
SQL Server:
可以在SQLServer里实现个自定义个函数叫translate, 参考至http://blog.sina.com.cn/s/blog_95cfa64601018akj.html具体实现见下:
SET ANSI_NULLSON
GO
SET QUOTED_IDENTIFIERON
GO
CREATE FUNCTION [dbo].[translate](
@string VARCHAR(MAX),
@from_str VARCHAR(MAX),
@to_str VARCHAR(MAX)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
-- 返回将(所有出现的)from_str中的每个字符替换为to_str中的相应字符以后的string。
-- TRANSLATE是 REPLACE所提供的功能的一个超集。
-- 如果 from_str比 to_str 长,那么在 from_str 中而不在 to_str 中的额外字符将从 string 中被删除,因为它们没有相应的替换字符。
-- to_str不能为空。
-- Oracle将空字符串解释为 NULL,并且如果TRANSLATE 中的任何参数为NULL,那么结果也是 NULL。
IF @string IS NULL OR @from_strISNULLOR @to_strISNULL
BEGIN
RETURN NULL;
END;
-- 源长度与目标长度
DECLARE @FromLen INT, @ToLen INT;
SET @FromLen = LEN(@from_str);
SET @ToLen = LEN(@to_str);
-- 准备用于返回的数值.
DECLARE @resultVal VARCHAR(MAX);
SET @resultVal =@string;
-- 用于存储 本次需要替换的字符信息.
DECLARE @thisTimeReplace CHAR(1);
-- 从后向前依次替换.
WHILE @FromLen > 0
BEGIN
-- 取得本次即将要替换的字符.
SET @thisTimeReplace =SUBSTRING(@from_str, @FromLen, 1);
IF CHARINDEX(@thisTimeReplace,@from_str)<@FromLen
BEGIN
-- 假如当前这个要替换的字符,在前面还有,那么这里就不替换了
-- 原因,为了支持
-- SELECT TRANSLATE('2KRW229','1234567890' || '2KRW229', '1234567890')
-- 这样的效果.
-- 向前处理上一个
/*
补充说明:
1 理论上TRANSLATE函数的@from_str参数和@to_str参数的长度要一致,即一一映射。比如@from_str='0123',@to_str='abcd'
2 该步骤旨在找到在@from_str参数里要替换的的字符重复指定了,比如'0123XYZ23',这里23是重复指定了,对于重复指定的要舍弃所以需要在该步时需要将@FromLen锁定到字符Z的位置即7
*/
SET @FromLen =@FromLen - 1;
CONTINUE;
END
IF @FromLen >@ToLen
BEGIN
--from_str 比 to_str长,那么在 from_str 中而不在 to_str 中的额外字符将从 string 中被删除,因为它们没有相应的替换字符。
SET @resultVal =REPLACE(@resultVal,SUBSTRING(@from_str, @FromLen, 1),'');
END
ELSE
BEGIN
-- from_str中的每个字符替换为to_str中的相应字符以后的string
--SELECT dbo.TRANSLATE('2KRW229', '12345678902KRS229','12345678902')这里用S替换时其实无效
SET @resultVal =REPLACE(@resultVal, @thisTimeReplace,SUBSTRING(@to_str, @FromLen, 1));
END;
-- 处理完当前字符后,向前处理上一个.
SET @FromLen =@FromLen - 1;
END;
-- 依次处理完毕后,返回结果.
RETURN @resultVal;
END
create view tmp_v
AS SELECT ename+' '+cast(deptnoasvarchar)as data
from emp;
SELECT data,replace(dbo.translate(data,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','@@@@@@@@@@@@@@@@@@@@@@@@@@'),'@','') as deptno FROM tmp_v
order by replace(dbo.translate(data,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','@@@@@@@@@@@@@@@@@@@@@@@@@@'),'@','')desc
执行结果:
DATA | DEPTNO |
ALLEN 30 | 30 |
WARD 30 | 30 |
MARTIN 30 | 30 |
BLAKE 30 | 30 |
TURNER 30 | 30 |
JAMES 30 | 30 |
FORD 20 | 20 |
SMITH 20 | 20 |
ADAMS 20 | 20 |
SCOTT 20 | 20 |
JONES 20 | 20 |
CLARK 10 | 10 |
KING 10 | 10 |
注: SQL Server 2017里已经有translate函数,见如下示例:
DECLARE @v VARCHAR(100)
SET @v = '123#456*789!/0'
SELECT REPLACE(TRIM(TRANSLATE(@v,'#*!/',' ')),' ','') AS transDemo
transDemo |
1234567890 |
Mysql:
可以在Mysql里实现个自定义个函数叫translate,具体实现见下:
DROP FUNCTION IF EXISTS shenl.translate;
CREATE FUNCTION shenl.`translate`(
stringToTranslate VARCHAR(256),
from_str VARCHAR(256),
to_str VARCHAR(256)) RETURNSvarchar(256)CHARSET utf8
BEGIN
DECLARE resultVal VARCHAR(256);
DECLARE FromLen INT;
DECLARE ToLen INT;
DECLARE thisTimeReplace VARCHAR(1);
SET FromLen = LENGTH(from_str);
SET ToLen = LENGTH(to_str);
SET resultVal = stringToTranslate;
IF stringToTranslate IS NULL OR from_strISNULLOR to_strISNULLTHEN
RETURN NULL;
END IF;
loop_label: LOOP
#因为是从后往前替换,所以FromLen=0时循环要结束了。
IF FromLen<=0THEN
LEAVE loop_label;
END IF;
#from_str里从后往前每次取1个字符
SET thisTimeReplace = SUBSTRING(from_str, FromLen, 1);
#如果在from_str字符串里重复指定了要替换的字符,则舍弃。即如果from_str的值是1234567890fat29,则29是要舍弃掉的。
#即FromLen要锁定到13
IF INSTR(from_str,thisTimeReplace)< FromLen THEN
SET FromLen = FromLen - 1;
ITERATE loop_label;
ELSE
#如果from_str的长度大于ToLen则以ToLen的长度为标准,此时from_str里多提供的字符会被替换为''
IF FromLen > ToLen THEN
SET resultVal = REPLACE(resultVal, SUBSTRING(from_str, FromLen, 1),'');
#如果from_str的长度等于ToLen则以ToLen对应的字符替换from_str里多的字符
ELSE
SET resultVal = REPLACE(resultVal, thisTimeReplace, SUBSTRING(to_str, FromLen, 1));
END IF;
SET FromLen = FromLen - 1;
END IF;
END LOOP;
RETURN resultVal;
END;
create view tmp_v
AS SELECTCONCAT(ename,' ',deptno)as data
from emp;
SELECT data,replace(translate(data,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','@@@@@@@@@@@@@@@@@@@@@@@@@@'),'@','') as deptno
FROM tmp_v
order by replace(translate(data,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','@@@@@@@@@@@@@@@@@@@@@@@@@@'),'@','') desc
执行结果:
data | deptno |
ALLEN 30 | 30 |
MARTIN 30 | 30 |
WARD 30 | 30 |
BLAKE 30 | 30 |
JAMES 30 | 30 |
TURNER 30 | 30 |
SCOTT 20 | 20 |
ADAMS 20 | 20 |
SMITH 20 | 20 |
JONES 20 | 20 |
FORD 20 | 20 |
MILLER 10 | 10 |
KING 10 | 10 |
CLARK 10 | 10 |
7.2.21 处理空值的排序
需求:查询雇员表emp里的员工编号、员工名、奖金信息,这里需要将comm字段为空的排在前面。
解决方法:需要对comm字段进行特殊处理,比如进行转换,然后再排序,而有的数据库可以在排序时指定null的顺序。如oracle里字段排序时可以指定nulls first或则nulls last
Oracle:
SELECT empno,ename,comm
FROM emp
ORDER BY comm nulls first
执行结果:
EMPNO | ENAME | COMM |
7369 | SMITH | |
7782 | CLARK | |
7902 | FORD | |
7900 | JAMES | |
7876 | ADAMS | |
7566 | JONES | |
7698 | BLAKE | |
7934 | MILLER | |
7788 | SCOTT | |
7839 | KING | |
7844 | TURNER | 0.00 |
7499 | ALLEN | 300.00 |
7521 | WARD | 500.00 |
7654 | MARTIN | 1400.00 |
Sql Server:
SELECT empno,ename,CASE WHEN comm IS NULL THEN -1 ELSE comm END AS comm
FROM emp
ORDER BY comm
Mysql:
SELECT empno,ename,CASE WHEN comm IS NULL THEN -1 ELSE comm END AS comm
FROM emp
ORDER BY comm
Sqlserver和Mysql的执行结果见下:
empno | ename | comm |
7369 | SMITH | -1.00 |
7566 | JONES | -1.00 |
7698 | BLAKE | -1.00 |
7782 | CLARK | -1.00 |
7788 | SCOTT | -1.00 |
7839 | KING | -1.00 |
7876 | ADAMS | -1.00 |
7900 | JAMES | -1.00 |
7902 | FORD | -1.00 |
7934 | MILLER | -1.00 |
7844 | TURNER | 0.00 |
7499 | ALLEN | 300.00 |
7521 | WARD | 500.00 |
7654 | MARTIN | 1400.00 |
7.2.22 根据数据项的值排序
需求:查询雇员表emp里的员工编号、员工名、工作信息、奖金信息,这里需要对工作是“MANAGER”和“SALESMAN”的按照comm降序排序其他员工按照员工编号降序排列。
解决方法:这里需要在order by后接case when之类的条件判断以调整排序规则。order by可以跟多个字段,排在前面的规则会被优先应用。
Oracle:
SELECT empno,ename,job,comm
FROM emp
ORDER BY CASE WHEN job IN ('SALESMAN','MANAGER') THEN comm ELSE empno END DESC
执行结果:
EMPNO | ENAME | JOB | COMM |
7782 | CLARK | MANAGER | |
7698 | BLAKE | MANAGER | |
7566 | JONES | MANAGER | |
7934 | MILLER | CLERK | |
7902 | FORD | ANALYST | |
7900 | JAMES | CLERK | |
7876 | ADAMS | CLERK | |
7839 | KING | PRESIDENT | |
7788 | SCOTT | ANALYST | |
7369 | SMITH | CLERK | |
7654 | MARTIN | SALESMAN | 1400.00 |
7521 | WARD | SALESMAN | 500.00 |
7499 | ALLEN | SALESMAN | 300.00 |
7844 | TURNER | SALESMAN | 0.00 |
Sql Server、Mysql:
SELECT empno,ename,job,comm
FROM emp
ORDER BY CASE WHEN job IN('SALESMAN','MANAGER')THEN comm ELSE empno END DESC
执行结果:
empno | ename | job | comm |
7934 | MILLER | CLERK | NULL |
7902 | FORD | ANALYST | NULL |
7900 | JAMES | CLERK | NULL |
7876 | ADAMS | CLERK | NULL |
7839 | KING | PRESIDENT | NULL |
7788 | SCOTT | ANALYST | NULL |
7369 | SMITH | CLERK | NULL |
7654 | MARTIN | SALESMAN | 1400.00 |
7521 | WARD | SALESMAN | 500.00 |
7499 | ALLEN | SALESMAN | 300.00 |
7844 | TURNER | SALESMAN | 0.00 |
7698 | BLAKE | MANAGER | NULL |
7782 | CLARK | MANAGER | NULL |
7566 | JONES | MANAGER | NULL |