1. 程式人生 > 實用技巧 >DML: 資料庫操作語言

DML: 資料庫操作語言

DML 語言: 資料庫操作語言

增 

/*

方式一:
    語法: insert into 表名(列名1,...) values(值1...);
    注:
      1. 插入的值的型別要與列的型別一致或相容 2. 不可以為null的列必須插入值;可以為null的列有兩種方式:1. 插入式加了列名,對應值寫null;2. 插入時不加列名,對應value裡面也不需要寫,資料庫預設為null或預設值; 3. 列的順序可以調換,對應value也需要調換 4. 列數和值得個數必須一致 5. 可以省略列名,預設所有列,而且列的順序和表中列的順序一致 方式二:`     語法:       insert into 表名 set 列名=值,列名=值...
方式一和方式二:     1. 方式一支援插入多行,方式二不支援       insert into 表名 VALUES(...),(...),...     2.方式一支援子查詢,方式二不支援       INSERT INTO 表 SELECT value1,value2... UNION SELECT value1,value2...;
*/

刪 

/*

方式一: delete     單表刪除:         delete from 表名 where 篩選條件     多表刪除         sql 92             delete 表1的別名,表2的別名 from 表 1 別名, 表2 別名 where 連線條件 and 篩選條件; sql99: delete 表1的別名,表2的別名 from 表1 別名 inner|left|right join 表2 別名 on 連線條件 where 篩選條件; 案例: 刪除Bob的女朋友的資訊 DELETE g FROM girls g INNER JOIN boys b ON g.boyid=b.id WHERE b.name='Bob'; 案例: 刪除Bob的資訊以及他女朋友的資訊 DELETE g,b FROM girls g INNER JOIN boys b ON g.boyid=b.id WHERE b.name='Bob'; 方式二: truncate,清空表     truncate table 表名; 注:
  delete 和truncate
      1. delete 可以加where條件, truncate不能加 2. truncate 刪除,效率高一點 3. 假如要刪除的表中有自增長列,使用delete刪除胡,在插入資料,自增長列的值從斷點開始;使用truncate刪除後,在插入資料,自增長列的值從1開始。 4. truncate刪除沒有返回值,delete刪除有返回值 5. truncate 刪除不能回滾,delete刪除可以回滾
*/

改 

/*

1.修改單表記錄:
      語法: 
              update 表名  set 列=值,列=值... where 篩選條件;
2.修改多表記錄:
          語法:
                 sql 92
                update 表1 別名,表2 別名 set 列=值... where 連線條件 and 篩選條件;
                 sql99:
                   update 表1 別名 inner|left|right join 表2 別名 on 連線條件 set 列=值,... where 篩選條件;

*/

查  

SELECT column_name,column_name FROM table_name [WHERE Clause] [OFFSET M ][LIMIT N]

  • 查詢語句中可以使用一個或者多個表,表之間使用逗號(,)分割,並使用WHERE語句來設定查詢條件
  • SELECT 命令可以讀取一條或者多條記錄。
  • 你可以使用星號(*)來代替其他欄位,SELECT語句會返回表的所有欄位資料
  • 你可以使用 WHERE 語句來包含任何條件。
  • 你可以通過OFFSET指定SELECT語句開始查詢的資料偏移量。預設情況下偏移量為0。
  • 你可以使用 LIMIT 屬性來設定返回的記錄數。

SELECT

/*
  show databases;
  use weekly;
  show tables;-- 
  desc task;
  SELECT name FROM task;
  select * from weeklyinfo;
  SELECT id,name,owner,dueTime,'group' FROM task; 

  查詢常量     SELECT 100;     SELECT 'GARETH'; # 字元和日期必須用引號   
  查詢表示式     SELECT 100*99;
  查詢函式 SELECT 函式名(實參列表)     SELECT VERSION();
  起別名: 便於理解,如果要查詢的欄位有重名的情況,使用別名可以區分開來:
    兩種方式: 使用AS 或者空格; 如果別名有空格則使用引號括起來;       SELECT id, name AS 任務名, owner AS 責任人, 'group' AS 所屬組 FROM task;       SELECT id, name 任務名, owner 責任人, 'group' 所屬組 FROM task;
*/

去重: DISTINCT

/*
去重: 查詢任務表中所有責任人,責任人可能多條記錄
        SELECT DISTINCT owner FROM task;
*/    

+號的作用

/*
   select 100+90:  兩個運算元都為數值型,則做假髮運算;
   select '123'+90: 其中一方為字元型,試圖將字元型數值轉換成數值型;
                    如果轉換成功, 則繼續做加法運算;
   select 'gareth'+90   如果轉換失敗,則將字元型數值轉換成0
    
*/

NULL 與 <=>

當where查詢條件欄位為NULL時,該命令可能無法正常工作,可採用如下運算子:

  • IS NULL: 當列的值是NULL,此運算子返回true。
  • IS NOT NULL: 當列的值不為NULL, 運算子返回true。
  • <=>: 比較操作符,安全等於(不同於=運算子),當比較的的兩個值為NULL時返回true。判斷是否等於,如果等於則返True
  • 關於 NULL 的條件比較運算是比較特殊的。你不能使用 = NULL 或 != NULL 在列中查詢 NULL 值,即 NULL = NULL 返回false;等號不能判斷NULL
  • IS只能用於NULL 或 NOT NULL
