sql 几点记录
1 With子句
1.1 学习目标
掌握with子句用法,并且了解with子句能够提高查询效率的原因。
1.2 With子句要点
- with子句的返回结果存到用户的临时表空间中,只做一次查询,反复使用,提高效率。
- 如果定义了with子句,而在查询中不使用,那么会报ora-32035 错误:未引用在with子句中定义的查询名。
- 前面的with子句定义的查询在后面的with子句中可以使用。但是一个with子句内部不能
嵌套with子句。
- 当一个查询块名字和一个表名或其他的对象相同时,解析器从内向外搜索,优先使用子查询块名字。
- with查询的结果列有别名,引用的时候必须使用别名或*。
- with有可能影响执行计划。
1.3 with子句语法
With alias_name as (select1), --as和select中的括号都不能省略
alias_name2 as (select2),--后面的没有with,逗号分割,同一个主查询同级别地方,with子
查询只能定义一次
…
alias_namen as (select n) –与下面的实际查询之间没有逗号
Select ….
1.4 with使用例子:
- 最简单的使用方法:
如查询部门名称包含“A”的所有员工信息
--with clause
with a as
(select deptno from dept where dname like '%A%')
select * from emp where deptno in (select * from a);
with a as
(select deptno from dept where dname like '%A%'),--a结果集
a2 as(select * from a where deptno>20)--a1结果集直接从a中筛选
select * from emp where deptno in (select * from a2);
- 多层同级只能用一个with,并且后面的结果集可以使用前面的结果集:
查询部门名称包含“A”并且部门编号大于20的所有员工信息
with a as
(select deptno from dept where dname like '%A%'),--a结果集
a2 as(select * from a where deptno>20)--a1结果集直接从a中筛选
select * from emp where deptno in (select * from a2);
- 不同级查询可以使用多个with:
查询部门名称包含“A”并且部门编号大于20的所有员工信息的另外一种实现方式如下
with a as
(select deptno from dept where dname like '%A%')--a结果集
select * from emp where deptno in (--括号内层作为子查询,为第二级
with a2 as(select * from a where deptno>20)--a1结果集直接从a中筛选
select * from a2
);
1.5 使用场景
那什么情况下能使用到with子句呢?以下我就举几个简单的例子,简单的说明以下:
- 我想测试一句sql,而我不想专门建立一个测试表:
我想测试成绩大于90的学生,我不想建立学生表,可以用到with子句
with stu as(
select '张娜' sname,99 score from dual union
select '王杰' ,35 from dual union
select '宋丽' ,85 from dual union
select '陈晓' ,73 from dual union
select '李元' ,100 from dual
)--with 组成一个临时的结果集,存放在用户的临时表空间
select * from stu where score>90
- 当一个sql重复用到某个相同的结果集作为子查询:
--查询销售部工资>1500或者销售部工资小于1000的员工
select * from emp where deptno=(select deptno from dept where dname ='SALES') and sal >1500
union all
select * from emp where deptno=(select deptno from dept where dname ='SALES') and sal <1000
--以上sql select deptno from dept where dname ='SALES'需要执行两次,影响效率
--可以使用with优化一下
with salno as(select deptno from dept where dname ='SALES')
select * from emp where deptno=(select * from salno) and sal >1500
union all
select * from emp where deptno=(select * from salno) and sal <1000
2 集合操作
2.1 学习目标
掌握union,union all,minus,intersect的使用,能够描述集合运算,了解内部运行原理。
2.2 要点
Union all 效率一般比union高。Union all内部不做排序工作,也不做剔除
重复行工作,而union则做这个工作。所以当数据量比较大的时候,能用union all的时候尽量用union all。除了union all 默认不做排序和剔除重复行的操作外,
union,minus,intersect都默认按第1个查询结果的第1列进行升序排列,并且
不包含重复行。
2.3 语法
(select resource 1)
Union/union all/minus/intersect
(select resource 2)
Union/union all/minus/intersect
(select resource 3)
……….
其中查询结果集的各个字段的类型能够互相兼容,并且总的结果集字段名与第一个结果集相同。
2.4 使用案例
数据准备:
create table t1 as select rownum rn from dual connect by rownum<7;
create table t2 as select rownum+3 rn from dual connect by rownum<7;
- 查询t1和t2表的所有记录,不去除重复。
- 查询t1和t2表的所有记录,去除重复。
- 查询t1和t2表都存在的记录
- 查询t1表存在,t2表不存在的记录
- 排序操作:
- 除了union all其他的全部会在总的结果集中剔除重复,例如:
insert into t1 values(1);
commit;
现在t1表中有两条相同的记录,其rn的值为1。
在进行集合运算时重复的记录被剔除:
2.5 使用场景
当要对多个结果集进行集合操作时,可是使用集合操作。
3 case与decode
3.1 学习目标
会使用case表达式和decode函数,理解各个参数和返回值的含义。
3.2 要点
Case表达式:
- When后面的表达式类型应该全部保持一致,返回值类型也必须保持一致,或者能够进行隐式转换。
- case 表达式 when 值,如果值是null,就算表达式也是null,结果也是返回false。也就是case 后面的表达式如果值为null,不会与when null 匹配,只会与else 匹配。
Decode函数的使用方法与case when相似,但是decode只能用等号匹配。
3.3 语法
Case表达式第一种:
case exp when comexp then returnvalue
..when comexp then returnvalue
Else
Returnvalue
End
Case表达式第二种:
case when Boolean then returnvalue
..when Boolean then return value
Else
Returnvalue
End
Decode函数:
decode(exp,
value1,res1,
value2,res2,….,
valuen resn,
elsevalue)。
3.4 使用案例
Case 第一种用法:
Case 第二种用法:
Decode用法:
上文提到过null,碰到null的时候要注意,比如:
这种情况可以这样处理:
如果用decode函数:
3.5 使用场景
当我们的sql要求根据不同的条件返回不同的值时,可以使用。
4 exists与in、not exists与not in
4.1 学习目标
掌握exists与in的、not exists与not in的用法,了解其内部的执行顺序 与执行原理,知道什么情况下用exists,什么情况下用in。
4.2 要点
- Exists 用于只能用于子查询,可以替代in,若匹配到结果,则退出内部
查询,并将条件标志为true,传回全部结果资料。
- 若子查询结果集比较小,优先使用in,若外层查询比子查询小,优先使用exists。因为若用in,则oracle 会优先查询子查询,然后匹配外层查询,若使用exists,则oracle 会优先查询外层表,然后再与内层表匹配。最优化匹配原则,拿最小记录匹配大记录。
4.3 语法
In:Select select_fields from table_name where field_name in(select clause);
Exists:Select select_fields from table_name exists (select clause)
4.4 使用案例
查询员工部门编号在部门表中存在的员工记录:
以上语句可以用Exist替换:
另外not in和not exists在某些情况下也可以相互转换,但是要注意一点,not in中的子查询返回的结果集包含null值的时候,查询会失效。例如我想查询对应员工记录数为0的部门。如下:
用not exists:
以上语句不能用not in替换:
查询失效无记录返回。注意这并不是oracle的bug,因为在oracle中null不表示空,而是表示未知,当使用not in的时候,如果子查询返回的结果集中包含null值,我们并不知道外层查询的记录在不在子查询返回的结果集之内,所以无记录返回。虽然这样,但是并不表示not in和not exists是完全不可以转换的,比如子查询所选的字段在对应的表中没有null值,这时not in和not exists是可以相互转换的。或者在某些情况下内层子查询加上field_name is not null限制条件也是可以的。
4.5 使用场景
当内层查询返回的结果集较小时,用in 或者not in效率较高。当内层子查询返回的结果集比较大时,用exists或者not exists执行的效率较高。
5 行列互换
5.1 学习目标
掌握列转行技术和常用的行专列技术。
5.2 要点
行专列的情况有多种,不同的情况侧重点也不一样。
5.3 语法
5.4 使用案例
- 列转行
第一种方法:需要用到union或者union all:
第二种方法:用到model
- 行专列,如我有escore表用来记录每个学生每个科目的成绩,如下:
如果我想将每个学生的成绩统计在一行上,如:
3 语文 11 数学 55 英语 66
则我可以使用如下sql:
这个sql表面上看没什么问题,但是仔细看一下三个结果集es、ys和ss,他们来源于同一个表,而且查询方法也类似,都是根据type的值去筛选的,这样就会对escore表查询三遍,严重影响查询速率,那这个sql我们如何去优化呢!
首先在你的脑海里面要有一种思路,根据需求,原先每个学生成绩有多行记录,现在要显示到一行上,那一般情况下我们是需要根据学生分组的。所以group by sid 这个是一定要有的,既然分组那我们可是使用oracle的聚合函数去求其他行的数据。至于科目字段目前都是已知的,也就是第2,4,6列显示的分别是英语、语文、数学这几个字,是常量,我们不用去考虑,那剩下的也就是最关键的,我们去求三科的成绩就可以了。
让我们再看一下escore表,当指针移到某一行数据时,当type=e时,我们就取到score,加到第三列上,那第五列和第七列就加0,也就是sum(decode(type,’e’,score,0)),其他列类似,这样group
by时用到的聚合函数还有decode结合在一起使用,就可以完成我们的要求了,sql写出来时这样的:
- 字符串组合的多行转一列,例如我有一张测试表如下:
我想根据id分组,将每一行的name连接起来,如下图是我想要的结果:
这种行转列不是真正意义的行转列,是多行数据的值拼接后显示到一列上,那这种情况怎么处理呢,首先分析一下:多行id相同的值转换成一行,一般情况下需要用到group by,但是对于字符串,oracle中没有一个聚合函数适合用到此处的字符串连接,那该怎么办呢?
在oracle中,有sys_connect_by_path(field_name,concat_value)函数,可以通过connect by来依次连接每一行的数据,connect by 的语法是这样的:
start with field1=1--以当前表达式返回true的行开始
connect by prior field2=field3--通过当前行查找下一行,也就是说某一行数据的field3字段等于当前行的field2,那就把这行数据作为下一行
有了这个思路,我们就可以用connect by 通过使用sys_connect_by_path(field_name,concat_value)这个函数,并且根据id分组,将字符串连接在一起,然后通过max聚合函数,选出每组最长的字符转就可以了,那剩下的也就是最关键的问题就是我怎样去使用connect by,通过当前行找到下一行呢?充分发散一下你的思维,看一下如下结果集:
那我下一步用如下思路使用connect by将所要的结果查询上来:
start with lg is null--以lg为null的行作为起始行
connect by prior rn=lg and prior id=id --当前行与其他行比较,满足这个条件的就作为下一行数据
总的查询结果如下:
其实怎么使用connect by 方法很多,例如如下sql也能完成:
sql 几点记录的更多相关文章
- Oracle SQL调优记录
目录 一.前言 二.注意点 三.Oracle执行计划 四.调优记录 @ 一.前言 本博客只记录工作中的一次oracle sql调优记录,因为数据量过多导致的查询缓慢,一方面是因为业务太过繁杂,关联了太 ...
- oracle 、mysql、 sql server使用记录
oracle .mysql. sql server使用记录 mysql常用命令: mysqld --启动mysql数据库 show databases; -- 查看数据库 use database; ...
- SQL去除重复记录
SQL去除重复记录 if not object_id('Tempdb..#T') is null drop table #T Go Create table #T([ID] int,[Name ...
- Mysql中 查询慢的 Sql语句的记录查找
Mysql中 查询慢的 Sql语句的记录查找 慢查询日志 slow_query_log,是用来记录查询比较慢的sql语句,通过查询日志来查找哪条sql语句比较慢,这样可以对比较慢的sql可以进行优化. ...
- 监控SQL:执行表中所有sql语句、记录每个语句运行时间(3)
原文:监控SQL:执行表中所有sql语句.记录每个语句运行时间(3) 通过执行一个 带参数的存储过程 exec OpreateTB('OpreateUser','IsRun') 更新表的数据 表 ...
- 使用SQL Server Audit记录数据库变更
最近工作中有一个需求,就是某一个比较重要的业务表经常被莫名其妙的变更.在SQL Server中这类工作如果不事前捕获记录的话,无法做到.对于捕获变更来说,可以考虑的选择包括Trace,CDC. ...
- SQL Server转发记录指针的坏味道
什么是转发记录指针? 转发记录指针是堆表中特有的数据存储机制. 当你修改了某个数据页中的一行时,如果该行所在的数据页已经无法存放其修改后的行, SQL Server会把这行数据移动到一个新的数据页上面 ...
- 【转】SQL删除重复记录,只保留其中一条
SQL:删除重复数据,只保留一条用SQL语句,删除掉重复项只保留一条在几千条记录里,存在着些相同的记录,如何能用SQL语句,删除掉重复的呢 1.查找表中多余的重复记录,重复记录是根据单个字段(peop ...
- Delphi中SQL批量插入记录
http://www.cnblogs.com/azhqiang/p/4050331.html 在进行数据库操作时, 我们经常会遇到批量向数据库中写入记录的情况. 在这里我提供3种操作方式: 1. ...
随机推荐
- MySQL数据类型——数值类型
1.1.1 整型 整型 占用字节 范围 范围 tinyint 1 -27~27-1 -128~127 smallint 2 -215~215-1 -32768~32767 mediumint 3 -2 ...
- Join的表顺序
在今天的文章里,我想谈下SQL Server里一个非常有趣的话题:在表联接里,把表指定顺序的话是否有意义?每次我进行查询和性能调优的展示时,大家都会问我他们是否应该把联接中的表指定下顺序,是否会帮助查 ...
- SQL Server 2008 R2——PIVOT 行转列 以及聚合函数的选择
==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...
- js 读取 cookie
(新摘未验证)// 将document.cookie的值以名/值对组成的一个对象返回 // 假设储存cookie的值的时候是采用encodeURIComponent()函数编码的 function g ...
- Ubuntu13.04安装历险记--Mono,Nginx,Asp.Net一个都不能少
----Ubuntu13.04安装历险记--新人新手新作------------------------------------------------- 注:以下操作均省略权限获取操作,如有需要,请 ...
- spring 注入一个以枚举类型对象
1.枚举 在实际编程中,往往存在着这样的“数据集”,它们的数值在程序中是稳定的,而且“数据集”中的元素是有限的. 例如星期一到星期日七个数据元素组成了一周的“数据集”,春夏秋冬四个数据元素组成了四季的 ...
- HTTP 请求报文 响应报文
引言 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议.所有的WWW文件都必须遵守这个标准.设计HTTP最初的目的是为了提供一种发 ...
- STM32时钟理解
转载自 http://blog.sina.com.cn/s/blog_6ebd49350100q6xw.html STM32时钟理解 一.硬件上的连接问题 如果使用内部RC振荡器而不使用外部晶振,请按 ...
- CentOS7 (64位) 下QT5.5 连接MySQL数据库(driver not loaded)
用qt连接MySQL需要共享库 libqsqlmysql.so的驱动,路径在plugin/sqldrivers目录下,乍看已经可用了,其实不然. 用ldd命令分析一下,libmysqlclient_r ...
- AI (Adobe Illustrator)详细用法(二)
本文主要是介绍形状的创建与编辑. 一.系列形状工具 1.矩形工具 矩形的作用很大,比如输入框,按钮,图片的大小,比如相片应用中每一个照片占的比例是多大. 初步的UI图的话,会画矩形和圆角矩形就够了. ...