SQL學習:SQLCookBook源代碼-mysql版本(3)



<span style="font-size:14px;">--EmpAndDept4
--主要關於表格的更復雜查詢(多表、多層)、視圖的創建


--複雜的多表查詢
--分爲查詢、子查詢、連接查詢
--簡單解釋如下:
select * from emp;                                          --查詢
select * from (select empno,sal from emp) v;                  --子查詢
select * from emp e left join dept d on e.deptno=d.deptno;  --連接查詢
--注:子查詢的話,子表需要附名字




--顯示錶格前幾行
select * from emp limit 4;
--顯示前幾名,降序、必須有別名x,否則會報錯
select * from(select * from emp order by sal) as x limit 4;
--選取表示爲:clark as a manager即'ename' as a 'job'
select concat(ename,' work as a ',job) as x from emp where deptno=10;
--隨機產生5個實例
select ename,job from emp order by rand() limit 5;
--選取comm列,同時用0來代替空值  PS:isnull(comm)返回的是1,0;coalesce(comm)返回的是實際值和0
--也可以使用case函數 is null then 0
select ename,coalesce(comm) as comm from emp;


--重複的數據
--union對2個結果集取並集,重複數據僅顯示一次
--union all 對結果取並集,重複數據全部顯示
--如下例子(所謂視圖就是臨時表的意思,但要知道,當實際表的內容改變時,視圖的表也會跟着改變)
--第二個語句創建的v將在後面使用到
create view v as select * from emp union select * from emp;
create view v as 
       select * from emp where deptno!=10 
       union all 
       select * from emp where ename='WARD';


--exists函數(速度較快)
--功能跟in有點類似,exists()括號內存在時返回true,否則返回false
--記住exists裏面的where需要跟外部的dept表有聯合,否則exists會只返回true
--例子:查詢在deptno裏,emp裏沒有的部門
select depno from dept d where not exists(select deptno from emp e where e.deptno=d.deptno);


--例子:使用關聯子查詢和union all 來查找視圖V中存在而在表emp中不存在的行,然後與在表emp中存在而在視圖v中不存在
--的行進行合併
--cookbook上的這個例子簡直又臭又長,花了好長功夫才搞懂,如下:
--要看懂這個得簡化下他的表達式如下:
--select * from e where not exists(select null from v where v.all=e.all)
--意思就是當e中的數據,v中有時,not exists就返回false,沒有時則返回true,ok,這就是我們要的那行,選出來
--select null是選出一列null列,通常用在exists,表示我們其實不是要選列,只是想通過他的返回來判斷真假
--記住這裏的null列在exists中是真值
select * 
from (  
      select e.empno,e.ename,e.job,e.mgr,e.hiredate,
             e.sal,e.comm,e.deptno,count(*) as cnt 
      from emp e 
      group by empno,ename,job,mgr,hiredate,sal,comm,deptno
      ) e 
where not exists
      (
      select null 
      from(
           select v.empno,v.ename,v.job,v.mgr,v.hiredate,
                  v.sal,v.comm,v.deptno,count(*) as cnt
           from v
           group by empno,ename,job,mgr,hiredate,sal,comm,deptno
           ) v
      where  v.empno=e.empno
         and v.ename=e.ename
         and v.job=e.job
         and v.mgr=e.mgr
         and v.hiredate=e.hiredate
         and v.sal=e.sal
         and v.deptno=e.depno
         and v.cnt=e.cnt
         and coalesce(v.comm,0)=coalesce(e.comm,0)
      )
      
      union all
      
select * 
from (--跟上面一模一樣,只是把v跟e倒換過來了,可以自己寫一遍試試
     )


     
--創建一個emp_bonus 表
create table emp_bonus(
    empno int primary key,
    received date,
    type int,
    )engine=InnoDB;