#  NULL 判斷
    SELECT CONCAT(owner, 'group', IFNULL('content', '')) as 'out put' FROM task;

# 案例: 查詢content為NULL的記錄
SELECT * FROM  task WHERE content IS  NULL;
SELECT * FROM task WHERE content IS NOT NULL;

SELECT * FROM task WHERE content<=>NULL;
SELECT * FROM task WHERE id<=>10;

/*
    is null 和 <=>
        is null: 僅僅可以判斷NULL值; 可讀性高
        <=>: 既可以判斷NULL值,又可以判斷普通的值; 可讀性低
*/        

條件查詢

操作符描述例項
= 等號,檢測兩個值是否相等,如果相等返回true (A = B) 返回false。
<>, != 不等於,檢測兩個值是否相等,如果不相等返回true (A != B) 返回 true。
> 大於號,檢測左邊的值是否大於右邊的值, 如果左邊的值大於右邊的值返回true (A > B) 返回false。
< 小於號,檢測左邊的值是否小於右邊的值, 如果左邊的值小於右邊的值返回true (A < B) 返回 true。
>= 大於等於號,檢測左邊的值是否大於或等於右邊的值, 如果左邊的值大於或等於右邊的值返回true (A >= B) 返回false。
<= 小於等於號,檢測左邊的值是否小於於或等於右邊的值, 如果左邊的值小於或等於右邊的值返回true (A <= B) 返回 true。

使用主鍵來作為 WHERE 子句的條件查詢是非常快速的。

/*
    語法:
        SELECT 查詢列表 FROM 表名  WHERE 篩選條件
    分類:
        按條件表示式篩選:   > 、   <  、   = 、  != 、 <>   、>= 、 <=, 等號不能判斷NULL值
        邏輯表示式篩選:  &&、 || 、  !、  and   or    not
        模糊查詢:    like/ between and /   in  /   is null
*/

SELECT * FROM task WHERE id>10; SELECT name,owner FROM task WHERE owner='Gareth'; SELECT name,owner FROM task WHERE owner='Gareth' AND name='ddd';
#案例 查詢 id 不在10到20之間,或者責任人是Gareth的記錄
SELECT name,owner FROM task WHERE NOT(id>=10 AND id<=20) OR owner='Gareth';

模糊查詢

/*
like:通常與萬用字元搭配使用; like不能去匹配NULL,匹配失敗;可以匹配字元型和數值型;
        %:  百分號,匹配任意多個字元,包含0個字元;
        _:     下劃線,匹配任意單個字元
*/

# 案例 查詢任務名中包含 ‘模擬’ 的記錄
SELECT * FROM task WHERE name LIKE '%模擬%';
SELECT * FROM task WHERE name LIKE "__模擬%";

# 轉義
SELECT * FROM task WHERE name LIKE "_\_%";   # 匹配任務名第二個字元為下劃線的記錄 
SELECT * FROM task WHERE name LIKE "_$_%" ESCAPE '$'; # 把$定義為轉義符號,效果等同於上一條

between... and...

/*
between and
not between and
    使用between and 可以提高語句的簡潔度
    查詢結果包含臨界值;
    兩個臨界值不要調換順序,等價於大於等於左邊的值,小於等於右邊的值
*/

# 案例: 查詢 id在10到20之間的記錄
SELECT * FROM task WHERE id BETWEEN 10 AND 20;

in

/*
 in : 判斷某欄位的值是否屬於in列表中的某一項; 提高語句簡潔度; in列表的值必須一致或相容(相容 ('123',123)); 列表內容不支援萬用字元表示
*/
SELECT * FROM task WHERE name IN('ddddd','aaaaaa');

select * fromwhere id in (11,22,33)

select * fromwhere id not in (11,22,33)

select * fromwhere id in (select nid from 表)

常用函式:

/*
   concat函式: 拼接字元
    ifnull函式: 判斷某欄位或表示式是否為null,如果為null返回指定的值,否則返回原本的值; ifnull(欄位,指定值)
    isnull函式: 判斷某欄位或者表示式是否為null,如果是,則返回1,否則返回0
    LENGTH函式:
    
    呼叫: SELECT 函式名(實參列表) [ FROM 表]
    
    分類:
        單行函式: concat length  ifnull
        分組函式:  功能:做統計使用,又稱為統計函式,聚合函式,組函式
*/

CONCAT:

# 案例: 查詢責任人和所屬組連線成一個欄位,並顯示為 責任人組
SELECT CONCAT(owner,',','group') AS '責任人,組' FROM task;

字元函式

