1. 程式人生 > 其它 >學習筆記 2021.12.9cont

學習筆記 2021.12.9cont

2021.12.9

聚合函式

常見的聚合函式

具體的count的使用場景的比較(預設具體欄位沒有非空的)。這裡涉及到更多底層方面的東西,到後面索引的時候再去具體瞭解,這裡就大概知道各自的結果就可以了:

其實,對於MyISAM引擎的表是沒有區別的。這種引擎內部有一計數器在維護著行數。

Innodb引擎的表用count(*),count(1)直接讀行數,複雜度是O(n),因為innodb真的要去數一遍。但好於具體的count(列名)。

group by

需求:查詢各個不同部門的聚合資料。

示例:

此時也可以多個列同時group by,即在一個類中再細分,示例如下:

使用的注意事項:

  • select中出現的非組函式的欄位必須宣告在group by中,反之則不是必然要求。
  • group by宣告在from後面,where後面,order和limit前面。
  • 在後面新增with rollup可以多顯示一個總體的計算後的結果。知道有這麼個東西就好,一般也不常用。

having的使用

作用:也是過濾資料的。

過濾分組:HAVING子句

  1. 行已經被分組。
  2. 使用了聚合函式。
  3. 滿足HAVING 子句中條件的分組將被顯示。
  4. HAVING 不能單獨使用,必須要跟 GROUP BY 一起使用。

顯示各個部門中最高工資比10000高的部門資訊。

使用tips:

  • 如果過濾條件中使用了聚合函式,則必須用having來替換where,作為一種習慣去適應。但是如果沒有聚合函式,兩種都可以,但是推薦用where。
  • 且having必須在group by後面。

下面的這種方式也是合理的,注意兩種篩選條件的區分:

但是這種方式也不推薦,最後還是按照規範來寫。

where和having的對比

  • having的使用範圍更廣。
  • 沒有聚合函式時,where的效率要比having好。

具體的分析後面涉及到底層的時候再去詳細瞭解。

優點 缺點
WHERE 先篩選資料再關聯,執行效率高 不能使用分組中的計算函式進行篩選
HAVING 可以使用分組中的計算函式 在最後的結果集中進行篩選,執行效率較低

select的執行過程

常見的sql99的全部包含的語法:

但執行的順序卻是如下,而不是上面的編寫順序

1. 關鍵字的順序是不能顛倒的:

SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT...

2.SELECT 語句的執行順序(在 MySQL 和 Oracle 中,SELECT 執行順序基本相同):

FROM -> WHERE -> GROUP BY -> HAVING -> SELECT 的欄位 -> DISTINCT -> ORDER BY -> LIMIT

比如你寫了一個 SQL 語句,那麼它的關鍵字順序和執行順序是下面這樣的:

SELECT DISTINCT player_id, player_name, count(*) as num # 順序 5
FROM player JOIN team ON player.team_id = team.team_id # 順序 1
WHERE height > 1.80 # 順序 2
GROUP BY player.team_id # 順序 3
HAVING num > 2 # 順序 4
ORDER BY num DESC # 順序 6
LIMIT 2 # 順序 7

在 SELECT 語句執行這些步驟的時候,每個步驟都會產生一個虛擬表,然後將這個虛擬表傳入下一個步驟中作為輸入。需要注意的是,這些步驟隱含在 SQL 的執行過程中,對於我們來說是不可見的。

  • 即是先找表,再分組和篩選。然後再按照select的條件來呈現。
  • 這時就可以去理解select和having的功能區別了,where在遍歷的過程中即實行了篩選的操作,這樣在後面的group和having操作就可以省略很多,但是如果在having中進行實現的話,則會對所有的分組進行計算,但是實際上也不需要其他組的計算。

子查詢

即理解為查詢的巢狀。子查詢指一個查詢語句巢狀在另一個查詢語句內部的查詢,這個特性從MySQL 4.1開始引入。

SQL 中子查詢的使用大大增強了 SELECT 查詢的能力,因為很多時候查詢需要從結果集中獲取資料,或者需要從同一個表中先計算得出一個數據結果,然後與這個資料結果(可能是某個標量,也可能是某個集合)進行比較。

