Oracle 查询(SELECT)语句(一)

让人想犯罪 __ 提交于 2019-12-08 15:39:52

Ø  简介

本文介绍 Oracle 中查询(SELECT)语句的使用,在 SQL SELECT 语句是相对内容较多的,也是相对比较复杂一点的,所以这里拿出来单独学习。

 

首先,我们先来理一下思路,我们知道查询通常包含以下内容:

Ø  查询指定的表和列

Ø  根据指定的条件查询,即 WHERE 条件

Ø  查询数据去重,即 DISTINCT 子句

Ø  查询数据聚合,即 COUNT()MAX()MIN()

Ø  按条件输出,即 CASE WHEN THEN 子句

Ø  排序(ORDER BY)

Ø  分组(GROUP BY)与分组过滤(HAVING)

Ø  多表连接(INNER JOINLEFT JOIN 等)

Ø  子查询(SELECT 子查询、WHERE 子查询等)

Ø  其他

 

好了,既然知道了有这些查询功能,下面我们就一一突破,准备了以下内容:

1.   准备数据

2.   SELECT 语法

3.   基本用法

4.   WHERE 条件

5.   聚合查询

6.   CASE WHEN THEN 子句

7.   排序

8.   分组与分组过滤

 

1.   准备数据

1)   创建表结构

CREATE TABLE JNUser (

  UserId NUMBER(10) NOT NULL ,

  Name VARCHAR2(8) NOT NULL ,

  Sex NUMBER(3) NOT NULL ,    --性别(0 女,1 男,2 未知)

  Age NUMBER(5) NOT NULL ,

  Birthday DATE NOT NULL ,

  City VARCHAR2(6) NOT NULL ,

  IdNumber CHAR(18) NOT NULL ,

  Salary FLOAT ,

  Remarks VARCHAR2(4000) NOT NULL ,

  PRIMARY KEY (UserId),

  CONSTRAINT UQ_JNUser_IdNumber UNIQUE (IdNumber),

  CONSTRAINT CK_JNUser_Sex CHECK (Sex >= 0 AND Sex <= 2)

);

 

CREATE TABLE JNOrder (

  OrderId NUMBER(10) NOT NULL ,

  UserId NUMBER(10) NOT NULL ,

  OrderNo VARCHAR2(16) NOT NULL ,

  TotalAmount FLOAT NOT NULL ,

  OrderDate DATE NOT NULL ,

  Remarks VARCHAR2(4000) ,

  PRIMARY KEY (OrderId),

  CONSTRAINT UQ_JNOrder_OrderNo UNIQUE (OrderNo)

);

 

2)   插入数据

INSERT ALL

--用户数据

INTO JNUser VALUES(1, '孙器璇', 2, 17, to_date('2002/11/18', 'yyyy/mm/dd'), '北京', '17730094858437637X', 10400, 'hello')

INTO JNUser VALUES(2, '周器璇', 0, 22, to_date('1966/05/12', 'yyyy/mm/dd'), '武汉', '534668342907162757', 15000, '用户2')

INTO JNUser VALUES(3, '张二娃', 1, 24, to_date('1967/01/24', 'yyyy/mm/dd'), '杭州', '36935324879542561X', 7600, '大家好,我是张二娃')

INTO JNUser VALUES(4, '陈悴', 2, 22, to_date('1984/10/11', 'yyyy/mm/dd'), '武汉', '585823614699788016', 7100, '你好,贵姓?')

INTO JNUser VALUES(5, '钱悴', 2, 58, to_date('1961/10/21', 'yyyy/mm/dd'), '深圳', '449489822531507067', 15320, 'hello 张二娃')

INTO JNUser VALUES(6, '张无忌', 1, 61, to_date('1988/02/24', 'yyyy/mm/dd'), '杭州', '385929993868497572', 17800, '哈啰,我是张无忌')

INTO JNUser VALUES(7, '张大彪', 1, 24, to_date('1995/05/16', 'yyyy/mm/dd'), '上海', '466484458398445233', 1200, '我说了,我是彪爷')

INTO JNUser VALUES(8, '冯小二', 1, 29, to_date('1976/09/28', 'yyyy/mm/dd'), '广州', '40016865591929392X', 5700, '客观,吃点莫子?')