/*
  length:   
      select length('gareth') 獲取引數值得位元組數
  concat:
      select concat(name,'_',owner) from task; 字元拼接
  upper, lower:
      select concat(upper(name),'_',lower(owner)) from task; 大小寫
  substr: 索引從1開始, 擷取字元       select substr('abcdefg', 3) out_put; # 擷取指定索引處後面的所有字元(包括指定索引的字元),案例輸出cdefg select substr('abcdefg',1,3) out_put # 擷取從指定索引處指定字元長度的字元,案例輸出:abc
  instr: 返回子字串第一次出現的索引,如果找不到返回0 select instr('str_sub_abcdefg', 'sub_abc') as out_put;
  trim: 去掉字串前後空格,也可以去掉指定字元 select trim(' abc ') as output; # 輸出abc select trim('a' from 'aaaaabaaca') as out_put; 去電字串前後的'a', 輸出baac select trim('aa' from 'aaaaabaaca) as out_put; 輸出 abaaca ldap:用指定的字元實現左填充指定的長度, 如果字串超過指定長度,則截斷 rpad:用指定的字元實現右填充指定的長度 select lpad('strabcd', 10,'*') as out_put replace: 替換 select replace('abcdefg', 'abc','ggg') as output; 把abc替換成ggg
*/

數學函式

/*
    round()    四捨五入
            select round(-1.55);
            select round(-1.555,2); 保留兩位小數
    
    ceil:  向上取整,返回大於或等於該引數的最小整數
    floor:   向下取整
    truncate:  截斷
            select truncate(1.6999,1); 返回1.6
        
    mod     取餘
            mod(a,b)   等價於a-a/b*b
            select mod(10,3);
            select 10%3


*/    

日期函式

/*
    now()     返回當前系統日期+時間
    curdate()  返回當前系統日期
    curtime()    返回當前系統時間
    DIFFRENCE('time1','time2') 返回兩個日期相差的天數
            
    select now();    可以獲取指定的部分,年(YEAR), 月(month, 或者    monthname),日(),時(),分(),秒()
            
    select YEAR(NOW()) 年;
    select YEAR("1993-09-01") 年;
        
    str_to_date   將字串通過指定的格式轉換成日期
            select str_to_date('1998-01-02', '%Y-%c-%d');
         
     date_format   將日期轉換成字元  
            select date_format(now(), '%y年%m月%d日');

*/    

其他函式

 version();
 database();
 user();

流程控制函式

/*
 
if函式, if else     select task,owner,IF(coment is null,'值,正確', '值2,錯誤') 備註 FROM task;
case函式,   使用一: switch case 的效果       case 要判斷的欄位或表示式 WHEN 常量1 THEN 要顯示的值1或語句1       WHEN 常量2 THEN 要顯示的值2或語句2   ... ELSE 要顯示的值n或語句n end
      SELECT name,owner,group_id CASE group_id WHEN 1 THEN "AAAAA" WHEN 2 THEN "BBBBB" ELSE 'DDDDD' END AS 備註 FROM task;
使用二:相當於if elif .. else   case   when 條件1 then 要顯示的值1或語句1   when 條件2 then 要顯示值2或語句2   else 要顯示的值n或語句n   end
    SELECT salary, CASE WHEN salary>2000 THEN 'A' WHEN salary>1500 THEN "B" WHEN salary>1000 THEN 'C' ELSE 'D' END CASE 工資級別 FROM employees;
*/

分組函式

/*

功能: 用作統計使用,又稱為聚合函式或統計函式或組函式
sum() 求和 AVG MIN MAX COUNT
特點:   sum 和 avg 一般用於處理數值型   max min count 可以處理任何型別
  以上分組函式都忽略null值   COUNT函式單獨介紹,一般使用COUNT(*) 統計行數   和分組函式一同查詢的欄位要求是group by後的欄位
簡單使用:   select sum(salary) from tb;   select avg(salary) FROM tb;   SELECT MIN(salary) FROM tb;   SELECT MAX(salary) FROM tb;   SELECT COUNT(salary) FROM tb;   SELECT SUM(salary) 和, AVG(salary) 平均,COUNT(salary) 個數 FROM tb;
引數支援哪些型別:   sum('aaadsd') 返回0   count 計算不為none的個數   可以和distinct搭配:SELECT SUM(DISTINCT salary), SUM(salary) FROM tb; COUNT 詳細說明   一般使用COUNT(*)統計行數   SELECT COUNT(salary) FROM tb;   SELECT COUNT(*) FROM tb;   SELECT COUNT(1) FROM tb;
效率問題:   MYISAM 儲存引擎下,COUNT(*) 的效率高   INNODB 儲存引擎下, COUNT(1)和COUNT(*)效率差不多,比COUNT(欄位)高
*/

分組查詢

