MySQL學習筆記-2

  1. 鏈接查詢html

    主要分爲內鏈接(等值鏈接,非等值鏈接,自鏈接),外鏈接(左外鏈接,右外鏈接,全外鏈接),交叉鏈接三大類。mysql

    sql92標準中: from 表1,表2 ,表3 where 條件1 and 條件2 and 題目條件
    sql99標準中: from 表1 join 表2 on 條件1 join 表3 on 條件2 where 題目條件sql

    • 內鏈接:表之間經過某種關係創建鏈接來進行關聯查詢。其中自鏈接是針對自身的兩次表的查詢,必須指定別名來區別查詢時使用哪一次的表數據庫

    • 外鏈接函數

      • 外鏈接主要用於添加 where語句後篩選:(主表中有可是副表中沒有)'s 主表中的對象。不添加where 語句則篩選出:以主表爲主的主副鏈接表優化

      • select 字段 
        from table_m 
        left [outer] join table_vice1 on 表間關聯條件1 
        [left join table_vice2 on 關聯條件2 ...] 
        where condition_clause;#條件語句通常爲 ... is [not] null .
      • 與查詢有關的關鍵字段屬於哪一個表,哪一個表就是主表。code

      • 例如:查詢沒有獎金的員工姓名,此時員工表e就爲主表,獎金錶s爲副表。
        SELECT e.e_name FROM e LEFT JOIN s ON e.e_id=s.e_id WHERE s.e_id IS NULL; htm

      • right [outer] join 相似同理(主副表位置調換)對象

      • full [outer] join 全鏈接 :兩表交集(經過內鏈接可實現)+左外鏈接(A主B副)+左外鏈接(B主A副)blog

    • 交叉鏈接:交叉鏈接是笛卡爾積在sql中的實現。 關鍵字:cross join

  2. 子查詢(內查詢)

    • 定義:出如今其餘語句中的select查詢語句。
    • 按照子查詢出現的位置能夠主要分爲四類:
      • select語句中:僅僅支持標量子查詢(查詢結果爲一行一列/單個字段)。
      • from語句中:支持表子查詢,即將查詢的結果集充當一張'新表'(必須起別名以供調用)。
      • where/having 條件語句:支持標量子查詢(>.<,=,<>);列子查詢(單列多行:判斷大小時與in語句,any/some語句或all語句嵌套使用。in能夠改寫爲=any,not in 能夠改寫爲<>all);行子查詢(較少應用)。
      • exists語句中(相關子查詢):表子查詢。
    • 子查詢語句應包含在"()"內,且結束用 右括號")"標識便可,不該再加分號表示子查詢語句的結束,分號可能會被誤認爲是用來標識主查詢語句的結束,會報錯。
  3. 聯合查詢

    • 關鍵字:Union 將多條查詢語句的結果合併成一個結果。
    • 應用場景; 要查詢的結果來自多個表,且多個表之間沒有直接的鏈接關係,但查詢的信息一致時。
    • 特色: 查詢的字段數需相等;各字段類型與順序最好保持一致;union 默認去重,若需包含重複項,可以使用union all .
  4. 一些思考點

    • (1) . group by語句的使用場景。
      多表鏈接查詢時,若主查詢的select字段中含有 count, sum, average等聚合函數,以 "查詢每一個部門的員工個數" 爲例:

      • 若count字段做爲外查詢字段而直接顯式存在,須要使用group by 語句呈現分類效果

        select d.* ,count(e.department_id) as 員工個數 
        from departments d 
        left join employees e on e.department_id =d.department_id  
        group by d.department_id;
        /* count(e.department_id) 不該書寫爲count(d.department_id),也不該書寫爲count(*),二者都會致使本沒有員工的部門員工個數計爲1。應充分理解外鏈接查詢結果的含義,從而理解外查詢count(para)字段中para的不一樣所對應的含義,當para爲「*」時,是計算列數,空值也會計算在內並計爲1,故當要求「沒有員工的部門的員工個數既要正確書寫爲0,又不能省略員工個數爲0的部門(簡單的在e表中按照d_id分類count查詢)」時正確操做應爲:d表爲主 e表爲副 group by(d.department_id) 查詢 count(e.department_id)  */

        假如無group by 子句,則查詢結果將始終爲單行,無論與count(*)同時查詢的還有什麼字段。如:
        image-20210124151548585
        或是(不合題,僅做示例):
        image-20210124151719938

      • 若count字段做爲子查詢(內查詢)隱式存在

        select d.* ,(select count(*) from employees e where e.department_id = d.department_id ) 員工個數 
        from departments d ;

        此時爲內外嵌套,外在表現爲單表查詢

        • 外爲主,即d表爲主,首先保證了部門的完整呈現,即不會像 ①e表爲主,d表爲副鏈接查詢時count(*) ; ②內鏈接時count(*) 由於某些部門無員工而缺省該行
        • 外爲主,即d表爲主且 count查詢字段隱式存在, 又保證了查詢結果直接按照d表desc呈現,無需group by子句再進行分類。
        • 實際上,內在的來說,該操做仍是屬於兩錶鏈接查詢 (內鏈接),只不過是沒有向92的','或者99的'join'之類的關鍵字眼。(理解語句之間的執行順序)
    • (2). Exist 子查詢的使用。(未充分理解)
      博客園'半壁江山'總結詳細,可供參考 關鍵字: 執行順序&規則,boolean,應用場景,效率。

    • (3). 如題:查詢各部門工資比所在部門平均工資高的員工的員工號,姓名,薪資

      • ① 第一想法: 內鏈接+where clause 子查詢 關聯三表 ,結果正確,表面也易理解。

        select d.department_id , d.department_name ,e.employee_id , e.last_name , e.salary 
        from employees e 
        join departments d on e.department_id = d.department_id  
        where salary > (select avg(salary) from employees em where em.department_id = e.department_id);
      • ② 將各部門的平均工資經過 select 子查詢 命名'建表' ——davg。employees,departments,davg 三表左外鏈接 。

        • code以下:
        select d.department_id , d.department_name ,e.employee_id , e.last_name , e.salary , davg.a  as 該部平均工資
        from departments as d 
        left join employees as e on e.department_id = d.department_id 
        left join (select department_id , avg(salary) a from employees group by department_id ) as davg on davg.department_id = d.department_id where e.salary > davg.a 
        order by davg.a,e.salary;
        • 固然由於where語句的限制,某些沒有員工的部門沒有呈現出來。(固然題目也沒有這種要求,可是理論上d爲主表進行 left join 查詢時全部的部門都應該呈現,即便對應的其他表爲皆爲null值)。經過刪除where 限制,並按department_id DESC排列能夠看到實際上三表鏈接後是存在這樣的數據的。

          • code:
          ...
          on davg.department_id = d.department_id 
              order by d.department_id DESC 
              limit 0,50;
          • 關於上述代碼中的 Limit clause ,詳見手冊13.2.10 Select Statement.
            ① 基本語法:Limit [ offset ,] row_count ;
            ② 參數釋義:The first argument specifies the offset of the first row to return, and the second specifies the maximum number of rows to return. The offset of the initial row is 0 (not 1)
            ③ 兩參數通常皆爲非負整數常量(在預處理語句以及其餘語句中可能爲其餘值);
            select 結果爲 第offset+1行到第offset+row_cout行的數據;
            當offset爲0時,該參數可省略。
            ④ MySQL 一樣支持PostgreSQL中的分頁語法:
            Limit row_count OFFSET offset
            ⑤ 關於 Limit 查詢的優化細節。須要時可參見:
            手冊8.2.1.19 LIMIT Query Optimization 一節
      • ③ 固然也能夠省略select 字段中的department_name 字段,從而免去departments表與另外兩表的鏈接。只將e表與davg表(經過select 子查詢命名的各部門平均薪資表)內鏈接或者外鏈接。代碼略。

    • (4) 如題:查詢平均工資最低的部門信息。

      • 錯解1: 子查詢所構建的表不識別,失效

        SELECT	d.*, davg.a 
        FROM
        	departments AS d
        	RIGHT JOIN ( SELECT department_id, avg( salary ) a FROM employees WHERE department_id IS NOT NULL GROUP BY department_id ) AS davg ON davg.department_id = d.department_id 
        WHERE
        	davg.a = ( SELECT MIN( davg.a ) FROM davg );
        • 現象:在上述寫法中,除去where 語句,運行正常。添加後顯示:
          Table 'my_employees.davg' doesn't exist
        • ① 經過將where 子查詢語句直接更改成‘TRUE’,發現雖然結果爲空,但並無報錯。說明錯誤之處必定是where子查詢語句,即where子查詢中的davg不能識別
          ② 猜測:子查詢中所調用的只能是當前系統已顯式create並存儲的當前數據庫中的"全局表",各個子查詢之間是獨立的,因此在right join 語句中所建的表davg不能在where 子查詢語句中被識別。
      • 正解2: 可使用 order by + limit 的結合語句來實現查詢效果

        SELECT d.*, davg.a 
        FROM
        	departments AS d
        	RIGHT JOIN ( SELECT department_id, avg( salary ) a FROM employees WHERE department_id IS NOT NULL GROUP BY department_id ) AS davg ON davg.department_id = d.department_id #內鏈接更簡?
        ORDER BY
        	davg.a ASC 
        	LIMIT 1;# 可修改行數肯定是否最低值只有一個。

        該策略一樣適用於: 其餘有關 '最低,最高 '類字眼的查詢 (在此不考慮效率問題)

      • 正解3:複雜嵌套1

        SELECT 	d.* 
        FROM  departments d 
        WHERE 	department_id = (    #此處 '=' 換用 'in' 更好
        	SELECT davg.department_id 
        	FROM  ( SELECT department_id, avg(salary) a 
                    FROM employees 
                    GROUP BY department_id
                   ) AS davg 
        	WHERE a = ( SELECT MIN(該部平均工資)
                        FROM (SELECT avg(salary) AS 該部平均工資 
                              FROM employees 
                              GROUP BY department_id 
                              ) AS davg  
                        # 'AS davg' 必須有,語法要求。儘管前面select min(arg)不加davg也OK
                      )
        )
        # 兩個子查詢字段中的別名‘davg’互不影響,固然若寫成不同更易理解。

        此類嵌套查詢解題思路:
        ①明確各個層次,清晰定義。② 從最內層,最小解題單元開始,逐步完善。③ 耐心,耐心。
        疑問:對於mysql中重複出現的語句有沒有相似命名定義方法。

      • 正解4:複雜嵌套2

        SELECT 	d.* 
        FROM  	departments d 
        WHERE  	department_id = (   #此處 '=' 換用 'in' 更好
                    SELECT department_id 
                    FROM employees e 
                    GROUP BY department_id  
                    HAVING  AVG(salary) = ( 
                                SELECT MIN( a ) 
                                FROM ( SELECT AVG(salary) a 
                                      FROM employees 
                                      GROUP BY department_id
                                     ) AS davg 
                                           )
        						 )

        該解不一樣與正解3的地方在於Having 子句的使用替代了where子查詢嵌套,須要理解的是:

        要真正理解group by 子句的所帶來的效果/意義,以及各子句之間的執行順序:
        ① group by 子句的使用必然與' 需使用聚合類函數的需求'有關(想不出沒有使用聚合類函數的需求仍然使用group by 子句的),但: 並不意味着聚合類函數必定[顯式]出如今select 語句的字段中,它也能夠出如今 having ,where 等子句中(執行順序在它以後的就OK)
        ② 執行順序:from 子句,join ta_name on cond類 子句 , group by 子句 , having 子句 , where 子句,select 子句 ,order by 子句,limit 子句。

      • 解5 存儲過程?視圖?

相關文章
相關標籤/搜索