SQL 查询学习笔记

语句的执行顺序必须掌握


1 .  =  和in的区分

       = 就是唯一条件, in 表示一个范围

       SELECT a.*
       FROM city AS a 
       where a.CountryCode in (select `Code` from country as b where b.Population = 22720000 or b.Population=15864000)

       如果子查询返回的 一个值,用=或in都可以,但如果是多个值,一定要用in,在SQL  server 中,in 后可是一个范围

2.  查询条件放在where 还是on后面

      SELECT a.*,b.*
     FROM city AS a 
     INNER JOIN country AS b ON a.CountryCode = b.`Code` and b.Population >1000

     或者

     SELECT a.*,b.*
     FROM city AS a 
     INNER JOIN country AS b ON a.CountryCode = b.`Code` 
     where b.Population >1000

     这两个语句都能满足要求,不过根据运行的顺序,在On里面写条件可以先过滤掉一部分,where是在on后执行,所以从优化的角度讲放在on里面运行速度快。


    select a.A,a.B, b.C, b.D from ta a

    left join ta2 b  on a.id=b.id and b.D <3

结果是

A    B    C    D 

as   12   12   1

ed    13    13    2

ed    13    24     NULL

egf    34     44   NULL

如果变成

   select a.A,a.B, b.C, b.D from ta a

    left join ta2 b  on a.id=b.id 

 where  b.D <3

结果会是

A    B    C    D 

as   12   12   1

ed    13    13    2

这里面涉及次序问题

这种原理也用在一个表中与其它表中不匹配的记录查询 ,在连接后用where过滤掉非空的,也叫反连接

select d.*

from dept d left out join emp e 

on (d.depno=e.depno)

where e.depno is NULL









    




3. 相关子查询和非相关子查询

  关联子查询的语句不是一次执行完毕,而是每一个候选行执行一次,子查询依赖于外查询提供的数据。

子查询在 where 后

 select * from city b where (select sum(a.Population)from city a where a.id=b.id) between 10000 and 20000

注意子查询内部用的where,不是group和聚合函数,因为这时是一行一行执行,每次返回一个结果。

select * from city b where (id,CountryCode)=(select min(id),CountryCode from city a where a.CountryCode=b.CountryCode)

exists 的用法,只看存在不存在,不关心值

子查询作为表达式生成器,及Select后

Select

(select p.name from product p where p.product_cd=a.product_cd and p.product_type_cd='ACCOUNT' ) product,

(select b.name from branch b where b.branch_id=a.open_branch_id) branch,

(select concat(e.fname,' ',e.lname) from employee e where e.emp_id) name,

SUM(a.avail_balance) total_deposits

from account a

group by a.product_cd, a.open_branch_id,a.open_emp_id

order by 1,2.

标量子查询也可出现在Order   by 后,此时子查询返回一行或者关联子查询返回一行

select emp.emp_id,concat(emp.fname, ' ',emp.lname) emp_name,