/*
分組查詢:  可以使用GROUP BY 字句將表中的資料分成若干組

分組資料: GROUP BY 字句語法 語法:   SELECT column, group_function(column)   FROM tb   [WHERE condition]   [GROUP BY group_by_expression]   [ORDER BY column];
注意:
  WHERE 一定放在FROM後面;查詢列表必須特殊,要求是分組函式和group by後出現的欄位
特點:   分組查詢中的篩選條件分為兩類:     分組前篩選 對原始表資料 GROUP BY 字句前面 WHERE 關鍵字     分組後篩選 對分組後的結果集 GROUP BY 子句後面 HAVING 關鍵字   分組函式做條件肯定是放在HAVING 字句中   能用分組前篩選的,優先考慮使用分組前篩選   GROUP BY 子句支援單個欄位分組,多個欄位分組(多個欄位用逗號隔開,沒有順序要求),表示式或函式(用的較少)   也可以新增排序,排序放在最後 # 案例 查詢每個工種的最高工資   SELECT MAX(salary), job_id FROM tb GROUP BY job_id; # 案例 查詢每個位置上的部門的個數   SELECT COUNT(*), location_id FROM tb GROUP BY location_id;
新增分組前的篩選   # 案例 查詢郵箱中包含a字元的,每個部門的平均工資     SELECT AVG(salary), department_id, department_id FROM employees WHERE email link '%a%' GROUP BY department_id;
新增分組後的篩選條件: HAVING   # 案例 查詢哪個部門的員工人數大於2     SELECT COUNT(*),department_id FROM tb GROUP BY department_id HAVING COUNT(*)>2;
  # 案例 查詢每個工種有獎金的員工的最高工資大於12000 的工種編號和最高工資     SELECT MAX(salary),job_id FROM tb WHERE commission_pct IS NOT NULL GROUP BY job_id HAVING MAX(salary)>12000;
  # 案例 查詢領導編號大於100的每個領導手下員工的最低工資大於5000的領導編號以及其最低工資     SELECT MIN(salary), manager_id FROM tb WHERE manage_id>100 GROUP BY manager_id HAVING MIN(salary) > 5000;
按表示式或者函式分組   #案例 按員工姓名的長度分組,查詢每一組員工的員工個數,篩選員工個數大於5的有哪些     SELECT COUNT(*), name FROM tb GROUP BY LENGTH(name) HAVING COUNT(*) > 5;     SELECT COUNT(*) c, name FROM tb GROUP BY LENGTH(name) HAVING c> 5; 按多個欄位分組   # 案例 查詢每個部門每個工種的員工的平均工資     SELECT AVG(salary), department_id, job_id FROM tb GROUP BY department_id,job_id;
新增排序:   # 案例 查詢每個部門每個工種的員工的平均工資, 並且按平均工資的高低顯示     SELECT AVG(salary), department_id, job_id FROM tb GROUP BY department_id,job_id ORDER BY AVG(salary) DESC;     SELECT AVG(salary), department_id, job_id FROM tb WHERE department_id is not null GROUP BY department_id,job_id HAVING AVG(salary)>10000 ORDER BY AVG(salary) DESC;
*/

連線查詢

