Oracle-DQL语句:查

导航

  • 我们为什么需要DQL语句?
  • DQL的关键词
  • 简单查询
  • 子查询
  • 通配符
  • ORDER BY排序
  • DUAL表
  • GROUP BY子句
  • HAVING子句
  • 多表联合查询
    • 1.内连接
    • 2.外连接
    • 3.交叉连接
    • 4.自然连接
  • EXISTS
  • UNION 与 UNION ALL
  • INTERSECT 与 MINUS

我们为什么需要DQL语句?

  当我们只需要知道数据内容,但并不对数据进行操作的时候,我们就需要使用DQL语句来进行数据的查询读取(只读)。

  DQL:Data Query Language 数据查询语言。

DQL的关键词

  DQL的关键字只有一个,就是SELECT,但它却比DDL与DML加起来都要复杂:

关键词 作用
SELECT 查询表中数据

简单查询

  通过select-from-where语句,即可查询指定表的特定数据,这也是最基础最简单的查询语句。我们以学生信息表t_student为例,该表中有五个字段:s_id,name,age,gender,classes分别记录:学生ID,学生姓名,学生年纪,学生性别,学生班级。建表:

	create table t_student
	(s_id number,
	name  varchar2(20),
	age   number,
	gender varchar2(10),
	classes varchar2(5)
	);

  对该表的查询示例:

	select r.name,r.* from t_student r where r.s_id = 2;

  其中,t_student后的r,为表取的临时别名,仅在当前sql语句中生效。别名可以为除了关键字的任意名字,主要是为了方便sql编写,不必再写一长串的表名。

  r.*中的星号表示展示目标表的所有列。

子查询

  子查询,就是一种嵌套查询,在很多sql语句中都可以灵活的使用。使用子查询,我们就可以把一个查询集的结果,当作一张表;也可以把查询的字段值,作为另一个查询的where筛选条件等等。有了子查询,sql更加灵活多变,可以实现更复杂的逻辑。

  来个案例:请查询出比小虎年纪更大的所有学生信息。

  看到这个需求,我们首先得查出小虎年纪,然后再查比该年纪更大的学生信息。可以想到用子查询一步到位~:

	select * from t_student t
	where t.age > (select r.age from t_student r where r.name = '小虎' );

  需要注意的是,子查询与外层查询是分开的,可以看作是两步查询,及时使用了同一张表,我们应该看作是不同时间维度上的两张表。为了阅读更方便,建议将同一张表取两个不同别名,用来区分。

通配符

  当我们使用模糊查询like时,常会与通配符一起使用。PL/SQL中常用的通配符有两个:

  • %,替代零个、一个或多个字符
  • _,替代一个字符
      示例,查询学生名字中含有A字符的:
SELECT * FROM t_student r where r.name like '%A%';
--包括A开头和A结尾的

  示例,查询学生名字的第三个字母为A的:

--前两个字符用_替代,_的地方必须有一个字符
SELECT * FROM t_student r where r.name like '__A%';

ORDER BY排序

  查询结果的排序方式,往往并不方便我们查看,我们可以在查询语句结果通过order by语句,来指定字段(列)进行排序。order by默认是从小至大,再加上desc关键字,可以改为从大至小排序。例:

	select r.age,r.* from t_student r where r.classes = 'A' order by r.age [desc];

  [ ]中为可选项。

  ORDER BY子句的目标字段可以是多个,但会一

DUAL表

  当我们只想查询某些数据库的基本信息,或者是一些不需要实际存放在某张表中的数据,则可以通过Oracle提供的dual来实现。

  dual表是一个实际存在的表,它只有固定的一行一列,不能用于存储数据。因为select语句必须接上from某张表,我们常常用它来换取系统时间等信息,实例:

	select sysdate from dual;   --获取系统时间
	select to_char(sysdate,'YYYY-MM-DD hh24:mi:ss') from dual; --执行内置函数
	select 666*777 from dual;   --单纯进行计算

GROUP BY子句

  当我们需要对某列进行分组统计时,则会使用到group by子句。

  举个实际点的例子,我们想知道t_student表中,A,B,C班,分别有多少学生。如果不用group by,只能一个班一个班的查询,如下:

	select count(1) from t_student r where r.classes = 'A';
	select count(1) from t_student r where r.classes = 'B';
	select count(1) from t_student r where r.classes = 'C';

  通过这种方式也不靠谱,如果还有D班级,则会遗漏。如果在查询语句结尾,使用group by子句,则会将指定字段的所有值分组,相同的为一组来展示,需要注意的是,一单使用group by子句,则查询的列里只能为group by指定的列,或内置函数。实例:

	select r.classes,count(1) from t_student r 
	group by r.classess;
-------------------------
查询结果为:
  classess    count(1)
-----------  ----------
	A			 25
	B			 30
	C            20

  GROUP BY子句的目标字段也可以是多个。

