mysql 基礎知識

来源:https://www.cnblogs.com/slivermirror/archive/2022/12/02/16945931.html
-Advertisement-
Play Games

學習中的思考 在 mysql 學習和使用中,我遇到了不少的難題,我覺得我應該形成一套邏輯思考體系,可以讓我在初識 mysql 的過程中加入理性思考,從一開始就探求原理,瞭解所學內容的核心和關鍵點,做到一葉知秋而不是只見樹木不見森林。 mysql 幾種數據類型的底層是如何存儲的,不同的 sql 語句對 ...


學習中的思考

在 mysql 學習和使用中,我遇到了不少的難題,我覺得我應該形成一套邏輯思考體系,可以讓我在初識 mysql 的過程中加入理性思考,從一開始就探求原理,瞭解所學內容的核心和關鍵點,做到一葉知秋而不是只見樹木不見森林。

  1. mysql 幾種數據類型的底層是如何存儲的,不同的 sql 語句對其有何限制?
  2. 學習 sql 語句時,需要思考:這個 sql 語句的底層是如何實現的,對哪些數據類型起作用,有什麼限制,如果這個 sql 語句對單欄位可以使用,可否在多欄位中使用,在多欄位使用的過程中,可否做到只對一個欄位起作用或者對多個欄位同時起作用?
  3. 隔離級別是如何實現的?

MySQL 基礎

一、為什麼要學習資料庫

二、資料庫的相關概念:

  • DB:資料庫(database),存儲數據的“倉庫”,它保存了一系列有組織的數據。
  • DBMS:資料庫管理系統(Database Management System),資料庫是通過 DBMS 創建和操作的容器。
  • SQL:結構化查詢語言(Structure Query Language),專門用來與資料庫通信的語言。

SQL的優點:

  1. 不是某個特定資料庫供應商專有的語言,幾乎所有DBMS都支持 SQL 。
  2. 簡單易學。
  3. 強有力,靈活使用。

三、資料庫存儲結構的特點:

  1. 將數據放到表中,表再放到庫中。
  2. 一個資料庫可以有多個表,每個表都有一個名字,用來表示自己。表名具有唯一性。
  3. 表具有一些特定,這些特定定義了數據在表中如何存儲,類似 java 中“類”的設計。
  4. 表由列組成,我們也稱為欄位。所有表都是由一個或多個列組成的,每一列類似 java 中的“屬性”。
  5. 表中的數據都是按行存儲的,每一行類似與 java 中的“對象”。

四、初識MySQL

MySQL產品的介紹

DBMS分為兩類:

  • 基於共用文件系統的DBMS(Access)
  • 基於客戶機-伺服器的DBMS(MySQL、Oracle、SqlServer)

MySQL產品的安裝

MySQL安裝

MySQL卸載

  1. 控制面板卸載

  2. 安裝路徑刪除 mysql 文件夾 + 刪除 C 盤根目錄下 ProgramDatamysql 文件夾;

  3. 清理註冊表:

A. HKEY_LOCAL_MAACHINE\SYSTEM\ControlSet001\Services\Eventlog\Application\MySQL 目錄
B. HKEY_LOCAL_MAACHINE\SYSTEM\ControlSet002\Services\Eventlog\Application\MySQL 目錄
C. HKEY_LOCAL_MAACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\MySQL 目錄
D. HKEY_LOCAL_MAACHINE\SYSTEM\CurrentControl001\Services\MYSQL 目錄
E. HKEY_LOCAL_MAACHINE\SYSTEM\CurrentControl002\Services\MYSQL 目錄
F. HKEY_LOCAL_MAACHINE\SYSTEM\CurrentControlSet\Services\MYSQL 目錄
  1. 刪除 C:\Document and Settings\All Users\Application Data\MySQL 目錄(隱藏的目錄)

MySQL服務的啟動和停止

  • 方式一:電腦 -> 管理 -> 服務

  • 方式二:命令行(管理員)

    net start 服務名(啟動服務)
    net stop 服務名(停止服務)

MySQL服務端的登錄和退出

  • 方式一:通過 mysql 自帶的客戶端;只限於 root 用戶

  • 方式二:通過 windows 自帶的客戶端

    登錄:mysql [-h 主機名 -P 埠號] -u 用戶名 -p密碼

    退出:exit 或者 ctrl + c

MySQL常見的命令

  1. 查看當前所有資料庫 show databases;

  2. 打開指定的庫 use 庫名;

  3. 查看當前庫的所有表 show tables;

  4. 查看其它庫的所有表 show tables from 庫名;

  5. 查看目前位於哪個庫 select database();

  6. 創建表

create table 表名(
    列名     列類型,
    列名     列類型,
    ......
);
  1. 查看表結構 desc 表名;

  2. 查看伺服器的版本

  • 方式一:登錄到mysql伺服器 select version();
  • 方式二:沒有登錄到mysql伺服器 mysql --version

MySQL語法規範

  1. 不區分大小寫,但建議關鍵字大寫,表名、列名小寫。

  2. 每條命名最好用分號或 \G、\g 結尾(會格式化輸出數據)

  3. 每條命令根據需要,可以進行縮進或換行。

  4. 註釋

  • 單行註釋:# 註釋文字
  • 單行註釋:-- 註釋文字
  • 多行註釋:/* 註釋文字 */
  1. 試說出查詢語句中涉及到的所有關鍵字,以及執行先後順序
SELECT 查詢列表             7
FROM 表1 別名                第1步
連接類型 join 表2             2
ON 連接條件                 3
WHERE 篩選條件                 4
GROUP BY 分組列表             5
HAVING 分組後的篩選            6
ORDER BY 排序列表             8
LIMIT 偏移,條目數;            9

五、DQL(Data Query Language)語言的學習

基礎查詢

語法:

SELECT 查詢列表 FROM 表名;

特點:

1.查詢列表可以是:表中的欄位、常量值、表達式、函數;
2.查詢的結果是一個虛擬的表格;查詢表中的某個欄位
  1. 查詢表中的所有欄位
> 方式一:
    SELECT `employee_id`,
        `first_name`,
    FROM
        employees;
> 方式二:
    SELECT * FROM employees;
  1. 查詢常量值
SELECT 100;
SELECT 'john';    //字元和日期型的常量值必須用單引號,數值型不需要;
  1. 查詢表達式
SELECT 100*99;
  1. 查詢函數
SELECT VERSION();
SELECT 函數名(實參列表);
  1. 起別名
  • 便於理解;
  • 如果要查詢的欄位有重名的情況,使用別名可以區分開來;
  • 如果別名中含有關鍵詞,用 單引號 或者 雙引號 將別名括起來;
方式一:使用 AS
    SELECT 100%98 AS 結果;
    SELECT last_name AS 姓, first_name AS 名 FROM employees;

方式二:使用空格
    SELECT last_name 姓,first_name 名 FROM employees;
  1. 去重 distinct

  2. DISTINCT 需要放到所有列名的前面。

  3. DISTINCT 其實對後面所有列名的 組合 進行去重。

SELECT DISTINCT 欄位名 FROM 表名;

案例:查詢員工表中涉及到的所有部門編號
    SELECT DISTINCT department_id FROM employees;
  1. concat 函數:和null拼接結果為null
案例:查詢員工名和姓連接成一個欄位,並顯示為 姓名
  SELECT 
      CONCAT(last_name,first_name) AS 姓名
  FROM
      employees;

案例:顯示出表employee的全部列,各個列之間用逗號連接,列頭顯示成OUT_PUT
  SELECT 
      CONCAT(`first_name`,',',`last_name`,',',`job_id`,',',IFNULL(commission_pct,0)) AS out_put
  FROM
      employees;
  1. ifnull 函數