(select concat(boss.fname,' ',boss.lname) 

from employee emp

where emp.superior_emp_id is not null

order by (select boos.lname from employee boss where boss.emp_id=emp.superior_emp_id), emp.lname.

 理解问题

有2个表 employees和salary,用employeeID联系起来,employees里面有name,employeeID,workyear,sex,birthday等等,然后salary里面有employeeID和inCome和outcome。在order by子句中使用子查询,查询员工姓名,性别和工龄信息,要求按实际收入从大到小排列
回答:
select * from employees a order by (select income-outcome from salary where employeeid=a.employeeid)


select ename,sal,job,comn

from emp

order by case when job='Saleman' then comn else sal end

这句和下面的功能一样

select ename, sal,job,comn,

 case when job='Saleman' then comn else sal end

order by 5


子查询不能用在group by后了,其它的都可以

Having, order by 后可是子查询或聚合函数,这些也可不在select list 里面出现















4. 自连接, 自然连接(有些不支持),内连接,外连接(left join, right join) 和交叉连接

    自连接直接用select  from多表实现的

    其它的都和Join相关

    注意在最开始的时候都是以卡笛尔积作为中间表,这样在最后Select list 的时候一定要慎重,有可能产生重复行,需要distinct去除掉。

    或者在连接的时候就转化成一对一的连接,避免重复

    内连接分等值连接和非等值连接, 一般非等值连接是在已经有的等值连接基础上,增加一个其它的非等值判断条件( 表的连接至少要一个相等的值连接才有意义)


  5 .聚合函数直接出现在Select list 和以(select  聚合函数(list) from table) 出现在select list 中的不同

select `Code`, Continent, format(avg(Population),2) as Avg1, (select format(avg(Population),2) from country) as Avg2
from country
group by Continent,`Code`

where 后面不能直接放聚合函数,需要子查询 select 聚合函数,  having 后直接聚合函数,。。。这些都和执行顺序相关,

select distinct a.`Name`,
case 
    when LENGTH(a.Name)>7 then 'Chang'
    when Length(a.Name)>4 then 'Zhong'
    else 'Duan'
 end as Judgement,
b.`Code`, concat(a.`Name`,'   ', b.`Code`),concat (b.Code,cast(b.SurfaceArea as char(2))) as Field1, sum(c.Percentage)
from city as a 
left join  country  as b on a.CountryCode=b.`Code` and b.Region  not  in 
(select d.Region from country as d where d.Region like '%Africa%' escape 'a')
right join countrylanguage as c on c.CountryCode=b.`Code`
where c.Percentage > (select avg(d.Percentage) from countrylanguage as d where b.code=d.CountryCode and b.GNPOld is not Null)  /×注意此时的select 聚合函数×/
group by a.`Name`, Judgement,b.`Code`,concat(a.`Name`,'   ', b.`Code`),concat(a.`Name`,'   ', b.`Code`),Field1
having b.code REGEXP '^[ABC]'  
and sum(c.Percentage)>80  /*注意此时放什么判断条件, 可以直接聚合函数×/
or sum(c.Percentage)  not between 20 and 60
order by sum(c.Percentage) desc, a.`Name`



    如上Avg1 算出的是通过group by 而聚合的, Avg2是所有的,和这里的Group by 没关系,因此Avg2这种形式出现,时不必配套相应的Group by

6. 聚合函数不一定要和 Group  by 组合, 如下当只有一个结果时,或者Group by 分完的group只有一行是可以不使用Group by,直接用where 选择一个条件进行聚合

having 句子有可能在没有Group 的句子中,这些的基础都是只有一个group,只一行

但如果多个结果多个组的时候一定要Group by

select Continent, format(avg(Population),2) as Avg1, (select format(avg(Population),2) from country) as Avg2
from country
where  Continent='Asia'

having avg(Population)>24


 select count(*) as number from employee where sex='female' and salary>1500   用where

 select count(*) from employee 

7.  多表连接 , 注意表连接的次序,然后是中间隐藏的连接关系, 

像滚雪球一样,一个表一个表的滚进去。注意不同的优化器选择不同的驱动表,Straight_join的用法

select a.*,b.*,c.*
from person a
right join person1 b on a.`name`=b.`name`        /*把B行排除在外*/ 
right join person2 c on a.alias=c.alias and b.id=c.id         /*c,b表之间把D行排除在外, a,c之间把A行排除在外,由于隐含了B行排除在外,因此总的结果是把A,D,B行都排除在外 */

8,自内外连接, 表和自身连接

比如员工和主管同在一张表上,要选择出员工和主管的关系,

select e.fname, e.lname, e_mgr.fname, e_mgr.lname

from employee e inner join employee e_mgr

on e.superior_emp_id=e_mgr.emp_id

上面的查询如果没有主管,就不显示出来, 换个自左外连接

select e.fname, e.lname, e_mgr.fname, e_mgr.lname

from employee e left out join employee e_mgr

on e.superior_emp_id=e_mgr.emp_id

上面查询出所有员工,没有主管的员工也在表上,只不过一些列NULL值

select e.fname, e.lname, e_mgr.fname, e_mgr.lname

from employee e right out join employee e_mgr

on e.superior_emp_id=e_mgr.emp_id

上表查询了每个员工的下属,没有下属的一些列NULL









9. 查询的执行顺序,搞懂这个很关键, 相等连接和不相等连接。

10. 集合操作, 注意此处where可用在union前, 而where 不能直接用在 join前,除非括号括起来作为子查询

  select a,b  from job1

where a='c'

union 

select a,b from job2

where a='d',     这个where 执行顺序是union执行后选择,还是先执行完where 再union 呢? 应该是先where ,一般集合操作符优先级是比较低的,

select cust_id

from account

where product_cd in ('SAV','MM')

union all

select a.cust_id

from account a inner join branch b

on a.open_branch_id=b.branch_id

where b.name='Woburn Brde'

union select cust_id

from account

where avail_balance between 500 and 2500

执行顺序是什么? 加上group, order 后呢? 目前测试还是union 的优先级低







11.查询优化问题,排序等引起索引变化。

12.多列子查询

select * from city
where (id,CountryCode) in (select a.id, a.CountryCode from city a where a.id<10)

注意此时的 id,CountryCode 是同时按照行对应满足的,同时满足同行。

如果

select * from city

where id in (select a.id from city a where a.id<10)

and CountryCode in (select CountryCode from city a where a.id<10)

这个没有同时满足行对应关系,只要id在集合中,CountryCode就满足了

13 相等连接和不等连接,相等查询和不等查询

14 子查询和连接的互换,关联子查询和连接的效率问题

15 交叉连接

例子,构建一年365天

select data_add('2008-01-01',interval(ones.num+tens.num+hundreds.num) day dt

from

(select 0 num union all

 select 1 num union all

 select 2 num union all

select 3 num union all

select 4 num union all

select 5 num union all

select 6 num union all

select 7 num union all

select 8 num union all

select 9 num ) ones

cross join

(

select 0 num union all

 select 10 num union all

 select 20 num union all

select 30 num union all

select 40 num union all

select 50 num union all

select 60 num union all

select 70 num union all

select 80 num union all

select 90 num ) tens

cross join 

(select 0 num union all

select 100 num union all

select 200 num union all

select 300 num ) hundreds

where date_add('2008-01-01',interval(ones.num+tens.num+hundreds.num) day)<'2009-01-01'

order by 1;

13 case 表达式 和简单case 表达式

一个把值放在case 后,和when 运算的判断,一个直接使用when后的表达式判断

case表达式和子查询的结合

select c.cust_id,c.fed_id,

case

    when c.cust_type_cd='I' then

(select concat(i.fname,' ',i.lname) from individual i where i.cust_id=c.cust_id)

   when c.cust_type_cd='B' then

(select b.name from business b where b.cust_id=cust_id)

else 'Unknown'

end name

from customer c;

使用Case结果集变换( SQL server 有pivot 方式)

一般结果

 Year    how many

2000      3

2001      4

2002      5

2003      3

2004      9

变换成列

select

sum(case when extract(year from open_date)=2000 then 1 else 0 end )  year 2000,

sum(case when extract(year from open_date)=2001 then 1 else 0 end )  year 2001,

sum(case when extract(year from open_date)=2002 then 1 else 0 end )  year 2002,

sum(case when extract(year from open_date)=2003 then 1 else 0 end )  year 2003,

sum(case when extract(year from open_date)=2004 then 1 else 0 end )  year 2004

from account 

结果是

 year 2000   year 2001     year 2002   year 2003   year 2004

         3                4                     5                 3                     9

选择性聚合

select  *

from account a

where (a.avail_balance, a.pending_balance)<>

(select

   sum(case 

             when t.funds_avail_date>current_timestamp() then 0

             when t.txn_type_cd ='DBT'  then t.amount *-1

              else t.amount

              end),

   sum(case 

             when t.txn_type_cd='DBT' then t.amount*-1

                else  t.amount

             end )

from transaction t 

when t.account_id=a.account_id);

Case 用在除零错误和NULL值的处理上

14 any all

select * from employee where salary> any(select salary from employee where warehouse='wh2')

由于any要求只要有一行结果为真, 因此上面的等价于

select * from employee where salary >(select min(salary) from employee where warehouse ='wh2')

select * from employee where salary<any(select salary from employee where warehouse='wh2') 这个等价于

select * from employee where salary <(select max(salary) from employee where warehouse ='wh2')

注意这其中的min和max


all 要求所有行都为真

select * from employee where salary> all(select salary from employee where warehouse='wh2') 等价于

select * from employee where salary >(select max(salary) from employee where warehouse ='wh2')


15 别名

select * from (select e.empno, e.name,e.job,cont(*)  from emp e  group by e.empon,e.name,e.job ) e

注意这种内外同时一个别名,先执行完内部后,再把执行完的表命名为 这个别名

16.遍历字符串

用笛卡尔积生成行号,用来在该行中返回字符串中的每个字符。   注意方法的扩展

select substr(e.name,iter.pos,1) as c

from(select ename,from emp where ename='KING') e,

(select id as pos from from t10) iter

where iter.pos<=length(e.name)

t10 包含了10行,内容从1到10.











你可能感兴趣的:(sql)