/*

又稱多表查詢,當查詢的欄位來自多個表時,就會用到連線查詢。 笛卡爾乘積: 表1 有m行,表2 有n行,結果=m*n行   發生原因: 沒有有效的連線條件   如何避免: 新增有效的連線 新增有效的連線條件分類:   按年代分類:     sql92標準: 僅僅支援內連線     sql99標準: 推薦   按功能分類:     內連線:       等值連線:       非等值連線:       自連線:     外連線:       左外連線:       右外連線:       全外連線:       交叉連線:

語法: SELECT name,boyName from beauty,boys; SELECT name,boyName from beauty,boys WHERE beauty.boys_id=boys.id; sql92標準   1.等值連線     多表等值連線的結果為多表的交集部分     n表連線,至少需要n-1個連線條件     多表的順序沒有要求     一般需要為表起別名     可以搭配前面介紹的所有子句使用,比如排序,分組等     1. 等值連線:       SELECT name,boyName from beauty,boys WHERE beauty.boys_id=boys.id;     
      # 查詢員工名和對應的部門名         SELECT name,department_name FROM employees,departments WHERE employees.department_id=departments.id;
    2. 為表起別名       提高語句的簡潔度,區分多個重名的欄位       注意: 如果為表起了別名,則查詢的欄位就不能使用原來的表名去限定     
      # 查詢員工名,工種號,工種名         SELECT e.name,e.job_id,j.job_name FROM employees e, jobs j WHERE e.job_id=j.id;   
    3. 兩個表的順序是可以調換的       SELECT e.name,e.job_id,j.job_name FROM jobs j, employees e WHERE e.job_id=j.id;
    4. 可以加篩選       # 案例 查詢有獎金的員工名,部門名         SELECT name, department_name FROM employees e, deportments d WHERE e.department_id=d.id AND e.commission_pct IS NOT NULL;       # 案例 查詢城市名中第二個字元為o的部門名或城市名         SELECT d.department_name,c.city_name FROM department d, city c WEHER city_name LIKE '_o%' AND d.city_id=c.id;
    5. 可以加分組       # 查詢每個城市的部門個數         SELECT count(*),city_name FROM departments d,citys c WHERE d.city_id=c.id GROUP BY city_name;       # 案例 查詢有獎金的每個部門的部門名和部門領導編號和該部門的最低工資。         SELECT department_name, d.manager_id,MIN(salary) FROM employees e,departments d WHERE e.commission_pct IS NOT NULL AND d.id=e.department_id GROUP BY d.department_name, manager_id;       注: GROUP BY後面加manage_id,是因為manage_id和部門不一定是一一對應。如果是不加也可以   
    6. 可以加排序       # 案例 查詢每個工種的工種名和員工的個數,並且按員工的個數降序         SELECT job_name, COUNT(*) FROM job j, employees e WHERE e.job_id=j.id GROUP BY job_name ORDER BY COUNT(*) DESC;     7. 三表連線       # 查詢員工名,部門名,和所在城市         SELECT name,department_name,city_name FROM employees e,departments d,city c WHERE e.department_id=d.id and d.city_id=c.id;   2。 非等值連線     # 案例 查詢員工的工資和工資級別         SELECT salary, grade_level FROM employees e,job_grades g WHERE salary BETWEEN g.lowest_sal AND g.highest_sal;   3. 自連線     # 案例 查詢員工名和上級的名稱         SELECT e.employee_id, e.name,m.employee_id,m.name FROM emplyoees e, employees m WHERE e.employee_id=m.employee_id; sql99語法:   語法:     select 查詢列表 from 表1 別名 【連線型別】 join 表2 別名 on 連線條件 【WHERE】 【GROUP BY】 [HAVING] [ORDER BY]   分類:     內連線: inner     外連線       左外 left 【outer】       右外 right [outer]       全外 full [outer]     交叉連線 cross   內連線     語法:       SELECT 查詢列表 FROM 表1 別名 inner join 表2 別名 on 連線條件;     分類:       等值       非等值       自連線 特點: 新增排序,分組,篩選 inner可以省略 篩選條件放在WHERE後面,連線條件放在ON後面,提高分離性,便於閱讀 inner join連線和sql92語法中的等值連線效果是一樣的,都是查詢多表的交集 案例: 等值連線 查詢員工名、部門名 SELECT name,department_name FROM employees e INNER JOIN departments d ON e.department_id=d.id; 查詢名字中包含e的員工名和工種名(新增篩選條件) SELECT name,job_name FROM emlopyees e INNER JOIN jobs j ON e.job_id=j.id WHERE e.name like '%e%'; 查詢部門個數大於3的城市名和部門個數 SELECT city_name,COUNT(*) FROM depaments d INNER JOIN city c ON c.id=d.city_id GROUP BY city_name HAVING COUNT(*)>3; 查詢哪個部門的員工個數大於3的部門名和員工個數,並按個數降序(新增排序) SELECT department_name,COUNT(*) FROM employees e INNER JOIN departments d ON e.department_id=d.id GROUP BY department_name HAVING COUNT(*)>3 ORDER BY COUNT(*) DESC; 查詢員工名,部門名,工種名,並按部門名降序; SELECT name,d.name,j.name FROM employees e INNER JOIN departments d ON e.department_id=d.id INNER JOIN jobs j ON j.id=e.job_id ORDER BY department DESC; 案例: 非等值連線 查詢員工的工資級別 和工資 SELECT salary, grade_level FROM employees e JOIN grades g ON e.salary BETWEEN g.lowest_sal AND g.highest_sal; 查詢工資級別的個數大於2,並且按工資級別降序; SELECT grade_level, COUNT(*) FROM emlopyees e JOIN grades g ON e.salary BETWEEN g.lowest_sal AND g.highest_sal GRADE BY grade_level HAVING COUNT(*)>2 ORDER BY grade_level DESC; 案例: 自連線 查詢員工的名字,上級的名字 SELECT e.name, m.name FROM employees e JOIN employees m ON e.manage_id=m.id; 外連線 應用場景: 用於查詢一個表中有,另一個表沒有的記錄 特點: 外連線的查詢結果為主表中的所有記錄: 如果從表中有和它匹配的,則顯示匹配的值; 如果從表中沒有和它匹配的,則顯示null; 外連線查詢結果=內連線結果+主表中有而從表中沒有的記錄 左外連線: left join, 左邊的是主表 右外連線: right join, 右邊的是主表 左外和右外交換兩個表的順序,可以實現同樣的效果 全外連線=內連線的結果+表1中有但表2中沒有 + 表2中有,但表1中沒有 案例: SELECT g.name, b.* FROM girls g LEFT OUTER JOIN boys b ON g.boy_id=b.id; SELECT g.name, b.* FROM girls g LEFT OUTER JOIN boys b ON g.boy_id=b.id WHERE b.id IS NULL; 查詢哪個部門沒有員工 SELECT d.*,e.id FROM departments d LEFT OUTER JOIN employees e ON e.department_id=d.id WHERE e.id IS NULL; SELECT d.*,e.id FROM employees e RIGHT departments d ON e.department_id=d.id WHERE e.id IS NULL; 查詢部門名為SAL或IT的員工資訊 SELECT e.*,d.name FROM departments d LEFT JOIN employees e ON e.department_id=d.id WHERE d.name IN ['SAL', 'IT']; 全外連線 交叉連線: 結果是笛卡爾積 SELECT b.*,g.* FROM girls g CROSS JOIN boys b; sql99和sql92 PK 內連線: 交集 外連線: 查詢主表的所有記錄
*/

子查詢

