1. 程式人生 > >JavaSE_day23:資料庫多表查詢

JavaSE_day23:資料庫多表查詢

#1. 連線查詢
                          內     連線
    select ... from 表1 inner join 表2 on 連線條件 WHERE ... group by ... HAVING ... ORDER BY ... limit ... (重點)
    
                          左    外  
    select ... from 表1 left [outer] join 表2 on 連線條件 (重點)
    
                          右    外
    select ... from 表1 right [outer] join 表2 on 連線條件
    
                          全
    select ... from 表1 full join 表2 on 連線條件 (mysql不支援全連線)
    
    
    例:連線部門表和員工表
    select * from emp a inner join dept b on a.deptno=b.deptno;
    
    注意:
    1) 內連線是將兩張表中所有符合連線條件的資料列入結果,不符合連線條件的結果中沒有,例如40號部門
    2) 如果連線的兩表中有同名的列,列前面要加表名(或表別名)來區分(否則會報歧義錯誤)
    3) inner join ... on 的寫法是符合SQL-92標準寫法,其實還有一種內連線的寫法:        
    select ... from 表1, 表2 where 連線條件;        
    例: 還是連線部門表和員工表 select * from emp a, dept b where a.deptno=b.deptno; 
        
    連線學生表成績表
    課程表連線老師表
    課程表連線成績表    
        
    例子:採用左外連線員工表和部門表
    select * from emp a left join dept b on a.deptno = b.deptno;
    例子:採用左外連線部門表和員工表
    select * from dept b left join emp a on a.deptno = b.deptno;
    左外連線,首先將符合連線條件的記錄連在一起,作為結果,其次左邊表中不符合連線條件的記錄也會出現在結果中,只不過它對應的右邊的列都是NULL
    
    例子:右外連線
    select * from emp a right join dept b on a.deptno = b.deptno;
    
    注意:左外和右外與表的先後次序有關,而內連線與表的先後次序無關
    
#2. 多表連線
    select * from 表1 
        inner join 表2 on 連線條件
        inner join 表3 on 連線條件
        ...
        
    例子
    select * from student a inner join sc b on a.sid = b.sid
                             inner join course c on b.cid = c.cid
                             inner join teacher d on c.tid = d.tid
                             order by a.sid, b.cid;
    
    等價寫法:
    select * from student a, sc b, course c, teacher d
                 where a.sid=b.sid and b.cid=c.cid and c.tid=d.tid;
    
    左外多表連線:
    select * from student a left join sc b on a.sid = b.sid
                             left join course c on b.cid = c.cid
                             left join teacher d on c.tid = d.tid
                             order by a.sid, b.cid;
    注意:左外多表連線要全部使用left join,不能再出現inner join
    
    效能上:連線的表越多,效能越低, 可以把連線查詢變成分多次查詢

#3. 自連線
    一個表自己和自己連線
    找到員工的姓名和上級的姓名
    select a.empno,a.ename,a.mgr,b.empno,b.ename,b.mgr
     from emp a left join emp b on a.mgr=b.empno;
    
    以後經常用於樹狀結構的資料表示
    陝西省
        西安
            雁塔區
            高新區
        咸陽
        寶雞
    id    name     parent_id
    1     陝西省   null
    2     西安     1
    3     雁塔區   2
    
#4. 子查詢
把某個select結果當做一個值,或一張表做進一步的查詢

情況1:找具有最高工資的員工資訊(子查詢作為值)

select max(sal) from emp; // 5000

select * from emp where sal = (select max(sal) from emp);

把select max(sal) from emp當成了一個值,代入到主查詢當中,代入時需要在子查詢的兩邊加()

情況2: 獲取每個部門的平均工資和部門的名稱(子查詢作為表)
先查詢平均工資
(select deptno,avg(sal) from emp group by deptno) a

再把子查詢看做臨時表,與其它表做表連線
select * from (子查詢)a inner join dept b on a.deptno=b.deptno;

練習:
1) 查詢所有同學的學號、姓名、選課數、總成績

   (select sid, count(*),sum(score) from sc group by sid) a
   
   select * from (select sid, count(*),sum(score) from sc group by sid) a 
    inner join student b on a.sid=b.sid;
    
   select a.*,b.sname from (select sid, count(*) 選課數,sum(score) 總成績 from sc group by sid) a 
    inner join student b on a.sid=b.sid;

2) 查詢學生平均成績大於80的所有學生的學號、姓名和平均成績 
   (select sid, avg(score) 平均成績 from sc group by sid having(avg(score)>80)) a
   
   select a.*, b.sname from (select sid, avg(score) 平均成績 from sc group by sid having(avg(score)>80))a 
    inner join student b on a.sid=b.sid;

