sql 語句系列(多表之鏈)[八百章之第三章]
阿新 • • 發佈:2020-03-23
### 新增連線查詢而不影響其他連線查詢
請看圖:
![](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相同。
所以這種情況儘量不要去使用這種