/*
 出現在其他語句內部的select語句,稱為子查詢或內查詢
        內部巢狀其他select語句的查詢,稱為外查詢或主查詢
        
        分類:
                按子查詢出現的位置:
                            SELECT 後面: 僅僅支援標量子查詢
                            FROM 後面:      支援表子查詢
                            WHERE 或HAVING 後面: 標量子查詢(單行),列子查詢(多行),行子查詢
                            EXISTS 後面:       表子查詢
                按結果集的行列數不同:    
                            標量子查詢(結果集只有一行一列)
                            列子查詢(結果集只有一列多行)
                            行子查詢(結果集有一行多列)
                            表子查詢(結果集一般為多行多列)
                    
       一、 WHERE 或 HAVING後面的
            特點:
                    子查詢放在小括號內;
                    子查詢一般放在條件的右側;
                    標量子查詢,一般搭配著單行操作符使用: >  <   >=  <=  <>
                    列子查詢:,一般搭配著多行操作符使用: in   any/some   all
                    子查詢的執行優先於主查詢執行,主查詢的條件用到了子查詢的結果
            1. 標量子查詢(單行子查詢)
                    案例:  查詢誰的工資比Abel高
                            SELECT * FROM employees WHERE salary>( SELECT salary FROM employees WHERE name=Abel );
                    案例:   返回job_id與141號員工相同,salary比143號員工多的員工姓名,job_id和工資
                            SELECT 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 )
                    案例:  返回公司工資最少的員工的name,job_id和salary
                            SELECT name,job_id,salary FROM employees WHERE salary=( SELECT MIN(salary) FROM employees );
                    案例:  查詢最低工資大於50號部門最低工資的部門id和其最低工資
                            SELECT MIN(salary),department_id FROM employees GROUP BY department_id HAVING MIN(salary)>( SELECT MIN(salary) FROM employees WHERE department_id=50);
                    非法使用標量子查詢,結果是一行一列
                    
            2. 列子查詢(多行子查詢: IN 等價於 =ANY   NOT IN 等價於 <>ALL    ANY 可以和 MIN換,  ALL可以和MAX換
                    案例:  返回location_id 是1400或1700的部門中的所有員工姓名
                            SELECT name, department_id FROM employees WHERE department_id IN ( SELECT DISTINCT department_id FROM departments WHERE location_id IN (1400, 1700)  )
                        或  SELECT name, department_id FROM employees WHERE department_id =ANY ( SELECT DISTINCT department_id FROM departments WHERE location_id IN (1400, 1700)  )
                    
                    案例:  返回其他工種中比job_id為‘IT_PROG’工種任一工資低的員工的員工工號,姓名,job_id以及salary.
                            SELECT 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 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'; 
                    案例:  返回其他工種中比job_id為‘IT_PROG’工種所有工資都低的員工的員工工號,姓名,job_id以及salary.
                            SELECT name,employee_id,job_id,salary FROM employees WHERE salary<ALL( SELECT DISTINCT salary FROM employees WHERE job_id='IT_PROG' ) AND job_id<>'IT_PROG'; 
                        或  SELECT name,employee_id,job_id,salary FROM employees WHERE salary<( SELECT MIN(salary) FROM employees WHERE job_id='IT_PROG' ) AND job_id<>'IT_PROG';
                    
            3. 行子查詢(多列多行或一行多列)
                    案例:  查詢員工編號最小並且工資最高的員工資訊
                            SELECT * FROM employees WHERE (employee_id,salary)=( SELECT MIN(employee_id),MAX(salary) FROM employees );
     二、 SELECT 後面: 
            僅僅支援標量子查詢
                    案例:  查詢每個部門的員工個數  (內連線也可以實現)
                            SELECT d.*,( SELECT COUNT(*) FROM employees WHERE e.department_id=d.id ) 個數 FROM department d;
                    案例:  查詢員工號=102的部門名
                            SELECT ( SELECT department_name  FROM departments d WHERE  d.id=e.id) FROM employees e WHERE e.id=102;
                        或  SELECT department_name FROM department INNER JOIN employees e ON d.department_id=e.department_id WHERE e.id=102;
     三、FROM 後面:    將子查詢結果充當一張表,要求必須起別名  
            支援表子查詢               
                   案例:   查詢每個部門的平均工資的工資等級 
                            SELECT ag_dep.*,g.grade_level FROM ( SELECT AVG(salary) ag,department_id FROM employees GROUP BY department_id ) ag_dep INNER JOIN job_grades g ON
                                ag_dep.ag BETWEEN lowest_sal AND highest_sal;
                    
     四、EXISTS 後面(相關子查詢):       表子查詢              
                    語法: 
                            exists (完整的語句)
                    結果: 0或1
                    案例:  查詢有員工的部門名
                            SELECT department_name FROM departments d WHERE EXISTS( SELECT * FROM employees e WHERE d.department_id=e.department_id );
                        或  SELECT department_name FROM departments d WHERE d.department_id IN (SELECT DISTINCT department_id FROM employees e);
    案例:                    
            案例1:  查詢和Bob 相同部門的員工姓名和工資        
                     SELECT name,salary FROM employees e WHERE e.department_id=( SELECT department_id FROM employees WHERE name=Bob ); 
            案例2:  查詢工資比公司平均工資高的員工的員工號,姓名和工資
                     SELECT  id,name,salary FROM employees WHERE salary > ( SELECT avg(salary) FROM employees );
            案例3:  查詢各部門中工資比本部門平均工資高的員工的員工號,姓名和工資
                     SELECT id,name,salar FROM employees e INNER JOIN (SELECT AVG(salary) ag,department_id FRMO employees GROUP BY departmen_id) ag_dep ON e.department_id=ag_dep.department_id WHERE e.salary>ag_dep.ag;
            案例4:  查詢在部門的location_id 為1700的部門工作的員工的員工號
                     SELECT id,name FROM employees WHERE department_id IN ( SELECT department_id FROM departments WHERE location_id=1700 );
            案例5:  查詢和姓名中包含字母u的員工在相同部門的員工的員工號和姓名
                     SELECT id,name FROM employees WHERE department_id IN ( SELECT DISTINCT department_id FROM employees WHERE name like '%u%' );
            案例6:     查詢管理者是Kin的員工姓名和工資
                     SELECT name,salary FROM employees WHERE manage_id IN (  SELECT id FROM employees WHERE name='Kin' )
            案例7:  查詢工資最高的員工的姓名,要求姓和名顯示為一列,列名為 姓.名
                     SELECT CONCAT(first_name,'.',last_name) '姓.名' FROM employees WHERE salary=( SELECT MAX(salary) FROM employees );       
*/