功能:判斷某欄位或表達式是否為null,如果為null,返回指定值,否則返回原本的值
SELECT ifnull(commissiop_pct,0) from employees;

空值參與運算

  • 所有運算符或列值遇到 null 值,運算的結果都為 null。

  • 在 MySQL 裡面, 空值不等於空字元串。一個空字元串的長度是 0,而一個空值的長度是空。而且,在 MySQL 裡面,空值是占用空間的。

運算符

算數運算符

  1. 加法與減法運算符

mysql 中的加號,只有一個功能:運算符,做加法運算。

SELECT 100+90; 兩個操作數都為數值型,則做加法運算

SELECT '123'+90;只要其中一方為字元型,試圖將字元型數值轉成數值型,
                如果轉換成功,則繼續做加法運算。
                如果轉換失敗,則將字元型數值轉換成0

SELECT null+10;    只要其中一方為null,則結果肯定為null
  1. 乘法與除法運算符
  • 一個數乘以整數1和除以整數1後仍得原數;

  • 個數乘以浮點數1 和除以浮點數1後變成浮點數,數值與原數相等;

  • 一個數除以整數後,不管是否能除盡,結果都為一個 浮點數

  • 一個數除以另一個數,除不盡時,結果為一個浮點數,並保留到小數點後4位;

  • 乘法和除法的優先順序相同,進行先乘後除操作與先除後乘操作,得出的結果相同。

  • 在數學運算中,0不能用作除數,在MySQL中,一個數除以0為NULL。

  1. 求模(求餘)運算符

結果的符號與被模數的符號一致。

比較運算符

比較運算符用來對錶達式左邊的操作數和右邊的操作數進行比較,比較的結果為真則返回1,比較的結果為假則返回0,其他情況則返回 NULL。

  1. 等號運算符
  • 如果等號兩邊的值一個是整數,另一個是字元串,則MySQL會將字元串轉化為數字進行比較。

  • 如果等號兩邊的值、字元串或表達式中有一個為NULL,則比較結果為NULL。

  • 使用安全等於運算符時,兩邊的操作數的值都為NULL時,返回的結果為1而不是NULL,其他返回結果與等於運算符相同。

  1. 不等於運算符
  • LEAST(值1,值2,...,值n):在有兩個或多個參數的情況下,返回最小值。當比較值列表中有NULL時,不能判斷大小,返回值為NULL。

  • GREASTEST:最大值運算符。

邏輯運算符

  1. 邏輯非運算符 邏輯非(NOT或!)運算符表示當給定的值為0時返回1;當給定的值為非0值時返回0;當給定的值為NULL時,返回NULL。

  2. 邏輯與運算符 邏輯與(AND或&&)運算符是當給定的所有值均為非0值,並且都不為NULL時,返回1;當給定的一個值或者多個值為0時則返回0;否則返回NULL。

  3. 邏輯或運算符 邏輯或(OR或||)運算符是當給定的值都不為NULL,並且有任何一個值為非0值時,則返回1,否則返回0;當一個值為NULL,並且另一個值為非0值時,返回1,否則返回NULL;當兩個值都為NULL時,返回NULL。

  4. 邏輯異或運算符 邏輯異或(XOR)運算符是當給定的值中任意一個值為NULL時,則返回NULL;如果兩個非NULL的值都是0或者都不等於0時,則返回0;如果一個值為0,另一個值不為0時,則返回1。

  5. AND 的優先順序高於OR。

位運算符

條件查詢

  • 語法:

    SELECT 
        查詢列表
    FROM
        表名
    WHERE
        篩選條件;
    
  • 分類:

    • 按條件表達式篩選

      條件運算符: > < = != <> >= <= <=>

    • 按邏輯表達式篩選

      邏輯運算符: && || !

      and or not

      && 和 and:兩個條件都為 true,結果為 true,反之為 false;

      || 和 or:只要有一個條件為 true,結果為 true;

    • 模糊查詢

      like
      between and
      in
      is null / is not null

  1. 按條件表達式篩選
#案例1:查詢工資>12000的員工信息
    SELECT
        *
    FROM
        employees
    WHERE
        salary>120000;

#案例2:查詢部分編號不等於90的員工名和部門編號
    SELECT
        last_name,
        department_id
    FROM
        employees;
    WHERE
        department_id<>90;
  1. 按邏輯表達式篩選
#案例一:查詢工資在10000到20000之間的員工名、工資以及獎金
    SELECT
        last_name,
        salary,
        commission_pct
    FROM
        employees
    WHERE
        salary >= 10000 
    AND
        salary <= 20000
  1. 模糊查詢
  • like

    一般和通配符搭配使用,可以判斷 字元型數值型

    通配符:%s任意多個字元,_任意單個字元

    #案例1:查詢員工名中包含符a的員工信息
        SELECT
            *
        FROM
            employees
        WHERE
            last_name LIKE '%a%';
    
    #案例2:查詢員工名中第三個字元為e,第五個字元為a的員工名和工資
        SELECT
            last_name,
            salary,
        FROM
            employees
        WHERE
            last_name LIKE '__e_a%';
    
    #案例3:查詢員工名中第二個字元為_的員工名
        SELECT 
            last_name
        FROM 
            employees
        WHERE
            last_name LIKE '_\_%';    或者        last_name LIKE '_$_%' ESCAPE '$';
    
  • between and

    • 使用 between and 可以提高語句的簡介度;
    • 包含 臨界值;
    • 兩個臨街值 不要 調換順序;
    案例1:查詢員工編號在100到120之間的員工信息
        SELECT
            *
        FROM
            employees
        WHERE
            employee_id BETWEEN 100 AND 120;
    
  • in

    含義:判斷某欄位的值是否屬於 in 列表中的某一項;

    • 使用 in 提高語句簡介度;
    • in 列表的值類型必須一致或相容;
    • 不支持通配符;
    案例:查詢員工的工種編號是 IT_PROG、AD_VP、AD_PRES中的一個員工名和工種編號。
        SELECT
            last_name,
            job_id
        FROM
            employees
        WHERE    
            job_id IN ('IT_PROT','AD_VP','AD_PRES');
    
  • is null

    判斷某欄位或表達式是否為 null,如果是,則返回1,否則返回0。

    • = 或 <> 不能用於判斷 null 值;
    • is null 或 is not null 可以判斷null值;
    案例1:查詢沒有獎金的員工名和獎金率
        SELECT
            last_name,
            commission_pct
        FROM
            employees
        WHERE
            commission_pct IS NULL;        IS NOT NULL
    
  • 安全等於 <=>

    案例1:查詢沒有獎金的員工名和獎金率
        SELECT
            last_name,
            commision_pct
        FROM
            employees
        WHERE
            commission_pct <=> NULL;
    
    案例2:查詢工資為12000的員工名和獎金率
        SELECT
            last_name,
            commision_pct
        FROM
            employees
        WHERE
            salary <=> 12000;
    
  • is null pk <=>

    • IS NULL:僅僅可以判斷NULL值,可讀性較高,建議使用;
    • <=>:既可以判斷 NULL 值,又可以判斷普通的數值,可讀性較低。
  • 經典面試題:

    試問,select * from employees;和select * from employees where commission_pct like '%%' and last_name like '%%';結果是否一樣?並說明原因。

    答:不一樣。如果判斷的欄位有null值。

排序查詢

語法:

SELECT     查詢列表
FROM     表
[WHERE     篩選條件]
order by 排序列表 [asc/desc]

