读书笔记——SQL CookBook

SQL CookBook——很多各样的例子

 

1. coalesce

COALESCE ( expression [ ,...n ] )

返回第一个非空表达式,如果所有表达式全为null,则返回null。

 

2. group by中使用count时关于null列

如果group by中对某列a使用count(a)as num, 那么对于所有a为空的行,不计算到num中。

如何才能使得即使a为空,也要计算进去呢,这时候就要使用count(*),他计算行数,而不关心行中该列是否为空,不是对行的该列值进行判断后才计算行数。

 

group by语句中,要想在select中显示的表列,就必须放在group by后,聚集函数除外。   在group by 后有的列,可以不显示在select后边。

 

3. 关于sql中的别名问题

sql中可以使用列别名、表别名,定义过别名之后何时生效,何时可以使用呢。这就要根据sql执行的顺序: from where select……  

from之后是表名,所以表名的别名最早生效,where中就可以使用表名别名了,select中对列定义完列别名之后,在后边的order by等或者外层的查询中才可以使用它所定义的别名。

 

4. 数据库中的字符串连接

使用concat函数,其中oracle中可以使用函数简写方式双竖线,sqlserver中可以使用加号。

mysql的concat函数中如果有一个是null,那么就返回null。oracle中只要一个不为null,就不返回null。

 

5. select中使用条件逻辑

     使用

case when 条件表达式  then 结果表达式

                   when 条件表达式  then 结果表达式

                   else   结果表达式

                   end   as  别名

其中,else可以没有,如果没有对应可以满足的情况,那么返回null值。

 

6.取多少行数据

mysql使用limit 50(50条) 或者 limit 200,50(从200+1条开始取50条)

oracle 使用where  rownum<=5 

sqlserver   select top n * from table

db2    select * from table fetch first 5 rows only

其中需要特殊说明的是oracle 的方法与其他不同,其他数据库是从结果集中指定要返回的行数,但是oracle的rownum是在获取每一个满足条件的行

后才开始赋值,并递增rownum的值作为行号。但是如果条件不符合,那么就会放弃该行,去取下一行然后再判断是否满足条件。

对于rownum=1,不管表中是否有行,都会尝试返回一行,所以是可行的。但是对于rownum=10,每次获取一行后判断条件为行数是否等于10,而每次都不满足,就放弃该行再继续取下一行,对于放弃的操作rownum的数值不会增加,返回的总行数也仍然是一行,不满足条件,这莫不是个死循环。所以方法不可行。 

oracle使用rownum<=n时判断条件是:每返回一行,就判断当前总行数是否满足<=n,如果满足那么为当前行赋值rownum(如果是第一行,值为1),继续返回下一行,判断总行数(如果之前已经反回了m个满足条件的行,那么现在的总行数是m+1)m+1是否<=n,如果满足就为刚返回的这一行rownum赋值为m+1,继续取下一行,如果不满足则结束取值。

 

7.随机排序原理

作数据库的时候给个字段,加上参数(rand())这样产生的就是每条记录都一个随机的id,然后以后要排序的时候order by这个字段就可以了。这样的方法检索速度很快。而且不会重复纪录,因为rand()产生的是很长的随机范围2.804989E-02~1.281764E-02
order by rand()运行的时候实际上已经将rand()搁到记录集中了

mysql获取n行随机数据   select * from table order by random() limit 50;

oracle获取n行随机数据   select * from (select rownum as num, t.* from table t order by dbms_random.value())  b where b.num<=50

select * from (select  t.* from table t order by dbms_random.value())  where rownum<=50

sqlserver select top 50 , * from table order by newid();

 

8.多列使用in的问题

select * from table1 where (a1, a2, a3) in (select b1, b2, b3 from table2);

也就是 select table1.* from table1 m inner join table2  n on(m.a1=n.b1 and m.a2=n.b2 and m.a3=n.b3) 

 

9. not in 的本质是什么?

为什么在有null值的时候not in 就会失效呢?下面将看到原因。

