1. 程式人生 > >sql 語句系列(多表之鏈)[八百章之第三章]

sql 語句系列(多表之鏈)[八百章之第三章]

### 新增連線查詢而不影響其他連線查詢 請看圖: ![](https://img2020.cnblogs.com/blog/1289794/202003/1289794-20200322224315615-1346978573.png) 這種情況我們一般會使用左連線的方式。 ``` select e.ENAME,d.LOC,eb.RECEIVED from emp e join dept d on(e.DEPTNO=d.DEPTNO) left join emp_bonus eb on(eb.EMPNO=e.EMPNO) order by 2 ``` 上面這種可以實現的,但是不利於我們在寫code語句中的複用。 下面是一種標量子查詢我的方式,可以幫助我們複用部分sql。 ``` select e.ENAME,d.LOC,(select eb.RECEIVED from emp_bonus eb where e.EMPNO=eb.EMPNO) as RECEIVED from emp e join dept d on(e.DEPTNO=d.DEPTNO) order by 2 ``` 這裡原理很簡單,其實就是先設定了RECEIVED 行然後去查詢。 同樣這裡有限制就是RECEIVED 查詢出來必須只有一個結果,因為開闢了一個空間。 在未來第600章中會介紹如果針對查詢出多行的問題。 ### 組合使用連線查詢與聚合函式 ``` select e.DEPTNO,e.EMPNO,e.ENAME,e.SAL,e.SAL*case when eb.TYPE=1 then 0.1 when eb.TYPE=2 then 0.2 when eb.TYPE=3 then 0.3 end as bonus from EMP e,emp_bonus eb where e.EMPNO=eb.EMPNO and e.DEPTNO=10 ``` ![](https://img2020.cnblogs.com/blog/1289794/202003/1289794-20200322231323506-991329788.png) 現在只需要看到上圖的表。 現在有一個需要,就是要統計上面部門為10的SAL 和 bonus。 這個時候一般想到的是聚合函式。 ``` select x.DEPTNO,sum(x.SAL) as total_sum,sum(x.bonus) as total_bonus from (select e.DEPTNO,e.EMPNO,e.ENAME,e.SAL,e.SAL*case when eb.TYPE=1 then 0.1 when eb.TYPE=2 then 0.2 when eb.TYPE=3 then 0.3 end as bonus from EMP e,emp_bonus eb where e.EMPNO=eb.EMPNO and e.DEPTNO=10) x group by x.DEPTNO ``` ![](https://img2020.cnblogs.com/blog/1289794/202003/1289794-20200322231727812-407566200.png) 得到的結果為錯誤的。因為有人得到兩次獎勵: ![](https://img2020.cnblogs.com/blog/1289794/202003/1289794-20200322231901975-1605681221.jpg) 那麼可能會這樣寫: ``` sql (select e.DEPTNO,e.EMPNO,e.ENAME,e.SAL,e.SAL*case when eb.TYPE=1 then 0.1 when eb.TYPE=2 then 0.2 when eb.TYPE=3 then 0.3 end as bonus from EMP e,emp_bonus eb where e.EMPNO=eb.EMPNO and e.DEPTNO=10) x group by x.DEPTNO ``` 排除掉sal中相同的項增加,但是萬一有人sal相同怎麼辦?這肯定是一個問題。還有一個問題就是如果這個部門有一部分人如果沒有得到bonus怎麼辦?也就是說有一部分SAL沒顯示出來 ``` sql select x.DEPTNO, d.total_sum,sum(x.bonus) as total_bonus from (select e.DEPTNO,e.EMPNO,e.ENAME,e.SAL,e.SAL*case when eb.TYPE=1 then 0.1 when eb.TYPE=2 then 0.2 when eb.TYPE=3 then 0.3 end as bonus from EMP e,emp_bonus eb where e.EMPNO=eb.EMPNO and e.DEPTNO=10 ) x,(select DEPTNO,sum(EMP.SAL) as total_sum from EMP where EMP.DEPTNO=10 group by EMP.DEPTNO) d where d.DEPTNO=x.DEPTNO group by x.DEPTNO,d.total_sum ``` 我們可以通過之查詢出sum(x.bonus),然後再外表連接出d.total_sum。 優化一下: ``` sql select e.DEPTNO,d.total_sum,sum(e.SAL*case when eb.TYPE=1 then 0.1 when eb.TYPE=2 then 0.2 when eb.TYPE=3 then 0.3 end) as bonus from EMP e,emp_bonus eb,(select DEPTNO,sum(EMP.SAL) as total_sum from EMP where DEPTNO=10 group by DEPTNO) d where e.EMPNO=eb.EMPNO and e.DEPTNO=d.DEPTNO group by e.DEPTNO,d.total_sum ``` 優化的依據是: 出現兩個EMP.DEPTNO=10 條件可以合併,第二點就是沒必要查e.ENAME這些,可以直接合並。 有些人可能使用sum over 函式去寫: ``` sql select e.DEPTNO,sum(distinct e.SAL) over (partition by e.deptno) as total_sum,sum(e.SAL*case when eb.TYPE=1 then 0.1 when eb.TYPE=2 then 0.2 when eb.TYPE=3 then 0.3 end) over (partition by e.deptno) as bonus from EMP e left join emp_bonus eb on e.EMPNO=eb.EMPNO where e.DEPTNO=10 ``` 我上面使用了外連線,是避免這個部門有一部分人如果沒有得到bonus。 其中有兩個問題,一個就是over 語句中不能包括distinct了,第二個就是不同人empno 中可能sal相同。 所以這種情況儘量不要去使用這種