特點:

  • asc 代表的是升序,desc 代表的是降序;如果不寫,預設是升序。

  • order by 子句中可以支持單個欄位、多個欄位、表達式、函數、別名。

  • order by 後面的列必須是在 select 後面存在的。

  • order by 子句一般是放在查詢語句的最後面,limit 子句除外。

  • 可以使用列的別名進行排序,但別名只能在 order by 中使用,不能在 WHERE 中使用。

#案例1:查詢愚弄信息,要求工資從高到低排序
 SELECT * FROM employees 
ORDER BY salary DESC;

#案例2:查詢部門編號>=90的員工信息,按入職時間的先後順序進行排序
 SELECT *
 FROM employees
 WHERE department_id>=90
 ORDER BY hiredate ASC;

#案例3:按年薪的高低顯示員工的信息和年薪[按表達式排序]
 SELECT *,salary*12*(1+IFNULL(commission_prt,0)) 年薪
 FROM employees
 ORDER BY salary*12*(1+IFNULL(commission_prt,0)) DESC; 或 ORDER BY 年薪 DESC;

#案例5:按姓名的長度顯示員工的姓名和工資[按函數排序]
 SELECT LENGTH(last_name) 位元組長度,last_name,salary
 FROM employees
 ORDER BY LENGTH(last_name) DESC;

#案例6:查詢員工信息,要求先按工資升序,再按員工編號降序[按多個欄位排序]
 SELECT *
 FROM employees
 ORDER BY salary ASC,employee_id DESC;

常見函數

select 函數名(實參列表) [from 表]
(1) 單行函數
    concat、length、ifnull等
(2) 分組函數
    做統計使用,又稱為統計函數、聚合函數、組函數

單行函數

  • 操作數據對象

  • 接受參數返回一個結果

  • 只對一行進行變換

  • 每行返回一個結果

  • 可以嵌套

  • 參數可以是一列或一個值

字元函數

註意:MySQL中,字元串的位置是從1開始的。

函數 作用
ASCII(S) 返回字元串 S 中的第一個字元的 ASCII 碼值
CHAR_LENGTH(s) 返回字元串s的字元數。作用與CHARACTER_LENGTH(s)相同
LENGTH(s) 返回字元串s的個數,和字元集有關
CONCAT(s1,s2,...,sn) 連接s1,s2,......sn 為一個字元串
CONACT_WS(x,s1,s2,......,sn) 同CONCAT(s1,s2,...)函數,但是每個字元串之間要加上x
INSERT(str,idx,len,replacestr) 將字元串str從第idx位置開始,len個字元長的子串替換為字元串replacestr
REPLACE(str,a,b) 用字元串b替換字元串str中所有出現的字元串a
UPPER(s) 或 UCASE(s) 將字元串s的所有字母都轉換成大寫字母
LOWER(s) 或 LCASE(s) 將字元串s的所有字母都轉成小寫字母
LEFT(str,n) 返回字元串str最左邊的n個字元
RIGHT(str,n) 返回字元串str最右邊的n個字元
LPAD(str,len,pad) 用字元串pad對str最左邊進行填充,直到str的長度為len個字元
RPAD(str,len,pad) 用字元串pad對str最右邊進行填充,直到str的長度為len個字元
LTRIM(s) 去掉字元串s左側的空格
RTRIM(s) 去掉字元串s右側的空格
TRIM(s) 去掉字元串s開始與結尾的空格
TRIM(s1 FROM s) 去掉字元串s開始與結尾的s1
TRIM(LEADING s1 FROM s) 去掉字元串s開始處的s1
TRIM(TRAILING s1 FROM s) 去掉字元串s結尾處的s1
REPEAT(str,n) 返回str重覆n次的結果
SPACE(n) 返回n個空格
STRCMP(s1,s2) 比較字元串s1,s2的ASCII碼值的大小
SUBSTR(s,index,len) 返回從字元串s的index位置其len個字元,作用與SUBSTING(s,n,len)相同
LOCATE(substr,str) 返回字元串 substr 在字元串 str 中首次出現的位置,作用與 POSITION(substr IN str)、INSTR(str,substr) 相同。未找到,返回0
ELT(m,s1,s2,......,sn) 返回指定位置的字元串,如果m=1,則返回s1,如果m=2,則返回s2,如果m=n,則返回sn
FIELD(s,s1,s2,...,sn) 返回字元串s在字元串列表中第一次出現的位置
FIND_IN_SET(s1,s2) 返回字元串s1在字元串s2中出現的位置。其中,字元串s2是一個以逗號分隔的字元串
REVERSE(s) 返回s反轉後的字元串
NULLIF(value1,value2) 比較兩個字元串,如果value1與value2相等,則返回NULL,否則返回value
  • length():獲取參數值的位元組個數

    SELECT LENGTH('張三豐hahaha');
    
    SHOW VARIVALE LIKE '%char%'; 查看字元集
    
  • concat():拼接字元串

    SELECTV CONCAT(last_name,'_',first_name) 姓名 FROM employees;
    
  • upper()lower()

  • substr()substring()

    註意:索引從1開始

    # 截取從指定索引處後面所有字元
        SELECT SUBSTR('李莫愁愛上了路站元',7) out_put;
    
    # 截取從指定所引處指定字元長度的字元
        SELECT SUBSTR('李莫愁愛上了路站元',1,3) out_put;
    
    #案例:姓名中首字元大寫,其他字元小寫,然後用 _ 拼接,顯示出來
    SELECT CONTACT(UPPER(SUBSTR(last_name,1,1)),LOWER(SUBSTR(last_name),2)) out_put;
    
  • instr():返回字串第一次出現的索引,如果找不到返回0

  • trim()

    SELECT TRIM('a' FROM 'aaaaa張aa翠山aaaaaa') AS out_put;
    
  • lpad():用指定的字元實現左填充指定長度

    SELECT LPAD('殷素素',10,'*') AS out_put;     //10為總字元數
    SELECT LPAD('殷素素',2,'*') AS out_put;     //殷素
    
  • rpad():用指定的字元實現右填充指定長度

    SELECT RPAD('殷素素',12,'ab') AS out_put;
    
  • replace():替換

數學函數
  • round():四捨五入

    SELECT ROUND(1.65);
    SELECT ROUND(1.567,2);         // 1.57
    
  • ceil():向上取整,返回 >= 該參數的最小整數

  • floor():向下取整,返回 <= 該參數的最大整數

  • truncate():截斷

    SELECT TRUNCATE(1.6999,1);    //1.6
    
  • mod():取餘

    mod(a,b) = a-a/b*b
    
  • rand():獲取隨機數,返回 0-1 之間的小數

日期函數
  • now():返回當前系統日期+時間

    SELECT NOW();
    
  • curdate():返回當前系統日期,不包含時間

    curtime():返回當前時間,不包含日期

  • 可以獲取指定的部分,年、月、日、小時、分鐘、秒

    SELECT YEAR(now());
    SELECT YEAR('1998-1-1') 年;
    
  • str_to_date:將日期格式的字元轉換成指定格式的日期

    STR_TO_DATE('9-13-1999','%m-%d-%Y')        1999-09-13
    
  • date_format:將日期格式轉換成字元

    DATE_FORMAT('2018/6/6','%Y年%m月%d日')    2018年06月06日
    
  • year()、month()、day()、hour()、minute()、second()

  • datediff():返回兩個日期相差的天數

  • monthname():以英文形式返回月