分頁查詢

/*
應用場景:  當要顯示的資料,一頁顯示不全,需要分頁提交sql請求
          語法:
                    SELECT 查詢列表  FROM 表 [ join type join 表2 ON 連線條件 WHERE 篩選條件 GROUP BY 分組欄位 HAVING  分組後篩選 ORDER BY  排序 ] LIMIT offset,size;
                        offset: 要顯示條目的其實索引,從0開始
                        size:    要顯示的條目個數
          特點:    
                    LIMIT 語句放在查詢語句的最後;
                    要顯示的頁數page, 每頁條目數size:
                        SELECT 查詢列表 FROM 表 LIMIT (page-1)*size,size;
          案例:     查詢前五條員工資訊
                    SELECT * FROM employee LIMIT 0,5; 或 SELECT * FROM employees LIMIT 5;
                    查詢第11條到第25條
                    SELECT * FROM employees LIMIT 10,15;
                    查詢有獎金的員工資訊,並且工資較高的前10名顯示出來
                    SELECT * FROM employees WHERE commission_pct IS NOT NULL ORDER BY salary DESC LIMIT 10;

*/

聯合查詢

/*
 union 聯合  合併:將多條查詢語句的結果合併成一個結果
        語法:  查詢語句1  union 查詢語句2 union ...
        應用場景: 
                要查詢的結果來自多個表,且多個表沒有直接的連線關係,但查詢的資訊一致時
        特點:
                要求多條查詢語句的查詢列數是一致的
                要求多條查詢語句的查詢的每一列的型別和順序最好一致
                union 關鍵字預設去重,如果使用union all 可以包含重複項
        案例:  查詢部門編號大於90或郵箱包含a的員工資訊
                 SELECT * FROM employees WHERE email LIKE '%a%' OR department_id>90;
                 SELECT * FROM employees WHERE email LIKE '%a%' UNION SELECT * FROM employees WHERE department_id>90;

*/

排序查詢

/*
語法:
    SELECT 查詢列表 FROM 表 WHERE 篩選條件 ORDER BY 排序列表 [ASC|DESC]
    排序列表:可以為欄位,可以為表示式,也可以按別名排序,也可以是函式
    DESC 降序  
    ASC  升序,預設是升序
*/
SELECT * FROM task ORDER BY owner DESC;

# 案例: 查詢id大於等於90,按截止時間先後排序, 按欄位排序
SELECT * FROM task WHERE id>=90 ORDER BY due_time ASC; 

# 案例:  查詢id大於等於90,按截止時間先後排序, 按別名
SELECT owner '責任人' FROM task WHERE id>=90 ORDER BY '責任人' DESC;
# 案例 按任務名的長度顯示任務資訊
SELECT LENGTH(name) 任務名長度,owner FROM task ORDER BY LENGTH(name) DESC;
# 案例: 查詢任務資訊,先按owner排序,再按id排序,即多個欄位排序
SELECT * FROM task ORDER BY owner ASC,id DESC;


例項