比如下面這種問題即是符合子查詢的場景:

子查詢的寫法:

即可以直觀的看到是查詢的巢狀。

  • 子查詢的基本語法結構:
  • 子查詢(內查詢)在主查詢之前一次執行完成。
  • 子查詢的結果被主查詢(外查詢)使用 。
  • 注意事項
    • 子查詢要包含在括號內
    • 將子查詢放在比較條件的右側
    • 單行操作符對應單行子查詢,多行操作符對應多行子查詢

子查詢的分類

單行子查詢和多行子查詢。即內查詢的結果是一個還是多個。

相關子查詢和不相關子查詢。即內查詢是否被執行多次。相關子查詢的需求:查詢工資是否大於本部門平均工資的員工資訊。

單行子查詢

最好理解的一種

單行比較操作符

操作符 含義
= equal to
> greater than
>= greater than or equal to
< less than
<= less than or equal to
<> not equal to

這裡就看一個例子就行

Q:查詢與141號員工的manager_id和department_id相同的其他員工的employee_id,manager_id,department_id

SELECT  employee_id, manager_id, department_id
FROM    employees
WHERE   manager_id IN
		  (SELECT  manager_id
                   FROM    employees
                   WHERE   employee_id IN (141)
AND     department_id IN 
		  (SELECT  department_id
                   FROM    employees
                   WHERE   employee_id IN (141)
AND	employee_id NOT IN(141);

having中的子查詢

直接看例子

Q:查詢最低工資大於50號部門最低工資的部門id和其最低工資

SELECT   department_id, MIN(salary)
FROM     employees
GROUP BY department_id
HAVING   MIN(salary) >
                       (SELECT MIN(salary)
                        FROM   employees
                        WHERE  department_id = 50);```

case中的子查詢

題目:顯式員工的employee_id,last_name和location。其中,若員工department_id與location_id為1800的department_id相同,則location為’Canada’,其餘則為’USA’。

SELECT employee_id, last_name,
       (CASE department_id
        WHEN
             (SELECT department_id FROM departments
	      WHERE location_id = 1800)           
        THEN 'Canada' ELSE 'USA' END) location
FROM   employees;

其他需要注意的

子查詢中的空值問題

SELECT last_name, job_id
FROM   employees
WHERE  job_id =
                (SELECT job_id
                 FROM   employees
                 WHERE  last_name = 'Haas');

子查詢不返回任何行

非法使用子查詢

SELECT employee_id, last_name
FROM   employees
WHERE  salary =
                (SELECT   MIN(salary)
                 FROM     employees
                 GROUP BY department_id);

多行子查詢使用單行比較符

多行子查詢

  • 也稱為集合比較子查詢
  • 內查詢返回多行
  • 使用多行比較操作符

多行比較操作符

操作符 含義
IN 等於列表中的任意一個
ANY 需要和單行比較操作符一起使用,和子查詢返回的某一個值比較
ALL 需要和單行比較操作符一起使用,和子查詢返回的所有值比較
SOME 實際上是ANY的別名,作用相同,一般常使用ANY

注意此時in對於單行查詢自然也是可以的。

例子

返回其它job_id中比job_id為‘IT_PROG’部門所有工資都低的員工的員工號、姓名、job_id以及salary

SELECT employee_id,last_name,job_id,salaryFROM employeesWHERE job_id <> 'IT_PROG'AND salary < ALL(		SELECT salary		FROM employees		WHERE  	job_id = 'IT_PROG'		);

查詢平均工資最低的部門id

注意聚合函式是沒法去巢狀的。

SELECT department_idFROM employeesGROUP BY department_idHAVING AVG(salary)=(SELECT MIN(asal)FROM(SELECT department_id,AVG(salary) asalFROM employeesGROUP BY department_id) dd);

這種情況注意一點就是因為group by後生成的也是一系列的資料,可以將其看作資料去比較,也自然可以看作表填到from後面的子迴圈裡面,這也是上面方法的思路。