其他函數
SELECT VERSION();
SELECT DATABASE();
SELECT USER();
SELECT password('字元'):返回該字元的密碼形式 自動加密
MD5('字元'):返回該字元的md5加密形式
流程式控制制函數
  • if 函數:if else 的效果

    if(條件表達式,表達式1,表達式2):如果條件表達式成立,返回表達式1;否則返回表達式2
    
    SELECT last_name,commission_pct,IF(commission_pct IS NULL,'沒獎金,呵呵','有獎金,嘻嘻') 備註
    FROM employees;
    
  • case函數的使用一:switch case 的效果

    case 要判斷的欄位或表達式
    when 常量1 then 要顯示的值1或語句1;
    when 常量2 then 要顯示的值2或語句2;
    ...
    else 要顯示的值n或語句n;
    end
    
    #案例:要查詢員工的工資,要求    
    部門號=30,顯示的工資為1.3倍
    部門號=40,顯示的工資為1.4倍
    部門號=50,顯示的工資為1.5 倍
    其他部門,顯示的工資為原工資
    
    SELECT salary 原始工資,department_id,
        CASE department_id
        WHEN 30 THEN salary*1.3
        WHEN 40 THEN salary*1.4
        WHEN 50 THEN salary*1.5
        ELSE salary
        END AS 新工資
        FROM employees;
    
  • case 函數的使用二:類似於 多重if

    case
    when 條件1 then 要顯示的值1或語句1
    when 條件2 then 要顯示的值2或語句2
    ...
    else 要顯示的值n或語句n
    end
    
    #案例:查詢員工的工資的情況    如果工資 > 20000,顯示A級別
                            如果工資 > 15000,顯示B級別
                            如果工資 > 10000,顯示C級別
                            否則,顯示D級別
    SELECT salary,
    CASE
    WHEN salary>20000 THEN 'A'
    WHEN salary>15000 THEN 'B'
    WHEN salary>10000 THEN 'C'
    ELSE 'D'
    END AS 工資級別
    FROM employees;
    
加密與解密函數
函數 用法
PASSWORD(str) 返回字元串str的加密版本,41位長的字元串。加密結果不可逆,常用語用戶的密碼加密。在mysql8.0中被棄用。
MD5(str) 返回字元串str的md5加密後的值,也是一種加密方式。若參數為NULL,則會返回NULL。不可逆。
SHA(str) 從原明文密碼str計算並返回加密後的密碼字元串,當參數為 NULL 時,返回 NULL。不可逆。
ENCODE(value,password_seed) 返回使用 password_seed 作為加密密碼加密value。mysql8.0後被棄用。
DECODE(value,password_seed) 返回使用password_seed作為加密密碼解密value
mysql 信息函數
函數 用法
VERSION() 返回當前MySQL的版本號
CONNECTION_ID() 返回當前MySQL伺服器的連接id
DATABASE(),SCHEMA() 返回MySQL命令行當前所在的資料庫
USER(),CURRENT_USER()、SYSTEM_USER(), SESSION_USER() 返回當前連接MySQL的用戶名,返回結果格式為 “主機名@用戶名”
CHARSET(value) 返回字元串value自變數的字元集
COLLATION(value) 返回字元串value的比較規則
其他函數
函數 用法
FORMAT(value,n) 返回對數字value進行格式化後的結果數據。n表示 四捨五入 後保留到小數點後n位
CONV(value,from,to) 將value的值進行不同進位之間的轉換
INET_ATON(ipvalue) 將以點分隔的IP地址轉化為一個數字
INET_NTOA(value) 將數字形式的IP地址轉化為以點分隔的IP地址
BENCHMARK(n,expr) 將表達式expr重覆執行n次。用於測試MySQL處理expr表達式所耗費的時間
CONVERT(value USING char_code) 將value所使用的字元編碼修改為char_code

分組函數

  1. 功能:用作統計使用,又稱為聚合函數或統計函數或組函數。輸入的是一組數據的集合,輸出的是單個值。

  2. 分類:sum 求和、 avg 平均值、 max 最大值、 min 最小值、 count 計算個數;

  3. 特點:

  4. sum、avg一般用於處理數值型;max、min、count 可以處理任何類型;

  5. 以上分組函數都忽略 null 值

  6. 可以和 distinct 搭配實現去重的運算;

```sql
SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;
```
  1. count函數的詳細介紹,一般使用 COUNT(*) 統計行數;
```sql
SELECT COUNT(salary) FROM employees;
SELECT COUNT(*) FROM employees;    //只要某一行有一個不為null,就相當於+1(不包含NULL值)
SELECT COUNT(1) FROM employees; //統計1的個數,相當於計算行數

效率:
    如果使用的是 MyISAM 存儲引擎,則三者效率相同,都是O(1)
    如果使用的是 InnoDB 存儲引擎,則三者效率:COUNT(*) = COUNT(1) > COUNT(欄位)
```
  1. 和分組函數一同查詢的欄位要求是 group by 後面的欄位
```
SELECT AVG(salary),employee_id FROM employees; 有問題,AVG(salary)只有一行,employee_id有很多行
```

分組查詢

  1. 語法
                                                 #執行順序
SELECT         column,group_function(column)           5
FROM         table                                    1
[WHERE         condition]                                2
GROUP BY     group_by_expression                     3
[HAVING     分組後的篩選]                                4
[ORDER BY     column];                                 6
  1. 明確:WHERE 一定放在 FROM 後面;

  2. 註意:查詢列表必須特殊,要求是分組函數group by 後出現的欄位;

  3. 當使用 ROLLUP 時,不能同時使用 ORDER BY 子句進行結果排序,即 ROLLUP 和 ORDER BY 是互相排斥的。

為了更好的理解 grouy by 多個列和聚合函數的應用,我們可以假設在group by執行之後,生成了一個虛擬的中間表。相同的group by欄位合併成一行,其餘的欄位分別寫到一個單元格裡。
對於id和number裡面的單元格有多個數據的情況,使用聚合函數。聚合函數就是用來輸入多個數據,輸出一個數據的。
#對name欄位進行分組
id    name    number
1    aa        2
2            3

3            4
4    bb        5
8            6
  1. 特點:

  2. 分組查詢中的篩選條件分為兩類:

```
            數據源            位置                    關鍵字
分組前篩選    原始表            group by子句的前面        where
分組後篩選    分組後的結果集    group by子句的後面         having
```
  1. group by 子句支持單個欄位分組,多個欄位分組(多個欄位之間用逗號隔開,沒有順序要求),表達式或函數(用的較少);

  2. 也可以添加排序(排序放在整個分組查詢的最後);

  3. 從 mysql8.0 開始,group by不再支持隱式排序。

  4. 當 group by 這列有 null 值時,group 會把他們當成是同一個直接聚合。

  5. 如果過濾條件中使用了聚合函數,則必須使用 HAVING 來替換 WHERE。否則,報錯。

  6. 案例:

#案例1:查詢每個工種的最高工資
    SELECT MAX(salary),job_id
    FROM employees
    GROUP BY job_id;

#案例2:查詢每個位置上的部門個數
    SELECT COUNT(*),location_id
    FROM employees
    GROUP BY location_id;

#案例3:查詢郵箱中包含a字元的,每個部門的平均工資
    SELECT AVG(salary),department_id
    FROM employees
    WHERE email LIKE '%a%'
    GROUP BY department_id;

#案例4:查詢有獎金的每個領導手下員工的最高工資
    SELECT MAX(salary),manager_id
    FROM employees
    WHERE commission_pct IS NOT NULL
    GROUP BY manager_id;

#案例5:查詢哪個部門的員工個數>2
(1) 查詢每個部門員工個數
    SELECT COUNT(*),department_id
    FROM employees
    GROUP BY department_id;
(2) 根據(1)的結果進行篩選,查詢哪個部門的員工個數>2
    SELECT COUNT(*),department_id
    FROM employees
    GROUP BY department_id
    HAVING COUNT(*)>2;