HAVING子句

  PL/SQL中提供的内置函数大多都挺好用的,方便快捷。但如果我们想对函数的计算结果进行筛选,是不可以直接在where条件中写函数并限制值的,因为在where条件里是还未查出结果的,函数得不到计算范围。

  此时我们可以在where条件语句结束后,使用HAVING子句。having后也是写条件语句,与where类似,但having的条件语句可以使用对函数计算结果进行筛选了,having中的函数是对where条件的查询结果来计算的。

  例如,我们只想查出班级人数大于25人的班级:

	select r.classess,count(1) from t_student r 
	group by r.classess
	having count(1) > 25;

  其实having大多数情况也可以通过两层select来实现,这个案例也可以改写为:

	select t.classes,t.cou
	from(select r.classess,count(1) cou from t_student r group by r.classess) t
	where t.cou > 25;

  我们将group by的查询结果作为一张表,来进行嵌套查询。其中,由于count为关键字,所以为count(1)的列其取个别名,方便查询。我们也可以猜测一下,having的内部实现,是不是就是类似嵌套查询呢?

  虽然两种方法都可以达到相同目的,但在代码可读性、性能等方面上,having更具优势,所以更推荐使用having。

多表联合查询

  以上的内容中,都是对一张表进行的查询,但实际数据库中总是会设计很多表,多张表之前也会有许多关联关联关系,我们常常会需要用到多表的联合查询。

  除了上面提到的t_student学生信息表外,我们再建一个学生的考试分数表t_score,字段有三个:s_id,score,course,分别记录:学生ID,得分,课程。建表:

	create table t_score
	(s_id number,
	score number,
	course varchar2(20)
	);

1.内连接

  有着主外键关联关系,并不一定需要有外键约束,只要逻辑上有着值相等的列,根据这个列建立起来的等值连接,被称为内连接,或简单连接。

  示例的t_student表和t_score表中s_id字段就是主外键关系,虽然没有外键约束,我们可以建立内连接来进行查询:

	select r.name,t.score,t.course from t_student r,t_score t where r.s_id = t.s_id;

2.外连接

  内连接的这个案例,正常场景下,用这样的连接查询就可以查出想要的结果了。但做程序开发,往往重点就在于全面考虑异常情况。来个异常例子:如果一名学生缺考了,那t_score表中就没有他的s_id对应数据,内连接则无法查出缺考的场景数据。

  对于一张表中数据是全的,另一张表中数据可能有缺失的情况,就可以使用外连接来查询。使用(+)来表示外连接,语法格式如下:

	--右外连接
	select  table1.column,table2.column
	from table1 , table2
	where table1.column(+) = table2.column;
	--左外连接
	select  table1.column,table2.column
	from table1 , table2
	where table1.column = table2.column(+);
  • 右外连接:(+)在等号左边,返回table2表所有数据,right jioin
  • 左外连接:(+)在等号右边,返回table1表所有数据,left jioin

  别被这个左右绕晕了,总之就是,(+)出现在哪个表字段后面,就表示这边表的字段可能不完全,需要被(+)补充一下的意思。

  有了外连接,那么对于上面提到的异常缺考情况,我们可以通过该实例查出来:

	select r.s_id,r.name,t.score,t.course from t_student r,t_score t 
	where r.s_id = t.s_id(+);

  如果学生缺考,则t_student表中的name等字段数据还是可以查出来,但对应t_score表的t.score,t.course则会为NULL空。

3.交叉连接

  交叉连接是指两张表的数据行相乘得到的笛卡尔积,在where条件后不对两张表进行关联,则会产生交叉连接。如:

	select r.*,t.* from t_student r,t_score t;

  得到的结果集数量是两张表行数的乘积,且由于每行缺少有意义的关联关系,结果集也失去了意义。

4.自然连接

  自然连接是内连接的严格要求后的升级版,如果两张表有着相同名字的字段,且数据类型也相同,那么可以使用natural join来让他们自然连接,示例:

	select * from t_student natural join t_score;

  但实际过程中一般不使用,还是采用内连接方式逻辑更清晰,提高代码可读性。

EXISTS

  来一个案例:请查询出缺考语文科目学生的学生信息。

  该例子中需要的结果只是学生信息,即t_student表,但学生是否缺考我们需要根据t_score成绩表才知道。如何实现不在from中添加t_score表,但在where中却可以将t_score表作为条件限制呢?。使用exists语句,则可以办到。

  exists是存在的意思,它后面接一个子查询,如果该子查询能查到结果集,则条件成立。not exists则是不存在,如果后面的子查询查不到结果集,条件才成立。

  查询缺考学生信息实例:

	select * from t_student r
	where not exists(select 1 from t_score t where r.s_id = t.s_id and t.course = '语文');

UNION 与 UNION ALL

  我们称每个查询语句的结果为结果集,如果多个结果集的列名和列数据类型一致的话,可以使用union或union all来合并,及取并集。

  如果我们有一张学生信息历史表t_student_history,记录了学生以前的信息。现在有一个需求,需要同时展示t_student与t_student_history中,s_id为1的数据。此使,就可以使用union来实现:

	select s_id,name,age,gender,classes from t_student where s_id = 1
	union 
	select s_id,name,age,gender,classes from t_student_history where s_id = 1;

  被union的结果集,列名、数据类型、顺序均相同,才可以编译通过,成功合并两个结果集的查询结果。该案例中,如果历史表中的数据,与当前表数据一模一样,则会被消除,完全相同的数据无论多少后,最后只保留一行。

  而union all与union基本一样,主要的区别是union all不会消除重复数据,而是全部保留。

INTERSECT 与 MINUS

  有取并集的方法,那就少不了取交集和差集嘛,来就来全套~

  intersect,是取交集,只会得到两个结果集数据相同的部分。

  minus,是取差集,会得到除去两个结果集数据相同的部分后的数据。

  语法与union相同,写在两个select中间。

你可能感兴趣的:(数据库)