INTO JNUser VALUES(9, 'DBA', 2, 32, to_date('1997/04/28', 'yyyy/mm/dd'), '上海', '488500420672587475', 16000, '小崽子们,你们好,我是 DBA')

INTO JNUser VALUES(10, '陈双', 0, 18, to_date('1995/02/07', 'yyyy/mm/dd'), '武汉', '942310204386191671', 10343, '我是双儿')

--订单数据

INTO JNOrder VALUES(1, 2, '58977924501badf7', 2620, to_date('2019/06/10', 'yyyy/mm/dd'), '又是双十一,我卖完再剁手啦')

INTO JNOrder VALUES(2, 3, '316626433f743978', 1115, to_date('2019/08/19', 'yyyy/mm/dd'), '其他没什么,就是想买')

INTO JNOrder VALUES(3, 4, '8698789361c78946', 1734, to_date('2019/03/16', 'yyyy/mm/dd'), '')

INTO JNOrder VALUES(4, 5, '58716471589e3df2', 897, to_date('2019/11/13', 'yyyy/mm/dd'), ' ')

INTO JNOrder VALUES(5, 8, '5583165337e0ee25', 2097, to_date('2019/01/21', 'yyyy/mm/dd'), '我已下单,快点发货,老板')

INTO JNOrder VALUES(6, 8, '395799340826d6f2', 304, to_date('2019/02/27', 'yyyy/mm/dd'), '   ')

INTO JNOrder VALUES(7, 3, '887799782996b3f1', 1246, to_date('2019/09/20', 'yyyy/mm/dd'), '老板,给我来个好看的包装盒,我要送老丈人')

INTO JNOrder VALUES(8, 8, '39482046468266d6', 306, to_date('2019/02/28', 'yyyy/mm/dd'), NULL)

SELECT * FROM DUAL;

COMMIT;

 

2.   SELECT 语法

SELECT <列名1> [<,列名2>]… FROM <表名或视图名>

[WHERE <条件表达式>]

[GROUP BY <列名1> [HAVING <条件表达式>]

[ORDER BY <列名1> [ASC | DESC]]

说明:如果输出所有列,可以指定为"*"。这里简单阐述下(SELECT * SELECT 所有列)的一些区别:

比较项

SELECT *

SELECT 指明所有列

结论

1.   执行效率

需要检索表中的所有列名

不需要检索列名

后者效率略高

2.   后续新增字段

原程序会直接将新字段查出

需要重新更改程序中的 SQL 语句

视业务情况而定

3.   难易程度

比较便捷

比较麻烦

前者有优势

4.   字段较多时(比如一两百多个)

减少网络流量

增加网络流量

前者有优势(可忽略的)

提示:如有其他看法,欢迎讨论。

 

3.   基本语法

1)   查询所有列

SELECT * FROM JNUser;

SELECT * FROM JNOrder;

clip_image002

clip_image004

 

2)   查询指定列

SELECT UserId, Name FROM JNUser;

 

3)   定义别名

SELECT UserId 用户Id, Name 用户名, Age AS "性 别", U.City FROM JNUser U;

说明:

1.   表别名不能使用 AS 关键字;定义别名后可使用或不使用;

2.   列别名可使用或不使用 AS 关键字;别名包含特殊字符时,采用""双引号括起来。

 

4)   算数运算符(+-*/)

SELECT Salary, Salary + 200, Salary - 200, Salary * 12, Salary / 30 FROM JNUser;

 

5)   比较运算符(>>=<<==!= | <>)

SELECT * FROM JNUser WHERE City <> '上海'; --或者使用 !=

 

6)   列连接

SELECT UserId || ' - ' || Name || ' - ' || City AS UserDesc FROM JNUser;

 

7)   构建表达式

SELECT ('SELECT * FROM ' || TABLE_NAME || ';') AS SEL FROM ALL_TABLES WHERE OWNER = 'USER01';

 

8)   数据去重

SELECT DISTINCT Age, City FROM JNUser;

说明:去除每列相同的数据行,只返回一行

 

4.   WHERE 条件

1)   复合条件

SELECT * FROM JNUser WHERE Salary > 10000; --查出工资大于10000的用户

SELECT * FROM JNUser WHERE Sex = 0 AND Salary > 10000; --查出性别为女性,且工资大于10000的用户

SELECT * FROM JNUser WHERE (Sex = 0 OR Sex = 2) AND Salary > 10000; --查出性别为女性或者未知,且工资大于10000的用户

 