#案例:查詢每個工種有獎金的員工的最高工資>12000的工種編號和最高工資
(1)查詢每個工種有獎金的員工的最高工資
    SELECT MAX(salary),job_id
    FROM employees
    WHERE commission_pct IS NOT NULL
    GROUP BY job_id;

(2)根據(1)結果繼續篩選,最高工資>12000
    SELECT MAX(salary),job_id
    FROM employees
    WHERE commission_pct IS NOT NULL
    GROUP BY job_id
    HAVING MAX(salary)>12000;

#案例:查詢領導編號>102的每個領導手下的最低工資>5000的領導編號是哪個,以及其最低工資;
(1)查詢每個領導手下的員工最低工資
    SELECT MIN(salary),manager_id
    FROM employees
    GROUP BY manager_id;
(2)添加篩選條件:編號>102
    SELECT MIN(salary),manager_id
    FROM employees
    WHERE manager_id > 102
    GROUP BY manager_id;
(3)添加篩選條件:最低工資>5000
    SELECT MIN(salary),manager_id
    FROM employees
    WHERE manager_id > 102
    GROUP BY manager_id
    HAVING MIN(salary)>5000;

     > 按表達式或函數分組
             > 案例:按員工姓名的長度分組,查詢每一組的員工個數,篩選員工個數>5的的有哪些
                 (1)查詢每個長度的員工個數
                     SELECT COUNT(*),LENGTH(last_name)
                     FROM employees
                     GROUP BY LENGTH(last_name);
                 (2)添加篩選條件
                     SELECT COUNT(*),LENGTH(last_name)
                     FROM employees
                     GROUP BY LENGTH(last_name)
                     HAVING COUNT(*)>5;
     > 按多個欄位分組
         #案例:查詢每個部門每個工種的員工的平均工資
             SELECT AVG(salary),department_id,job_id
             FROM employees
             GROUP BY job_id,department_id;

         #添加排序
        #案例:查詢每個部門每個工種的員工的平均工資,並且按平均工資的高低顯示
            SELECT AVG(salary),department_id,job_id
             FROM employees
             WHERE department_id IS NOT NULL
             GROUP BY job_id,department_id
             ORDER BY AVG(salary) DESC;

連接查詢

  1. 含義:又稱多表查詢,當查詢的欄位來自多個表時;

  2. 笛卡爾乘積現象:表1有 m 行,表2有 n 行,結果 m*n 行

發生原因:沒有有效的連接條件;

如何避免:添加有效的連接條件;

分類:

  1. 按年代分類:

sql92標準:僅僅支持內連接
    等值
    非等值
    自連接
    也支持一部分外連接(用於 oracle、sqlserver,mysql 不支持)
     sql99標準(推薦):支持內連接+外連接(左外和右外)+交叉連接

  1. 按功能分類:
  • 內連接
    等值連接
    非等值連接
    自連接

  • 外連接
    左外連接
    右外連接
    全外連接(mysql不支持)

  • 交叉連接

sql92 標準

等值連接
  • 多表等值連接的結果為多表的交集部分;
  • n表的連接,至少需要n-1個連接條件;
  • 多表的順序沒有要求;
  • 一般需要為表起別名;
  • 可以搭配前面介紹的所有子句使用,比如排序、篩選、分組;

語法:

SELECT 查詢列表
FROM 表1 別名, 表2 別名
WHERE 表1.key = 表2.key
[AND 篩選條件]
[GROUP BY 分組欄位]
[HAVING 分組後的篩選]
[ORDER BY 排序欄位]

案例:

#案列1:查詢女生名和對應的男生名
 SELECT NAME,boyName 
FROM boys,beauty
 WHERE beauty.boyfriend_id = boys.id;

#案例2:查詢員工名和對應的部門名
 SELECT last_name,department_name
 FROM employees,departments
 WHERE employees.`department_id` = departments.`department_id`;
  1. 為表起別名

  2. 提高語句的簡潔度;

  3. 區分多個重名的欄位;

  4. 註意:如果為表起了別名,則查詢的欄位就不能使用原來的表名去限定;

#案例:查詢員工名、工種號、工種名
    SELECT e.last_name,e.job_id,j.job_title     #employees.last_name錯誤
    FROM employees AS e,jobs j
    WHERE e.`job_id` = j.`job_id`;
  1. 兩個表的順序可以調換

  2. 加篩選

#案例:查詢有獎金的員工名、部門名
    SELECT last_name,department_name
    FROM employees e,departements d
    WHERE e.`department_id` = d.`department_id`
    AND e.`commission_pct` IS NOT NULL;

#案例2:查詢城市名中第二個字元為o的部門名和城市名
    SELECT dapartment_name,city
    FROM departments d,location l
    WHERE d.`location_id` = l.`location_id`
    AND city LIKE `_o%`;
  1. 加分組
#案例1:查詢每個城市的部門個數
    SELECT COUNT(*) 個數,city
    FROM departments d,locations l
    WHERE d.`location_id` = l.`location_id`
    GROUP BY city;

#案例2:查詢有獎金的部門的部門名和部門的領導編號和該部門的最低工資
    SELECT department_name,d.`manager_id`,MIN(salary)
    FROM dapartment d,employees e
    WHERE d.`department_id` = e.`department_id`
    AND commission_pct IS NOT NULL
    GROUP BY department_name,d.mamager_id;
  1. 加排序
#案例:查詢每個工種的工種名和員工的個數,並且按員工的個數降序
    SELECT job_title,COUNT(*)
    FROM employees e,jobs j
    WHERE e.`job_id` = j.`job_id`
    GROUP BY job_title
    ORDER BY COUNT(*) DESC;
  1. 三表連接
#案列:查詢員工名、部門名和所在的城市
    SELECT last_name,department_name,city
    FROM employees e,department d,location l
    WHERE e.`department_id` = d.`department_id`
    AND d.`location_id` = l.`location_id`

    AND city LIKE 's%'
    ORDER BY department_name DESC;
非等值連接
SELECT     查詢列表
FROM     表1 別名, 表2 別名
WHERE     非等值的連接條件
[AND     篩選條件]
[GROUP BY 分組欄位]
[HAVING 分組後的篩選]
[ORDER BY 排序欄位]
#案例1:查詢員工的工資和工資級別
    SELECT salary,grade_level
    FROM employess e,job_grades g
    WHERE salary BETWEEN g.`lowest_sal` AND g.`hightest_sal`
    //AND g.`grade_level` = 'A';
自連接
#案例:查詢員工名和上級的名稱
SELECT e.employee_id,e.last_name,m.employee_id,m.last_name
FROM employees e,employees m
WHERE e.manager_id = m.employee_id;

sql99 語法

SELECT 查詢列表
FROM 表1 別名 [連接類型]
JOIN 表2 別名
ON     連接條件
[WHERE 篩選條件]
[GROUP BY 分組]
[HAVING 篩選條件]
[ORDER BY 排序列表]
內連接:inner
SELECT 查詢列表
FROM 表1 別名
INNER JOIN 表2 別名
ON 連接條件;

