select * from scott.emp e,scott.dept d where (case when e.deptno is null then e.deptno2 else to_char(e.deptno) end)=d.deptno;
sql性能测试
windows环境下cmd控制台或者sqlplus里执行测试sql语句执行时间和吞吐量命令
set timing on
set autot on
但sqlplus里要更精准一些,因为cmd里是调用sqlplus执行的。
where 1=1作用
这段代码应该是由程序(例如Java)中生成的,where条件中 1=1 之后的条件是通过 if 块动态变化的。例如:
String sql=”select * from table_name where 1=1”;
if( conditon 1) {
sql=sql+” and var2=value2”;
}
if(conditon 2) {
sql=sql+” and var3=value3”;
}
where 1=1 是为了避免where 关键字后面的第一个词直接就是 “and”而导致语法错误。
(+)和left join on的转换
可以参考如下语句,其中语句1是left join用法,语句2是(+)用法。
1、select 列名 from 表1 left join 表2 on 条件
2、select 列名 from 表1 ,表2 where 表1.条件=表2.条件(+)
关于使用(+)的一些注意事项:
*(+)操作符只能出现在where子句中,并且不能与outer join语法同时使用。
当使用(+)操作符执行外连接时,如果在where子句中包含有多个条件,则必须在所有条件中都包含(+)操作符
*(+)操作符只适用于列,而不能用在表达式上。
*(+)操作符不能与or和in操作符一起使用。
*(+)操作符只能用于实现左外连接和右外连接,而不能用于实现完全外连接。
having语句
having是对查询结果进行二次加工
分组后,你还想加排除条件,就用having
group by 之后不能使用where,所以需要having
count(*)和count(1)
后者比前者效率高,因为不需要匹配。
in,exists区别
在ORACLE 11G大行其道的今天,还有很多人受早期版本的影响,记住一些既定的规则,
1.子查询结果集小,用IN
2.外表小,子查询表大,用EXISTS
这是完全错误的观点。在8i时代,这经常是正确的,但是现在已经11G了,马上12C就要面世了。其实在ORACLE 9i CBO就已经优化了IN,EXISTS的区别,ORACLE优化器有个查询转换器,很多SQL虽然写法不同,但是ORACLE优化器会根据既定规则进行查询重写,重写为优化器觉得效率最高的SQL,所以可能SQL写法不同,但是执行计划却是完全一样的。
IN与EXISTS有一点要记住:IN一般是用于非相关子查询,而EXISTS一般用于相关子查询。
相关子查询和非相关子查询的区别
分页
select * from (select rownum no, e.* from (select * from scott.emp e1 order by e1.sal,e1.deptno desc) e where rownum <= 5) where no >= 3;
select * from (select rownum no, e.* from (select * from scott.emp e1 order by e1.sal,e1.deptno desc) e) where no >= 3 and no <= 5;
区别:第一句只要找出前面5条排序就行了,后面那句得全部排序
order by +rownum使用的时候如果order by后面的字段是主键和非主键结果不一样
如果order by主键的话先排序再取前几条记录 如果是非主键先取前几条记录再order by
子查询
若子查询未返回任何行,则住查询也不会返回任何结果
(空值)select * from emp where sal>(select sal from emp where empno=8888);
如果子查询返回单行结果,则为单行子查询,可以在主查询中对其使用相应的单行记录比较运算符
(正常)select * from emp where sal>(select sal from emp where empno=7566);
如果子查询返回多行结果,则为多行子查询,此时不允许对其使用单行记录比较运算符
(多值)select * from where sal>(select avg(sal) from emp group by deptno);//非法
内连接和外连接的区别
内连接(自然连接): 只有两个表相匹配的行才能在结果集中出现
外连接: 包括
(1)左外连接(左边的表不加限制)
(2)右外连接(右边的表不加限制)
(3)全外连接(左右两表都不加限制)
as用法
as用于取别名,但是不用于给字段区别名,能用as的时候尽量用as,能够增强代码可读性
w,g,h,o顺序问题
SELECT 语句选FROM,再WHERE,再GROUP,再HAVING,再SELECT,再ORDER,别名是SELECT指定的,不能使用
分组函数
COUNT() 返回查寻的行数
MAX() 返回表达式的最大值
MIN() 返回表达式的最小值
SUM() 返回表达式的总合
AVG() 返回表达式的平均值
分组函数,不能和distinct合用,实际上分组函数已经起了distinct的作用,如要同时使用必须添加group by
分组函数通常是要和group by一起使用
有group by 的时候 select 后面只能包含 group by后面的字段
要查询的字段如果用了分组函数,则所有的字段都要使用分组函数,若有的没有,则需要用w(where)g(group by)h(having)o(order by)之类补齐
alter
–增加字段 alter table tablename add column fieldname varchar2(2)
或者 alter table tablename add(fieldname clob)
– 删除字段 alter table tablename drop column fieldname
– 修改字段 (修改字段名字) alter table tablename rename column oldfield to newfield(修改字段大小) alter table tablename modify fieldname varchar2(2000)
函数
1.字符串函数
||连接符
upper()
lower()
length()
initcap()首字母大写
concat()
substr()
replace()
instr()查询子字符串在母字符串中的位置
lpad()在母字符左侧串中插入子字符串
rpad()在母字符右侧串中插入子字符串
trim()
fm取出前后空格,用法后面直接跟日期fmyyyy表示取年份,fmmm表示取月份,fmdd表示取日,yyyy,mm,dd不能换其他写法,如不能写成yy,m,d等等
2.数值函数
round()
mod()
trunc()截取字符串
3.日期函数
months_between()时间a和时间b之间相差的月份数
add_months()在指定时间基础上加上n个月份
next_day()下一个指定时间出现在什么时候
last_day()指定时间当月的最后一天
4.转换函数
to_char()
to_number()
to_date()
5.通用函数
nvl(exp,指定值)如果指定字段为空显示指定值,其余不变
nvl2(exp,指定值1,指定值2)如果指定字段为空显示指定值1,其余显示指定值2
nullif(exp1,exp2)如果exp1和exp2相等则返回空(NULL),否则返回第一个值
coalesce()语法为COALESCE(表达式1,表达式2,…,表达式n),n>=2,此表达式的功能为返回第一个不为空的表达式,如果都为空则返回空值。
case()函数
CASE sex
WHEN ‘1’ THEN ‘男’
WHEN ‘2’ THEN ‘女’
ELSE ‘其他’ END
decode()函数
dual表用法
获取当前用户名
获取系统时间
计算器
得到序列的下一个值或当前值,用下面语句
select your_sequence.nextval from dual;–获得序列your_sequence的下一个值
select your_sequence.currval from dual;–获得序列your_sequence的当前值
merge用法
merge into是对比插入/更新
一般是增量整合全量做
merge into products p using (select * from newproducts) np on (p.product_id = np.product_id) when matched then update set p.product_name = np.product_name when not matched then insert values(np.product_id, np.product_name, np.category)
oracle中merge的用法
insert,update,delete都有可能产生事务,select不会产生事务。事务是为了保证数据的完整性,通常出现在对多张表的操作,单表操作一般不需要添加事物。在查询的时候使用缓存可以大大减少游标的使用量,select * from a where a.id=?使用类似的语句可以大大减少游标使用量,因为在数据库中只执行了一条select语句,如果每条查询都使用select对于高并发查询,会出现游标不够的情况,在极端情况下可能会导致服务器宕机。
with yy as(
select kk.* from(
(select * from a)
union all
select * from b tt
left join c tt1
where a.ddlx is not null
order by a.description
)kk
)
select * from yy
注意点:查询数量限制select * from (select rownum as num, t* from insurance_type t) where num >= 100;
select *
from (select rownum as num, t.*
from (select t1.user_code,
t1.username,
t1.name,
t3.insurance_type_code,
t3.insurance_type_name,
t4.description
from ta_survey_provide t1,
ta_survey_vs_insure t2,
ta_insurance_type t3,
ta_org_info t4
where t1.id = t2.survey_id
and t2.insurance_type_id = t3.id
and t1.org_id = t4.id
and t1.survey_type = 2
and t2.insurance_type_id is not null) t)
where num > 180000 and num <= 240000;
注意点:嵌套select(本条sql语句出错原因在最后的order by,因为句首使用了distinct,所以如果使用未出现的字段进行order by排序的话,必须要加表名,这也体现了distinct的特性)
select
from
(
select
distinct t4.USER_CODE,
to_char(t2.DISPATCH_TIME, ‘yyyy-mm-dd’) DISPATCH_TIME,
(
case when (sysdate - t2.dispatch_time) * 24 * 60 > 5 then 1 else 0 end
) as FLAG,
t1.REGIST_NO,
decode(t1.LOSS_NO, ‘0’, ‘0’, ‘1’) as LOSS_NO,
t1.LOSS_TYPE,
t5.DESCRIPTION,
t4.NAME,
t2.YARDMAN_NUMBER,
t2.YARDMAN_NAME,
t2.DISPATCH_TYPE,
t2.SURVEY_PLACE,
t1.STATUS,
t1.CONTACT,
t1.REMARK
from
ta_loss_item t1,
ta_dispatch_item t2,
ta_case_info t3,
ta_survey_provide t4,
ta_org_info t5
where
t1.id = t2.loss_id
and t3.id = t1.case_info_id
and t4.user_code = decode(
t2.dispatch_type, 2, t2.video_survey_number,
1, t2.survey_number, t2.survey_number
)
and t4.org_id = t5.id
and t1.status = 2
and t2.DISPATCH_TIME >= to_date(‘2015-12-20’, ‘yyyy-mm-dd’)
and t2.DISPATCH_TIME <= to_date(‘2016-01-07’, ‘yyyy-mm-dd’)
)
order by
dispatch_time desc
注意点:oracle选择函数,decode函数
select
t2.dispatch_time,
(case when (sysdate-t2.dispatch_time)*24*60>5 then 1 else 0 end) as flag,
t1.regist_no,
t1.loss_no,
t1.loss_type,
t5.description,
t4.user_code,
t4.name,
t2.yardman_number,
t2.yardman_name,
t2.dispatch_type,
t2.survey_place,
t1.status,
t1.contact,
t1.remark
from
ta_loss_item t1,
ta_dispatch_item t2,
ta_case_info t3,
ta_survey_provide t4,
ta_org_info t5
where
t1.id = t2.loss_id
and t3.id = t1.case_info_id
and t4.user_code = decode(
t2.dispatch_type, 2, t2.video_survey_number,
1, t2.survey_number, t2.survey_number
)
and t4.org_id = t5.id
and t1.status = 2
and t2.dispatch_time >= to_date(
‘2015-12-31 10:10:10’, ‘yyyy-MM-dd hh24:mi:ss’
)
order by
t2.dispatch_time desc
三表查询
select
g.main_image_ufid,
g.main_name,
i.goods_name,
i.buy_number,
i.sale_price,
o.amount,
o.order_no,
o.status
from orders o, order_items i
left join goods g
on g.id=i.goods_id
where i.order_id =o.id
select from [where] [group by] [having] [order by]
多表查询count
select
(select count(1) from tc_rl_grbsb)tc_rl_grbsb,
(select count(1) from tc_rl_jyrl)tc_rl_jyrl
truncate table 表名:删除对应的表,且主键从零开始
oracle 关于to_number()
注意: 尝试将英文字符用to_number转换为数字都会提示出错.
INSTR (源字符串,目标字符串, 起始位置, 匹配序号) //匹配序号:第几次出现在Oracle/PLSQL中,instr函数返回要截取的字符串在源字符串中的位置。只检索一次,就是说从字符的开始到字符的结尾就结束。
语法如下:
instr( string1, string2 [, start_position [,nth_appearance ] ] )
参数分析:
string1
源字符串,要在此字符串中查找。
string2
要在string1中查找的字符串.
start_position
代表string1 的哪个位置开始查找。此参数可选,如果省略默认为1. 字符串索引从1开始。如果此参数为正,从左到右开始检索,如果此参数为负,从右到左检索,返回要查找的字符串在源字符串中的开始索引。 nth_appearance 代表要查找第几次出现的string2. 此参数可选,如果省略,默认为 1.如果为负数系统会报错。
注意:
如果String2在String1中没有找到,instr函数返回0.
示例:
SELECT instr(‘syranmo’,’s’) FROM dual; – 返回 1
SELECT instr(‘syranmo’,’ra’) FROM dual; – 返回 3
SELECT instr(‘syran mo’,’a’,1,2) FROM dual; – 返回 0
(根据条件,由于a只出现一次,第四个参数2,就是说第2次出现a的位置,显然第2次是没有再出现了,所以结果返回0。注意空格也算一个字符!)
SELECT instr(‘syranmo’,’an’,-1,1) FROM dual; – 返回 4
(就算是由右到左数,索引的位置还是要看‘an’的左边第一个字母的位置,所以这里返回4)
SELECT instr(‘abc’,’d’) FROM dual; – 返回 0
注:也可利用此函数来检查String1中是否包含String2,如果返回0表示不包含,否则表示包含。
对于上面说到的,我们可以这样运用instr函数。请看下面示例:
如果我有一份资料,上面都是一些员工的工号(字段:CODE),可是我现在要查询出他们的所有员工情况,例如名字,部门,职业等等,这里举例是两个员工,工号分别是’A10001′,’A10002′,其中假设staff是员工表,那正常的做法就如下:
SELECT code , name , dept, occupation FROM staffWHERE code IN (‘A10001’,’A10002’);
或者:
SELECT code , name , dept, occupation FROM staffWHERE code = ‘A10001’ OR code = ‘A10002’;
有时候员工比较多,我们对于那个’觉得比较麻烦,于是就想,可以一次性导出来么?这时候你就可以用instr函数,如下:
SELECT code , name , dept, occupation FROM staffWHERE instr(‘A10001,A10002’,code)>0;
查询出来结果一样,这样前后只用到两次单引号,相对方便点。
还有一个用法,如下:
SELECT code, name, dept, occupation FROM staff WHEREinstr(code, ‘001’) > 0;
等同于
SELECT code, name, dept, occupation FROM staff WHEREcode LIKE ‘%001%’ ;
Oracle的instr函数使用实例
INSTR方法的格式为
INSTR(src, subStr,startIndex, count)
src: 源字符串
subStr : 要查找的子串
startIndex : 从第几个字符开始。负数表示从右往左查找。
count: 要找到第几个匹配的序号
返回值: 子串在字符串中的位置,第1个为1;不存在为0. (特别注意:如果src为空字符串,返回值为null)。
用法举例:
最简单的一种,查找l字符,首个l位于第3个位置。
SQL> select instr(‘hello,java world’, ‘l’) from dual;
3
查找l字符,从第4个位置开始。
SQL> select instr(‘hello,java world’, ‘l’, 4) from dual;
4
查找l字符,从第1个位置开始的第3个
SQL> select instr(‘hello,java world’, ‘l’, 1, 3) from dual;
15
查找l字符,从右边第1个位置开始,从右往左查找第3个(也即是从左到右的第1个)
SQL> select instr(‘hello,java world’, ‘l’, -1, 3) from dual;
3
找不到返回0
SQL> select instr(‘hello,java world’, ‘MM’) from dual;
0
源字符为空字符串”的情况
复制代码代码如下:
– Created on 2010-12-22 by CHEN
declare
– Local variables here
i varchar2(2);
begin
– Test statements here
i := instr(”,’,’);
if i is null then
dbms_output.put_line(’ i is empty’);
end if;
end;
结果输出:
i is empty
Oracle SQL语句大全
1.desc(描述 emp 描述emp这张表
2.desc dept 部门表
3.desc salgrade 薪水等级
4.select *from table 查找表中的元素
5.dual 是系统中的一张空表
6.select *from dual
7.select sysdate from dual 取出系统时间
8.select ename,sal*12 “annulsal”(取的别名 fromemp; 查找用户姓名和用户的年薪
9.任何含有空值的数学表达式的值都是空值
select ename,sal*12+comm from emp;
10.select ename||sal from emp 其中的||相当于将sal全部转化为字符串
11.表示字符串的方法
select ename ||’ajjf’ from emp;
12.如果其中有一个单引号就用2个单引号来代替他
select ename||’sakj’ ‘lds’from emp;
13.select distinct deptno from emp (去除部门字段中重复的部分,关键字distinct)
14.select distinct deptno,job from emp;(去除这2个字段中重复的组合)
15.select *from dept where deptno=10; 取出条件(取出部门编号为10的记录)
16.select * from emp where ename=’CLIRK’; 取出部门中姓名为clirk的记录(注意取出过程中
ename用单引号隔开)
17.select ename,sal from emp wheresal>1500; 取出部门中薪水大于1500的人的姓名
18.select ename,sal,deptno from emp wheredeptno<> 10 取出部门中的部门号不等于10的
19.select ename,sal,deptno from emp whereename>’CBA’ 取出部门中员工名字大于CBA的员
工(实际比较的是ACIIS码)
20.select ename,sal from emp where salbetween 800 and 1500
select ename,sal from emp where sal>=800 and sal<=1500; (取出800和1500之间的数)
21.select ename,sal,comm from emp wherecomm is null (选出其中的空值)
select enmae,sal,comm from emp where comm is not null(选出其中的非空值)
22.select ename,sal,comm from emp where salin (800,1500,2000);取出这3者之中的
select ename,sal,comm from emp where ename in(‘simth’);
23.select ename,sal,hiredate from emp wherehiredata>’3-04月-81’;宣传符合条件的日期
24.select ename,sal,from emp wheresal>1000 or deptno=10; 找出工资薪水大于1000或者
部门号等于10的员工
25.select ename,sal from emp where sal notin(500,1000); 查找薪水不在500到1000的员
工姓名和月薪
26.select ename,sal from emp where enamelike ‘%ALL%’;
select ename,sal from emp where ename like ‘_%A%’; 查找姓名中含有ALL的客户
信息一个横线代表一个通配符
27.select ename,sal from emp where enamelike ‘_% ’; 自己指定转易字符
select ename,sal from emp where ename like ‘_%\%%’; 查找中间含有%相匹配
的客户信息运用转易字符
28.select * from dept order by deptno 对表中元素按部门号排序 select *from dept order by deptno desc 默认为升序可以用desc
按降序
29.select ename,sal from emp where sal<>1000 order by sal desc 按照查询条件来查询并排
序asc升序排列
30.select ename,sal*12 from emp where enamenot like ‘_%A%’ and sal>800 order by sal desc
31.select lower(ename) from emp 将ename都转化为小写 lower是函数能将字母转化为小
写
32.select ename from emp where lower(ename)like ‘_%a%’; 找出ename 中所有的含有a的字符
33.select substr(ename,2,3) form emp 从第2个字符开始截取3个字符
34.select chr(65) from dual; 将65转化为字符
35.select ascii(‘A’) from dual 将ACSII码转化为字符串
36.select round(23.565)from dual 四舍五入
36.select round(23,4565,2)from dual 四舍五入到第二位
37.select to_char(sal,’ 99.999.9999′)fromemp按指定格式输出selecttochar(sal,′L99,999,9999′)formempL代表本地字符38.selecthiredatefromempselecttochar(hiredate,′YYYY−MM−DDHH:MI:SS)fromemp;时间格式的显示selecttochar(sysdate,′YYYY−MM−DDHH:MI:ss)fromdual;十二小时制显示系统时间selecttochar(sysdate,′YYYY−MM−DDHH24:MI:SS)fromdual二四小时制显示系统时间39.selectename,hiredatefromempwherehiredate>todate(‘2005−2−312:32:23′,′YYYY−MM−DDHH:MI:SS′);40selectsalfromempwheresal>tonumber(‘ 1,250.00','$9,999.99’); 取出比它大的一切字符串
把特定格式的数字转化成字符
41 select ename,sal+nvl(comm,0) fromemp; 讲comm值为空的用0来替换单行函数以
一条记录为条件一条对一条
42.select Max(sal) from emp;
select Min(sal) from emp;
select avg(sal) from emp;
select sum(sal) from emp;
select count(*) from emp; 查看表中一共有多少条记录
select count(*) from emp where deptno=10; 查找部门10一共有多少人
43.select avg(sal),deptno from emp group bydeptno; 按部门号进行分组
select deptno,job,max(sal) from emp group by job,deptno; 按工作和部门号进行分组
44.select ename from emp where sal=(selectmax(sal) from emp); 子查询查找部门中薪水最高
的员工姓名
45.group by 注意出现在select列表中的字段如果没有出现在组函数中必须出现在group by
子句中
46.select avg(sal),deptno from emp group bydeptno having avg(sal)>2000; 选出部门中平均
薪水大于2000的部门
47.select * from emp where sal>100 groupby deptno having ……….order by……..
先取数据–过滤数据——分组—-对分组限制——-排序
48.select avg(sal) from emp wheresal>2000 group by deptno having avg(sal)>1500 order by avg(sal) desc;
查找部门中平均薪水打印2000的员工并按部门号进行排序查询分组后的平均薪水必须大
于1500查询结果按平均薪水从低到高排列
49.select ename from emp wheresal>(select avg(sal) from emp);
查找出员工中薪水位于部门平均薪水之上的所有员工
50.select ename,sal from emp join(selectmax(sal) max_sal from emp group by deptno) t
on(emp.sal=t,max_sal andemp.deptno=t.deptno);
查找每个部门中薪水最高的
51.select e1.ename,e2.ename from emp e1,empe2 where e1.mgr=e2.empno; 表的自
连接
52.select dname,ename from emp cross joindept 交叉连接笛卡尔
SQL99中的新语法
53.select ename,dname from emp join depton(emp.deptno=dept.deptno);
54.select ename,dname from emp join deptusing(deptno); 查找emp和dept表中
deptno相同的部分。
55.select ename,dname,grade from emp e joindept d on(e.deptno=d.depno)
joinsalgrade s(e.sal between s.losal and s.hisal)
(三表查找
whereename not like ‘_%A%’;
56.select e1.ename,e2.ename from emp e1join emp e2 on(e1.mgr=e2.deptno); 表的自连接
57.select e1.ename,e2.ename from emp e1left join emp e2 on(e1.mgr=e2.deptno) 左外表连接
select ename,dname from emp e right join dept d on(e.deptno=d.deptno)右外连接
select ename,dname from emp e full join dept d on(e.deptno=d.deptno)全连接
58.求部门中薪水最高的
select ename,sal from emp join (select max(sal) max_sal, deptno from empgroup by deptno) t
on(emp.sal=t.max_sal and emp.deptno=t.deptno);
59.求部门中薪水等级的平均值
select deptno,avg(grade) from(select deptno,ename,grade,from emp joinsalgrade s on(emp.sal
between s.losal and s.hisal))t group bydeptno;
60.查找雇员中哪些是经理人
select ename from emp where empno in(select mgr from emp);
61.select distinct e1.sal from emp e1 joinemp e2 on(e1.sal