/*
1.  試問下面兩條語句執行結果是否一樣
SELECT * FROM task; 和 SELECT  * FROM task WHERE  content LIKE "%%" AND name like "%%"; 
答: 不一樣;如果判斷的欄位有NULL值,like匹配失敗;如果沒有NULL值,則結果一樣。

2. 已知表stuinfo:  學號(id)、姓名(name)、郵箱(email)、gradeID(年級編號)、性別(sex)、age(年齡)
         grade:     年級編號(id)、年級名稱(gradeName)
   查詢所有學員的郵箱的使用者名稱(注:郵箱中@前面的字元)
        SELECT SUBSTR(email,1, INSTR(email,'@')-1) FROM stuinfo;
   查詢男生和女生的個數
        SELECT COUNT(*), sex FROM stuinfo GROUP BY sex;
    查詢年齡大於18的所有學生的姓名和年級名稱
        SELECT naem, g.gradeName FROM stuinfo s INNER JOIN grade g ON s.gradeID=g.id WHERE s.age>18;
    查詢哪個年級的學生最小年齡大於20;
        SELECT MIN(AGE), gradeID FROM stuinfo group by gradeID having MIN(age) >20;
    試說出查詢語句中涉及到的所有關鍵字,以及執行先後順序
        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
3.     查詢工資最低的員工資訊: name, salary    
        SELECT name, salary FROM employees WHERE salary=( SELECT MIN(salary) FROM employees );
4.  查詢平均工資最低的部門資訊    
        SELECT d.* FROM departments d WHERE d.department_id=( SELECT department_id FROM employees GROUP BY department HAVING  AVG(salary)=(
            SELECT MIN(ag) FROM ( SELECT AVG(salary) ag,department_id FROM employees GROUP BY department_id ) ag_dep)  ); 
        或  SELECT d.* FROM department d WHERE d.department_id =( SELECT department_id FROM employees GROUP BY department_id ORDER BY AVG(salary) LIMIT 1 );
5.  查詢平均工資最低的部門資訊和該部門的平均工資
        SELECT d.*,ag FROM department d JOIN ( SELECT AVG(salary), department_id FROM employees GROUP BY department_id ORDER BY AVG(salary) LIMIT 1  ) ag_dep ON d.department_id=ag_dep.department_id;
        
6.  查詢平均工資最高的job資訊    
        select * from jobs WHERE job_id=(SELECT job_id FROM employees GROUP BY  job_id ORDER BY AVG(salary) desc LIMIT 1);

7.    查詢平均工資高於公司平均工資的部門有哪些
        SELECT AVG(salary), department_id FROM employees GROUP BY dapartment_id HAVING AVG(salary) > ( SELECT AVG(salary) FROM employees );

8.  查詢公司中所有manager的資訊
        SELECT * FROM employees WHERE id= ANY (SELECT DISTINCT manage_id FROM employees);

9.  各部門中最高工資中最低的那個部門的最低工資是多少
        SELECT MIN(salary),department_id FROM employees WHERE department_id=( SELECT department_id FROM employees GROUP BY department_id ORDER BY MAX(salary) LIMIT 1 )
10.  查詢平均工資最高的部門的manager的詳細資訊: name, id,salary            
        SELECT name,id,salary FROM employees e INNER JOIN departments d ON d.manager_id=e.id WHERE d.department_id=(
              SELECT department_id FROM employees GROUP BY department_id ORDER BY AVG(salary) desc LIMIT 1);

11. 查詢每個專業的學生人數
        SELECT majorid,COUNT(*) FROM student GROUP BY majorid;
        
12. 查詢參加考試的學生中,每個學生的平均分,最高分
        SELECT AVG(score),MAX(score),studentno FROM result GROUP BY studentno;
13. 查詢姓張的每個學生的最低分大於60的學號,姓名
        SELECT s.studentno,s.name,MIN(score) FROM student s JOIN result r ON s.studentno=r.studentno WHERE s.name LIKE '張%' GROUP BY s.studentno HAVING MIN(score)>60;

14. 查詢生日在1988-1-1後的學生姓名,專業名稱
        SELECT name,majorname FROM student s JOIN major m ON s.majorid=m.id WHERE DATEDIFF(borndate,'1988-1-1')>0;
        
15. 查詢每個專業的男生人數和女生人數分別是多少
        SELECT COUNT(*), sex, majorid FROM student GROUP BY sex,majorid;
    或  SELECT majorid, ( SELECT COUNT(*) FROM stuent WHERE sex='男' AND majorid=s.majorid ) 男,( SELECT COUNT(*) FROM student WHERE sex='女' AND majorid=s.majorid )女
            FROM student s GROUP BY majorid;

16. 查詢專業和Bob一樣的學生的最低分
        SELECT MIN(score) FROM result WHERE studentno IN( SELECT studentno FROM student WHERE majorid=( SELECT majorid FROM student WHERE name = 'Bob' ) );

17. 查詢大於60分的學生姓名、密碼、專業名
        SELECT name,passwd,majorname FROM student s JOIN major m ON s.majorid=m.majorid JOIN result r ON s.studentno = r.studentno WHERE r.score>60;
        SELECT name,passwd,majorname FROM student s JOIN major m ON s.majorid=m.majoeid WHERE s.studentno IN   (SELECT studentno FROM result WHERE score > 60);
18. 按郵箱位數分組,查詢每組的學生個數
        SELECT COUNT(*),LENGTH(email) FROM student GROUP BY LENGTH(email);

19. 查詢學生名、專業名、分數
        SELECT studentname,score,majorname FROM student s JOIN major m ON s.majorid=m.majorid LEFT JOIN result r ON s.studentno=r.studentno;

20. 查詢哪個專業沒有學生,分別用左連線和右連線實現
        SELECT m.majorid,m.majorname FROM major m LEFT JOIN student s ON m.majorid=s.majoeid WHERE s.studentno IS NULL;
        SELECT m.majorid,m.majorname FROM student s RIGHT JOIN major m ON m.majorid=s.majoeid WHERE s.studentno IS NULL;

21. 查詢沒有乘積的學生人數。
        SELECT COUNT(*) FROM student s LEFT JOIN result r ON s.studentinfo=r.studentinfo WHERE  r.id IS NULL;
    
*/