分類:等值、非等值、自連接

  • 等值連接

    特點:

    1. 添加排序、分組、篩選;
    2. inner 可以省略;
    3. 篩選條件放在 where 後面,連接條件放在 on 後面,提高分離性,便於閱讀;
    4. inner join 連接和 sql92 語法中的等值連接效果是一樣的,都是查詢多表;
    #案例1:查詢員工名、部門名
        SELECT last_name,department_name
        FROM employees e
        INNER JOIN departments d
        ON e.`department_id` = d.`department_id`;
    
    #案例2:查詢員工名字中包含e的員工名和工種名(添加篩選)
        SELECT last_name,job_title
        FROM employees e
        INNER JOIN jobs j
        ON e.`job_id` = j.`job_id`
        WHERE e.`last_name` LIKE '%e%';
    
    #案例3:查詢部門個數>3的城市名稱和部門個數(添加分組+篩選)
    #(1)查詢每個城市部門的個數
    #(2)在(1)結果上篩選滿足條件的
        SELECT city,COUNT(*) 部門個數
        FROM departments d
        INNER JOIN locations l
        ON d.`location_id` = l.`location_id`
        GROUP BY city
        HAING COUNT(*)>3;
    
    #案例4:查詢哪個部門的員工個數>3的部門名和員工個數,並按個數降序(添加排序)
    #(1)查詢每個部門的員工個數
        SELECT COUNT(*),department_name
        FROM employees e
        INNER JOIN departments d
        ON e.`department_id` = d.`department_id`
        GROUP BY department_name;
    #(2)在(1)結果上篩選員工個數>3的記錄,併排序
        SELECT COUNT(*),department_name
        FROM employees e
        INNER JOIN departments d
        ON e.`department_id` = d.`department_id`
        GROUP BY department_name
        HAVING COUNT(*)>3
        ORDER BY COUNT(*) DESC;
    
    #案例5:查詢員工名、部門名、工種名,並按部門名排序
        SELECT last_name,department_name,job_title
        FROM employees e
        INNER JOIN departments d ON e.`department_id` = d.`department_id`
        INNER JOIN jobs j ON e.`job_id`=j.`job_id`
        ODER BY department_name DESC;
    
  • 非等值連接

    #案例1:查詢員工的工資級別
        SELECT salary,grade_level
        FROM employees e
        JOIN job_grade e
        ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`;
    
    #案例2:查詢工資級別的個數>20的個數,並且按工資級別降序
        SELECT COUNT(*),grade_level
        FROM employees e
        JOIN job_grade e
        ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`
        GROUP BY grade_level
        HAVING COUNT(*)>20
        ORDER BY grade_level DESC;
    
  • 自連接

    #案例:查詢姓名中包含字元k的員工的名字、上級的名字
        SELECT e.last_name,m.last_name
        FROM employees e
        JOIN employees m
        ON e.`manager_id` = m.`manager_id`
        WHERE e.`last_name` LIKE '%k%';
    
外連接
  • 左外: left [outer]
  • 右外: right [outer]
  • 全外: full [outer]

應用場景:用於查詢一個表中有,另一個表中沒有的記錄;

特點:

  1. 外連接的查詢結果為主表中的所有記錄;

如果從表中有和它匹配的,則顯示匹配的值;

如果從表中沒有和它匹配的,則顯示 null

外連接查詢結果=內連接結果 + 主表中有而從表中沒有的記錄;

  1. 左外連接,left join 左邊的是主表;
    右外連接,right join 右邊的是主表;

全外連接,兩邊都是主表。

  1. 左外和右外交換兩個表的順序,可以實現同樣的效果;

  2. 全外連接=內連接的結果+表1中有但表2沒有的+表2中有的但表1沒有的;

#案例:查詢男朋友 不在男明星表的女明星名
    SELECT b.name,bo.*
    FROM beauty b
    LEFT OUTERF JOIN boys bo
    ON b.`boyfriend_id` = bo.`id`
    WHERE bo.`id` IS NULL;  //問題:為什麼用boys.id為NULL就可以了呢,實際上的boys表裡的id是主鍵,根本不可能為NULL啊?

#案例1:查詢哪個部門沒有員工
#左外
    SELECT d.*,e.employee_id
    FROM departments d
    LEFT OUTER JOIN employees e
    ON d.`department_id`=e.`department_id`
    WHERE e.`employee_id` IS NULL;

#案例2:查詢哪個城市沒有部門
    SELECT city
    FROM department d
    RIGHT OUTER JOIN locations l
    ON d.location_id = l.location_id
    WHERE d.department_id IS NULL;

#案例3:查詢部門為SAL或IT的員工信息
SELECT e.*,d.department_name
FROM departments d
LEFT OUTER JOIN employees e
ON d.department_id = e.department_id
WHERE d.department_name IN ('SAL','IT');
交叉連接:cross
SELECT 查詢列表
FROM 表1 別名
CROSS JOIN 表2 別名;

#特點:類似於笛卡爾乘積

sql99 語法新特性

自然連接

NATURAL JOIN 用來表示自然連接。我們可以把自然連接理解為 SQL92 中的等值連接。它會幫你自動查詢兩張連接表中所有相同的欄位 ,然後進行等值連接 。

#sql92中:
SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
ON e.`department_id` = d.`department_id`
AND e.`manager_id` = d.`manager_id`;

#在sql99中可寫成:
SELECT employee_id,last_name,department_name
FROM employees e NATURAL JOIN departments d;

USING 連接

當我們進行連接的時候,SQL99還支持使用 USING 指定數據表裡的 同名欄位 進行等值連接。但是只能配合JOIN一起使用。比如:

SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
USING (department_id);

子查詢

含義:出現在其他語句中的 select 語句,稱為子查詢或內查詢;
外部的查詢語句,稱為主查詢或外查詢。
外面的語句可以是 insert、update、delete、select 等,一般 select 作為外面語句較多。

分類:

  1. 按子查詢出現的位置:
  • select 後面:
    • 僅僅支持標量子查詢
  • from 後面:
    • 支持表子查詢
  • where 或 having 後面
    • 標量子查詢(單行)
    • 列子查詢 (多行)
    • 行子查詢
  • exists 後面(相關子查詢)(返回的結果1或0,類似布爾操作)
    • 表子查詢
  1. 按結果集的行列數不同:
  • 標量子查詢(單行子查詢)(結果集是一個數據:一行一列)
  • 列子查詢(多行子查詢)(結果集是一列:一列多行):一般搭配著多行操作符使用 in、any/some、 all
  • 行子查詢(結果集是一行:一行多列)
  • 表子查詢(結果集一般為多行多列)

where 或 haing 後面

  1. 標量子查詢
  2. 列子查詢
  3. 行子查詢

特點:

  • 子查詢放在小括弧內
  • 子查詢一般放在條件的右側
  • 標量子查詢,一般搭配著單行操作符使用 > < >= <= = <>
  • 子查詢的執行順序優於主查詢執行,主查詢的條件用到了子查詢的結果
標量子查詢
#案例1:誰的工資比Abel高?
#(1)查詢Abel的工資
    SELECT salary
    FROM employees
    WHERE last_name = 'Abel'
#(2)查詢員工信息,滿足 salary>(1)結果
    SELECT *
    FROM employees
    WHERE salary>(
        SELECT salary
        FROM employees
        WHERE last_name = 'Abel'
    );

#案例2:返回job_id與141號員工相同,salary比143號員工多的員工姓名,job_id和工資
#(1)查詢141號員工的job_id
    SELECT job_id
    FROM employees
    WHERE employee_id = 141
#(2)查詢143號員工的salary
    SELECT salary
    FROM employees
    WHERE employee_id = 143
#(3)查詢員工的姓名、job_id和工資,要求job_id=(1)並且salary>(2)
    SELECT last_name,job_id,salary
    FROM employees
    WHERE job_id = (
        SELECT job_id
        FROM employees
        WHERE employee_id = 141
    ) AND salary > (
        SELECT salary
        FROM employees
        WHERE employee_id = 143
    );

#案例3:返回公司工資最少的員工的last_name,job_id和salary
#(1)查詢公司的最低工資
    SELECT MIN(salary)
    FROM employees;