insert into emp_bonus values(7934,2005-3-17,1);
insert into emp_bonus values(7839,2005-2-15,3);
insert into emp_bonus values(7782,2005-2-15,1);
--插入以下行,會發現插入失敗,所以現在我們要先學下怎麼去除主鍵
insert into emp_bonus values(7934,2005-2-15,2);
--去除主鍵:1.先去除自增長  2.去除主鍵
--(自增長的意思是即使你的insert裏面沒有主鍵,他也會默認設置爲0,但是下次再這樣insert就不行了,因爲主鍵唯一,不能再默認爲0)
alter table emp_bonus empno empno int(10);
alter table emp_bonus drop primary key;
--之後再insert




--返回所有員工的姓名,工資,部門號和獎金,type爲1時獎金爲薪水的10%,type爲2時獎金爲薪水的20%,3時爲30%
select e.empno,e.ename,e.deptno,e.sal,e.sal* case 
   when eb.type=1 then .1
   when eb.type=2 then .2
   when eb.type=3 then .3
   else 0
   end as bonus
   from emp e left join emp_bonus eb on e.empno=eb.empno;
--注意結果miller有2個獎金


--可以使用sum和group by將相同員工編號的人獎金彙總到一起   
select e.empno,e.ename,e.deptno,e.sal,sum(e.sal* case 
   when eb.type=1 then .1
   when eb.type=2 then .2
   when eb.type=3 then .3
   else 0
   end) as bonus
   from emp e left join emp_bonus eb on e.empno=eb.empno 
   group by e.empno;
    
--計算各個部門員工的全部薪水總和、全部獎金總和
select deptno,
       sum(sal) as total_sal,
       sum(bonus) as total_bonus
       from(
       select e.empno,e.ename,e.deptno,e.sal,e.sal* case 
              when eb.type=1 then .1
              when eb.type=2 then .2
              when eb.type=3 then .3
              else 0
              end as bonus
              from emp e left join emp_bonus eb on e.empno=eb.empno
           ) x
       group by deptno ;
--你會發現總體薪水那一欄返回的值是錯誤的,可以自己計算檢測一下,原因是因爲x中有重複的人被多次計算了,因爲他獲得了多個獎金
--解決辦法是在x中加入group by e.empno 
--但是隻加group的話會發現獎金那欄又不對了。。所以正確的做法是還要加入個sum函數統計bonus,如下:
select deptno,
       sum(sal) as total_sal,
       sum(bonus) as total_bonus
       from(
       select e.empno,e.ename,e.deptno,e.sal,sum(e.sal* case 
              when eb.type=1 then .1
              when eb.type=2 then .2
              when eb.type=3 then .3
              else 0
              end 
              ) as bonus
              from emp e left join emp_bonus eb on e.empno=eb.empno
              group by e.empno
           ) x
       group by deptno ;
--要注意到,上面的例子基本都使用了外聯接left join,如果這裏不是使用的外聯接而是where的話,自行對比下面兩個語句:


select e.empno,e.ename,e.deptno,e.sal,sum(e.sal* case 
              when eb.type=1 then .1
              when eb.type=2 then .2
              when eb.type=3 then .3
              else 0
              end 
              ) as bonus
              from emp e left join emp_bonus eb on e.empno=eb.empno
              group by e.empno;
              
select e.empno,e.ename,e.deptno,e.sal,sum(e.sal* case 
              when eb.type=1 then .1
              when eb.type=2 then .2
              when eb.type=3 then .3
              else 0
              end 
              ) as bonus
              from emp e ,emp_bonus eb 
              where e.empno=eb.empno
              group by e.empno;
--第二個語句只產生了含有bonus的列,有時需要這樣,但是當需要用到其他不含獎金的行一起來統計薪水總和時他就會出錯,
--如前面的例子,用where篩選出來的表無法得到total_sal</span>


mysql代碼github地址:

https://github.com/databatman/SQLCookBook-MysqlVersion

PS:所有的mysql的EmpAnd1-n代碼都會上傳到這個文件夾,順便求關注啊,雖然還是菜鳥一個,啊哈




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章