比如现在的条件是   where col not in ( select col2 from table2 ***)

加入子查询中出现了null值,结果为 10, 20 ,null 

那么sql就是  where col not in ( 10, 20, null)

等同于   where not ( col=10 or col=20 or col=null)

当col的值为10时,表达式结果为  not ( true or false or null)=>   true or null => null   错了 不对,不明白

在sql中,true or null的结果是null , 但是false or null的结果也是null。当结果中只要有一个null值是,null就会延续下去。

所以使用in或者or时要非常注意到这一点。

 

10. 那么要解决not in 和null的问题,就需要使用到not exists了。

在表1中查找表2中不存在的数据:

select * from table1 where not exists( select '12368' from table2 where table1.col1 = table2.col2)

整个查询过程是什么样的呢?

首先从表1中依次取出一行, 根据条件 table1.col1 = table2.col2 判断表2中是否有满足此条件的记录,如果有exists()返回true,那么not exists()就返回false,

false的话,这一条记录就放弃。如果是true的话,这条记录就放入结果集中。

所以此时子查询中的select后边随便写什么字段都可以,因为写什么都没有影响,不影响结果。

 

11. 表连接

A LEFT JOIN B=====A LEFTOUTERJOIN B ====BRIGHTJOIN A

A RIGHT JOIN B =====A RIGHTOUTERJOIN B

A FULL JOIN B ======A FULLOUTERJOIN B

A INNER JOIN B===== A JOIN B

什么叫反连接呢,反连接(Anti-Join)用于从一个表中返回不在另一个数据源中的记录。

方法有三种: 第一种: not in     第二种: not  exists

第三种就是先使用左外连接或者右外连接,然后只保留不匹配的记录。

根据速度效率等建议首先使用第三种,然后第二种,最差第一种。如下这篇文章进行了详细分析,可以看看。

http://blog.itpub.net/post/33136/388503

 

12. 使用translate和replace函数。

 

13. oracle如何处理根据不同情况插入数据到不同的目标表。(mysql不支持)p70

orcle:

insert  all

when  loc in(2,4) then

into table1(col1, col2, col3) values ( cola, colb, colc)

when  loc in(1,3) then

into table2(col1, col2, col3) values ( cola, colb, colc)

else

into table3(col1, col2, col3) values ( cola, colb, colc)

select cola, colb, colc from dept;


insert all 和insert first的区别是 ,对于同一行数据, first在遇到表达式为真的情况就不在往后执行,all则每一条都判断和执行。

所以all有可能同一条数据插入多个表,只要满足多个条件。

 

 

14.使用其他表的值更新本表的值 p75

 

update emp e set (e.sal, e.comm) = (selecct ns.sal, ns.sal/2 from new_sal ns where ns.deptno = e.deptno)
where exists( select 1 from new_sal ns where ns.deptno = e.deptno)


这里必须要使用第二句where进行过滤,确保对什么样的数据进行操作。

因为更新emp数据,deptno相同的数据需要更新,但是deptno如果找不到相同的呢?那么(selecct ns.sal, ns.sal/2 from new_sal ns where ns.deptno = e.deptno)这条语句返回的就是空,所以其他本不应该被更新的数据就更新成空了,这不是我们要的结果。于是需要后边的条件进行过滤。切记切记。

或者通过inner join进行连接,也可以。

update emp e INNER JOIN dept d on  d.deptno = e.deptno 
set e.sal = d.sal/2


15 merge(oracle专用)            p78

 

merge into tablea a
using (select * from tableb ) b
        on (a.num = b.num)
when matched then
       update set a.com = 1000
when not matched then 
        insert (a.c1, a.c2, a.c3)
        values(b.c1, b.c2, b.c3)

16. P90  动态生成sql

select 'select count(*) from ' || table_name || ';'   counts from user_tables;

 

第五章  P83 元数据查询

第六章  使用字符串,非常强大

 


 

 

 

 

 

 

 

 

你可能感兴趣的:(读书笔记——SQL CookBook)