#(2)查詢last_name,job_id和salary,要求salary=(1)
    SELECT last_name,job_id,salary
    FROM employees
    WHERE salary = (
        SELECT MIN(salary)
        FROM employees;
    );

#案例4:查詢最低工資大於50號部門最低工資的部門id和其最低工資
#(1)查詢50號部門的最低工資
    SELECT MIN(salary)
    FROM employees
    WHERE department_id =50
#(2)查詢每個部門的最低工資
    SELECT MIN(salary),department_id
    FROM employees
    GROUP BY department_id
#(3)在(2)的基礎上,滿足min(salary)>(1)
    SELECT MIN(salary),department_id
    FROM employees
    GROUP BY department_id
    HAVING MIN(salary)>(
        SELECT MIN(salary)
        FROM employees
        WHERE department_id =50
    );

非法使用標量子查詢:

    SELECT MIN(salary),department_id
    FROM employees
    GROUP BY department_id
    HAVING MIN(salary)>(
        SELECT salary
        FROM employees
        WHERE department_id =50
    );
列子查詢(多行子查詢)
  • 返回多行
  • 使用多行比較操作符
操作符 含義
IN / NOT IN 等於列表中的任意一個
ANY | SOME 和子查詢返回的某一個值比較
ALL 和子查詢返回的所有值比較
#案例1:返回 location_id 是 1400 或 1700 的部門中所有員工姓名
#(1)查詢location_id是1400或1700的部門編號
    SELECT DISTINCT department_id
    FROM departments
    where location_id IN(1400,1700)
#(2)查詢員工姓名,要求部門號是(1)列表中的某一個
    SELECT last_name
    FROM employees
    WHERE deapartment_id IN(
        SELECT DISTINCT department_id
        FROM departments
        where location_id IN(1400,1700)
    );

#案例2:查詢其它工種中比job_id為`IT_PROG`工種任一工資低的員工的員工號、姓名、job_id 和 salary
#(1)查詢job_id為`IT_PROG`部門任一工資
    SELECT DISTINCT salary
    FROM employees
    WHERE job_id='IT_PROG'
#(2)查詢員工號、姓名、job_id以及salary,salary<(1)的任意一個
    SELECT last_name,employee_id,job_id,salary
    FROM employees
    WHERE salary < ANY(
        SELECT DISTINCT salary
        FROM employees
        WHERE job_id='IT_PROG'
    )AND job_id<>'IT_PROG';
    或
    SELECT last_name,employee_id,job_id,salary
    FROM employees
    WHERE salary < (
        SELECT MAX(salary)
        FROM employees
        WHERE job_id='IT_PROG'
    )AND job_id<>'IT_PROG';
行子查詢(結果集一行多列或多行多列)
#案例:查詢員工編號最小且工資最高的員工信息
#(1)查詢最小的員工編號
    SELECT MIN(employee_id)
    FROM employees
#(2)查詢最高工資
    SELECT MAX(salary)
    FROM employees
#(3)查詢員工信息
    SELECT *
    FROM employees
    WHERE employee_id=(
        SELECT MIN(employee_id)
        FROM employees
    )AND salary=(
        SELECT MAX(salary)
        FROM employees
    );

    SELECT *
    FROM employees
    WHERE (employee_id,salary)=(
        SELECT MIN(employee_id),MAX(salary)
        FROM employees
    );

select後面:僅僅支持標量子查詢

#案例1:查詢每個部門的員工個數
    SELECT d.*,(
        SELECT COUNT(*)
        FROM employees
        WHERE e.department_id = d.`department_id`
        ) 個數
    FROM departments d;

#案例2:查詢員工號=102的部門名
    SELECT (
        SELECT department_name
        FROM departments d
        INNER JOIN employees e
        ON d.department_id = e.department_id
        WHERE e.employee_id = 102
    ) 部門名;

from 後面

將子查詢結果充當一張表,要求必須起別名

#案例1:查詢每個部門的平均工資的工資等級
#(1)查詢每個部門的平均工資
    SELECT AVG(salary),department_id
    FROM employees
    GROUP BY department_id
#(2)連接(1)的結果集和job_grade表,篩選條件平均工資between lowest_sal and highest_sal
    SELECT ag_dep.*,g.`grade_level`
    FROM(
        SELECT AVG(salary) ag,department_id
        FROM employees
        GROUP BY department_id
    ) ag_dep
    INNER JOIN job_grade g
    ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;

#案例2:查詢各部門中工資比本部門平均工資高的員工的員工號,姓名和工資
#(1)查詢各部門的平均工資
    SELECT AVG(salary),department_id
    FROM employees
    GROUP BY department_id;
#(2)連接(1)結果集和 employees 表,進行篩選
    SELECT employee_id,last_name,salary,e.department_id
    FROM employees e
    INNER JOIN (
        SELECT AVG(salary) ag,department_id
        FROM employees
        GROUP BY department_id;
    )ag_dep
    ON e.department_id = ag_dep.department_id
    WHERE salary > ag_dep.ag;

exists後面(相關子查詢)

語法:
    exists(完整的查詢語句)            問題:exists(NULL)?
結果:
    1或0
#案例1:查詢有員工的部門名
    SELECT department_name
    FROM departments d
    WHERE EXISTS(
        SELECT *
        FROM employees e
        WHERE e.`department_id`= d.`department_id`
    );
#in
    SELECT department_name
    FROM departments d
    WHERE d.`deparment_id` IN (
        SELECT department_id
        FROM employees
    );


#案例2:查詢沒有女朋友的男生信息
#in
    SELECT bo.*
    FROM boys bo
    WHERE bo.id NOT IN(
        SELECT boyfriend_id
        FROM beauty
    );
#exists
    SELECT bo.*
    FROM boys bo
    WHERE NOT EXISTS(
        SELECT boyfriend_id
        FROM beauty b
        WHERE bo.id = b.boyfriend_id
    );

子查詢經典案例

# 1.查詢工資最低的員工信息:last_name,salary
#(1)查詢最低的工資
    SELECT MIN(salary)
    FROM employees
#(2)查詢last_name,salary,要求salary=(1)
    SELECT last_name,salary
    FROM employees
    WHERE salary = (
        SELECT MIN(salary)
        FROM employees
    )



# 2.查詢平均工資最低的部門信息
#方法一:
    #(1)各部門的平均工資
    SELECT AVG(salary),department_id
    FROM employees
    GROUP BY department_id
    #(2)查詢(1)結果上的最低平均工資
    SELECT MIN(ag)
    FROM (
        SELECT AVG(salary) ag,department_id
        FROM employees
        GROUP BY department_id
    ) ag_dep
    #(3)查詢哪個部門的平均工資=(2)
    SELECT AVG(salary),department_id
    FROM employees
    GROUP BY department_id
    HAVING AVG(salary) = (
        SELECT MIN(ag)
        FROM (
            SELECT AVG(salary) ag,department_id
            FROM employees
            GROUP BY department_id
        ) ag_dep
    )
    #(4)查詢部門信息
    SELECT d.*
    FROM departments d
    WHERE d,department = (
        SELECT department_id
        FROM employees
        GROUP BY department_id
        HAVING AVG(salary) = (
            SELECT MIN(ag)
            FROM (
                SELECT AVG(salary) ag,department_id
                FROM employees
                GROUP BY department_id
            ) ag_dep
        )
    )

#方法二:
    #(1)各部門的平均工資
    SELECT AVG(salary),department_id
    FROM employees
    GROUP BY department_id
    #(2)求出最低平均工資的部門編號
    SELECT department_id
    FROM employees
    GROUP BY department_id
    ORDER BY AVG(salary)
    LIMIT 1;