2)   IN 子句

IN 子句表示取出值包含在给出的值范围内的记录。

SELECT * FROM JNUser WHERE City IN('武汉', '上海', '北京') ORDER BY City; --查出所在城市在武汉、上海、北京的用户,并按城市升序排序

 

3)   BETWEEN 子句

BETWEEN 子句表示取出值在起始值与结束值之间的记录,且包含起始值与结束值(它是包头包围的)。

SELECT * FROM JNUser WHERE Salary BETWEEN 10400 AND 16000; --查出工资在10400(包含)至16000(包含)之间的用户

 

4)   LIKE 模糊匹配

SELECT * FROM JNUser WHERE Remarks LIKE 'h%'; --查出备注以 h 开头的用户(注意:匹配时区分大小写)

SELECT * FROM JNUser WHERE Remarks LIKE '%%'; --查出备注中包含字的用户

SELECT * FROM JNUser WHERE Name LIKE '__'; --查出姓张的,并且名为2个字的用户

注意:在实际应用场景中不到万不得已,尽量避免使用 LIKE 模糊查询,因为使用模糊的字段就不能使用索引了,影响查询效率。

 

5)   使用&变量

SELECT * FROM JNUser WHERE City = '&City' AND Salary > &Salary;

说明:该查询方式只适合在 PL/SQL Developer 中使用,提供一个条件参数占位符,用于在窗口中输入参数值。

clip_image005

 

5.   聚合查询

聚合函数是 Oracle 提供内置函数,用于计算某一列的聚合计算(如:数量、平均值等)

SELECT COUNT(*) AS COUNT FROM JNUser WHERE City = '上海'; --统计有多少上海用户,*可以改为数字1

SELECT MAX(SALARY) AS MAX FROM JNUser WHERE City = '上海'; --查询上海用户最高薪资

SELECT MIN(SALARY) AS MIN FROM JNUser WHERE City = '上海'; --查询上海用户最低薪资

SELECT SUM(SALARY) AS SUM FROM JNUser WHERE City = '上海'; --查询上海用户总薪资

SELECT AVG(SALARY) AS AVG FROM JNUser WHERE City = '上海'; --查询上海用户平均薪资

 

6.   CASE WHEN THEN 子句

CASE WHEN THEN 定义在 SELECT FROM 之间,用于判断当条件符合 WHEN 时,就返回 THEN 对应的值,否则返回 ELSE 中的值。

1)   第一种写法

SELECT City, (CASE City WHEN '上海' THEN 'SH' WHEN '武汉' THEN 'WH' ELSE 'WZ' END) AS JianCheng FROM JNUser;

 

2)   第二种写法

SELECT City, (CASE WHEN City = '上海' THEN 'SH' WHEN City = '武汉' THEN 'WH' ELSE 'WZ' END) AS JianCheng FROM JNUser;

clip_image006

 

7.   排序

排序采用 ORDER BY 子句,包含升序(ASC)和降序(DESC)排序方式。

SELECT * FROM JNUser ORDER BY Salary; --ASC 升序排序(默认排序方式)

SELECT * FROM JNUser ORDER BY Salary DESC; --DESC 降序排序

SELECT * FROM JNUser ORDER BY Sex ASC, Salary DESC; --首先按性别升序排序,再按薪资降序排序

clip_image008

SELECT * FROM JNUser WHERE Sex = 1 ORDER BY 4 ASC; --查出男性用户所有用户,并按照第4列(AGE)升序排序

 

8.   分组与分组过滤

分组采用 GROUP BY 子句,注意:包含分组的 SELECT 输出列中只能包含,分组的列和聚合计算的列。GRUOUP BY 分组后还可以跟条件子句,即 HAVING,通常用于聚合计算过滤。

1)   查出工资大于8000的用户,每个性别各占的数量,并按性别倒序排序

SELECT Sex, COUNT(1) AS Count FROM JNUser

WHERE Salary > 8000

GROUP BY Sex

ORDER BY Sex DESC;

 

2)   查出工资大于8000的用户,每个性别的平均工资大于13000,并按性别倒序排序

SELECT Sex, AVG(Salary) AS Avg FROM JNUser

WHERE Salary > 8000

GROUP BY Sex

HAVING AVG(Salary) > 13000

ORDER BY Sex DESC;

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!