3) 查詢課程相同且成績相同的的學生的學號、課程號、學生成績
    (select cid,score from sc group by cid,score having count(*) > 1) a
    
    select * from (select cid,score from sc group by cid,score having count(*) > 1)a 
        inner join sc b on a.cid=b.cid and a.score=b.score;
    
    
4) 查詢每個部門有最高工資的員工的(所有)資訊
(select deptno,max(sal) msal from emp group by deptno) a

select b.* from (select deptno,max(sal) msal from emp group by deptno)a 
    inner join emp b on a.deptno=b.deptno and a.msal=b.sal;
    
    
情況3: 將子查詢當做一個函式 (瞭解)

(select max(sal) from emp where deptno =?)

m(deptno)   返回結果是這個deptno下的最大工資

部門編號是一個入參, 最大工資是返回結果

select * from emp e where sal = m(e.deptno);  // 虛擬碼

select * from emp e where sal = (select max(sal) from emp where deptno = e.deptno); 


#6. 事務
DDL create alter drop truncate
DML insert update delete select 
TCL start transaction, commit, rollback

## 6.1 start transaction 開始事務 (begin)
## 6.2 commit 提交事務 
## 6.3 rollback 回滾事務


賬戶表account
ID      balance(餘額)
1       50000.0       
2       0.0           
create table account (
 id int primary key,
 balance decimal(12,2) not null
); 
insert into account(id,balance)values(1,50000.0),(2,0.0);
以下兩條sql必須作為一個整體執行, 要麼都成功,其中有一條失敗,前面成功的也得撤銷
update account set balance=balance+10000.0 where id=2; /*2號賬戶轉入10000元*/ 成功
update account set balance=balance-10000.0 where id=1; /*1號賬戶轉出10000元*/

所謂的事務,就是指一個事務內,多條sql語句是作為一個整體執行的。
一個事務內的多條sql是作為一個原子操作,不可以被分割。要麼都成功,要麼都不成功。
start TRANSACTION;
UPDATE
UPDATE
INSERT
DELETE
如果這個事務內多條sql全部成功 COMMIT(讓更改都生效)
如果這個事務內有sql失敗了,Rollback(讓更改都撤銷)

事務內所有更改,在結束之前,對於其它使用者來講都是不可見的。
事務commit提交時,這些更改才會真正生效,其它使用者才能看到你的更改。
事務執行中如果出現意外情況,這時候可以執行rollback,可以撤銷事務內所有更改,恢復到事務開始的時刻
commit 和rollback都意味著事務結束
事務有四大特性
ACID

A 原子性, 指事務內多條sql是作為一個整體執行
C 一致性, 事務開始前後,整個資料的狀態應當一致
I 隔離性, 指事務的隔離級別(未提交讀,提交讀,可重複讀,序列化讀)
    1) 髒讀(讀取到了未提交的資料)
    客戶1                         客戶2
    1 號賬戶餘額 10000.0
    begin;
    update 1 號賬戶餘額50000.0
                                  select 1 號賬戶餘額 50000.0 髒讀
    rollback;                                 
                                    select 1 號賬戶餘額 50000.0
    
    2)避免髒讀現象, 將隔離級別升級為提交讀
    查詢到的肯定是別人提交後的結果,提交讀下不會有髒讀,    但會有不可重複讀現象:
    客戶1 更新                   客戶2查詢
    1 號賬戶餘額 10000.0
                                  begin;
                                  select ... 10000.0
    begin;
    update 1 號賬戶餘額50000.0;
    commit;
                                  select ... 50000.0
                                  commit;
    
    3) 為了避免不可重複和髒讀的現象,可以將隔離級別升級可重複讀(mysql預設隔離級別)    
    4) 幻讀 (可以將隔離級別提高為序列化讀,即可避免幻讀現象)     
    
    客戶1 新增                    客戶2查詢
    原始記錄是10條
    begin                          begin;
                                    查詢個數  10
    insert 1
    commit;    
                                    查詢個數  11
                                    
                                    commit;
    5) mysql的【可重複讀】隔離級別三種現象都可以避免
D 永續性, 事務中做的更改必須在事務結束後永久生效
增刪改查(insert update delete select)
CRUD   c  insert 插入
       r  select 查詢
       u  update 更新
       d  delete 刪除
# 7. DCL 資料控制語言 (瞭解)
grant 授權
revoke 回收許可權
create user 'user1'@'localhost' identified by 'user1';
登入之後執行use test3;
會報告  Access denied for user 'user1' 含義是使用者無權訪問.
使用root 給user1授權
grant all on test3.* to 'user1'@'localhost'; 
all 是代表所有許可權:select,insert,update,delete...
test3.* 是許可權的範圍:test3庫中所有物件
to 後面跟的是使用者
使用root回收許可權
revoke all on test3.* from 'user1'@'localhost';
更細的許可權分配
grant select on test3.student to 'user1'@'localhost';  /*只讓test1使用者能夠查詢test3.student表*/