# 3.查詢平均工資最低的部門信息和該部門的平均工資
#(1)各部門的平均工資
    SELECT AVG(salary),department_id
    FROM employees
    GROUP BY department_id
#(2)求出最低平均工資的部門編號和平均工資
    SELECT department_id,AVG(salary)
    FROM employees
    GROUP BY department_id
    ORDER BY AVG(salary)
    LIMIT 1;
#(3)查詢部門信息(內連接)
    SELECT d.*,
    FROM departments d
    INNER JOIN (
        SELECT department_id,AVG(salary) ag
        FROM employees
        GROUP BY department_id
        ORDER BY AVG(salary)
        LIMIT 1;
    )ag_dep
    ON d.department_id = ag_dep.department_id;


# 4.查詢平均工資最高的 job 信息
#(1)查詢每個job的平均工資
    SELECT AVG(salary),job_id
    FROM employees
    GROUP BY job_id
#(2)在(1)的結果上獲取平均工資最高的job
    SELECT AVG(salary),job_id
    FROM employees
    GROUP BY job_id
    ORDER BY AVG(salary) DESC
    LIMIT 1
#(3)查詢job信息
    SELECT *
    FROM jobs
    WHERE job_id = (
        SELECT job_id
        FROM employees
        GROUP BY job_id
        ORDER BY AVG(salary) DESC   #order by後面存在的非聚合列必須在select後面出現
        LIMIT 1
    )


# 5.查詢平均工資高於公司平均工資的部門有哪些
#(1)查詢公司的平均工資
    SELECT AVG(salary)
    FROM employees
#(2)查詢每個部門的平均工資
    SELECT AVG(salary)
    FROM employees
    GROUP BY department_id
#(3)篩選(2)結果集,滿足平均工資>(1)
    SELECT AVG(salary),department_id
    FROM employees
    GROUP BY department_id
    HAVING AVG(salary) > (
        SELECT AVG(salary)
        FROM employees
    )


# 6.查詢出公司中所有 manager 的詳細信息
#(1)查詢所有manager的員工編號
    SELECT DISTINCT manager_id
    FROM employees
#(2)查詢詳細信息,滿足employee_id=(1)
    SELECT *
    FROM employees
    WHERE employee_id = ANY(
        SELECT DISTINCT manager_id
        FROM employees
    )


# 7.各個部門中,最高工資中最低的那個部門的最低工資是多少
#(1)查詢各部門的最高工資中最低的
    SELECT MAX(salary),department_id
    FROM employees
    GROUP BY department_id
    ORDER BY MAX(salary) ASC
    LIMIT 1
#(2)查詢(1)結果的那個部門的最低工資
SELECT MIN(salary),department_id
FROM employees
WHERE department_id = (
    SELECT department_id
    FROM employees
    GROUP BY department_id
    ORDER BY MAX(salary) ASC
    LIMIT 1
)


# 8.查詢平均工資最高的部門的 manager 的詳細信息:last_name,department_id,email,salary
#(1)查詢平均工資最高的部門編號
    SELECT department_id
    FROM employees
    GROUP BY department_id
    ORDER BY AVG(salary) DESC
    LIMIT 1
#(2)將employees和departments表連接查詢,篩選條件是(1)
    SELECT last_name,d.department_id,email,salary
    FROM employeese e
    INNER JOIN departments d
    ON d.department_id = e.department_id
    WHERE d.department_id = (
        SELECT department_id
        FROM employees
        GROUP BY department_id
        ORDER BY AVG(salary) DESC
        LIMIT 1
    )

分頁查詢

應用查詢:當要顯示的數據,一頁顯示不全,需要分頁提交 sql 請求。

語法:

    SELECT 查詢列表                    7
    FROM 表                          1
    [JOIN type join 表2              2
    ON 連接條件                        3
    WHERE 篩選條件                    4
    GROUP BY 分組欄位                5
    HAVING 分組後的篩選               6
    ORDER BY 排序的欄位]                8
    LIMIT offset,size;               9
    # offset 要顯示條目的起始索引(起始索引從0開始)
    # size 要顯示的條目個數

根據執行順訊,可以得出:
1. order by 後面的列必須是在 select 後面存在的;
2. select、having 或 order by 後面存在的非聚合列必須全部在 group by 中存在。

特點:

  1. limit 語句放在查詢語句的最後

  2. 公式

#要顯示的頁數page    每頁的條目數size
    SELECT 查詢列表
    FROM 表
    LIMIET (page-1)*size,size;
#案例1:查詢前五條員工信息
    SELECT * FROM employees LIMIT 0,5;
    或
    SELECT * FROM employees LIMIT 5;

#案例2:查詢

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ###伺服器:WindowsServer 2016 ###Cloudreve 需求方想整一個在小團隊內部使用的網盤系統,最終在千挑萬選之下選中了Cloudreve。 Github地址:https://github.com/cloudreve/Cloudreve 官網地址:https://docs.c ...
  • 引言 儘管 redis 是一款非常優秀的 NoSQL 資料庫,但更重要的是,作為使用者我們應該學會在不同的場景中如何更好的使用它,更大的發揮它的價值。主要可以從這四個方面進行優化:Redis鍵值設計、批處理優化、服務端優化、集群配置優化 1. Redis慢查詢日誌使用 Redis 提供了慢日誌命令的 ...
  • 一、序言 在日常一線開發過程中,多表連接查詢不可或缺,基於MybatisPlus多表連接查詢究竟該如何實現,本文將帶你找到答案。 在多表連接查詢中,既有查詢單條記錄的情況,又有列表查詢,還有分頁查詢,這些需求與多表連接是什麼關係,又該如何實現,這是本文討論的中心內容。 二、實戰編碼 1、兩個關聯DO ...
  • 本文講解二維碼的生成與解碼:使用Python工具庫qrcode『構建二維碼』,使用cv2和pyzbar兩類工具庫『解碼二維碼』。二維碼是目前最常使用的快捷信息存儲方式之一,讀完本篇即可掌握這一必備技能! ...
  • 有一個煤礦項目,使用iNeuOS系統時有一個需要是:要統計設備的運行時長,進一步統計設備運行效率。主要是有效分析設備運行狀態,合理的進行節能。iNeuOS本身具備強大的腳本能力,需要現場實施人員有一定腳本編寫能力,如果不具備腳本編寫能力,那麼下麵的模板修改相應的參數即可。 ...
  • 前言:本系列是我自己學習.net相關知識,以便跟上.net跨平臺的步伐,目前工作原因基本在.net Framework4.7以下,所以才有了這一系列的學習總結,但是並不是從基本的C#語法和基礎知識開始的,而是圍繞.net core以後平臺的重要設計和差異進行溫故知新。目的在於通過要點的梳理最後串聯起 ...
  • Linux 基礎-新手必備命令 概述 常見執行 Linux 命令的格式是這樣的: 命令名稱 [命令參數] [命令對象] 註意,命令名稱、命令參數、命令對象之間請用空格鍵分隔。 命令對象一般是指要處理的文件、目錄、用戶等資源,而命令參數可以用長格式(完整的選項名稱),也可以用短格式(單個字母的縮寫), ...
  • 1 hadoop-最全最完整的保姆級的java大數據學習資料 大數據技術解決的是什麼問題? 大數據技術解決的主要是海量數據的存儲和計算。 Hadoop的廣義和狹義之分 狹義的Hadoop:指的是一個框架,Hadoop是由三部分組成:HDFS:分散式文件系統--> 存儲; MapReduce:分散式離 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...