1. 程式人生 > >MySQL開發技巧 第一禪

MySQL開發技巧 第一禪

一、SQL的發展歷程

    SQL語言:結構化查詢語言
    簡史:從86年開始制定標準 經歷了SQL89 和 SQL92兩個歷程 直到2015

二、SQL語句的分類

    常見的SQL語句型別
               DDL 資料定義語言    create alt 
               TPL 事物處理語言
    SQL =》    DCL    資料控制語言    grant 
            DML    資料操作語言

三、join從句----連線

    JOIN    =》    INNER        (內連線
                =》    FULL OUTER    (全外連線
                =》    LEFT OUTER    (左外連線
                =》    RIGHT OUTER    (右外連線
                =》    CROSS        (交叉連線


    示例表結構體及資料
        A
        1    唐僧
        2    豬八戒
        3    孫悟空
        4    沙僧
        
        B 
        1    孫悟空
        2    牛魔王
        3    蛟魔王
        4    鵬魔王
        5    獅駝王

    Join的操作型別—————Inner join
        1. 內連線Inner join基於連線謂詞將兩張表的列組合在一起,產生新的結果表,獲取的內容是兩張表的公共的資料
            SELECT * FROM a INNER JOIN b ON a.`user_name` = b.`user_name`;
            查詢結果:3    孫悟空    1    孫悟空                (可以看出能夠查詢到兩張表公共的部分資料)

    Join的操作型別—————Join從句一左外連線—————Left Outer Join
        1. SELECT * FROM a left join b on a.user_name = b.user_name
            SELECT * FROM a left join b on a.user_name = b.user_name where b.user_name is not null
            查詢結果:     1    唐僧        
                                    2    豬八戒        
                                    3    孫悟空    1    孫悟空
                                    4    沙僧        
                                                        (A LEFT OUTER JOIN B表示把A表的記錄都顯示出來,把B表符合條件的結果集顯示出來,不符合條件的用NULL表示。)

    Join的操作型別——————Join從句一右外連線—————Right Outer Join
        1. SELECT * FROM b right join a on b.user_name = a.user_name where a.user_name is not null
            查詢結果:
                                    1    唐僧
                                    2    豬八戒
                                    1    孫悟空    3    孫悟空
                                    4    沙僧

                                                        (A RIGHT OUTER JOIN B表示把B表的記錄都顯示出來,把A表符合條件的結果集顯示出來,不符合條件的用NULL表示。)

    Join的操作型別——————Join從句一全連線—————FULL Join
        1.     SELECT * FROM a full join b on a.user_name = b.user_name 執行會報錯 大多不支援 需要用集合的方式去查詢
            SELECT * FROM a left JOIN b on a.user_name = b.user_name UNION ALL SELECT * FROM b LEFT JOIN a on b.user_name = a.user_name;
            查詢結果
                1    唐僧        
                2    豬八戒        
                3    孫悟空    1    孫悟空
                4    沙僧        
                1    孫悟空    3    孫悟空
                2    牛魔王        
                3    蛟魔王        
                4    鵬魔王        
                5    獅駝王        

                                                        (A FULL OUTER JOIN B 表示把A表和B表的記錄都顯示出來,不符合條件的用NULL表示)

    Join的操作型別——————Cross Join—————交叉連線
        簡介:交叉連線(Cross Join),又稱笛卡爾積(cartesian join) 或叉乘(Product),如果A和B是兩個集合,他們的交叉連線就記為A * B
        1. SELECT * FROM a CROSS JOIN b
            查詢結果及特點
                1    唐僧        1    孫悟空
                2    豬八戒    1    孫悟空
                3    孫悟空    1    孫悟空
                4    沙僧        1    孫悟空
                1    唐僧        2    牛魔王
                2    豬八戒    2    牛魔王
                3    孫悟空    2    牛魔王
                4    沙僧        2    牛魔王
                1    唐僧        3    蛟魔王
                2    豬八戒    3    蛟魔王
                3    孫悟空    3    蛟魔王
                4    沙僧        3    蛟魔王
                1    唐僧        4    鵬魔王
                2    豬八戒    4    鵬魔王
                3    孫悟空    4    鵬魔王
                4    沙僧        4    鵬魔王
                1    唐僧        5    獅駝王
                2    豬八戒    5    獅駝王
                3    孫悟空    5    獅駝王
                4    沙僧        5    獅駝王 
                                                        (笛卡爾積連線結果)

四、與join相關的開發技巧

    如何更新使用過濾條件中包括自身的表?(子查詢 帶條件)
    這條SQL的條件是 將都存在與兩張表中的某個欄位進行比較 只有是相同的欄位的資料相同 才進行數值的修改
    update a join (select b.`user_name` from a join b on a.user_name = b.user_name) b on a.user_name = b.user_name set a.over='齊天大聖';
    解釋 update a join b on a.user_name = b.user_name set a.over='鬥戰聖佛';

五、使用join優化子查詢

   寫在前面:子查詢是比較低效的,因為它會將每條記錄都進行匹配(如果資料量大時 會非常的耗時 可以用join進行優化)
    join 優化前的SQL語句顯示
    select a.user_name,a.over,(select over from b where a.user_name = b.user_name) as over2 from a;
        查詢到的資料
            +-----------+-----------------+--------+
            | user_name | over                      | over2    |
            +-----------+-----------------+--------+
            | 唐僧            | 旃檀功德佛          | NULL    |
            | 豬八戒        | 淨壇使者              | NULL    |
            | 孫悟空        | 齊天大聖              | 大嬸      |
            | 沙僧            | 金身羅漢              | NULL    |
            +-----------+-----------------+--------+
            4 rows in set (0.00 sec)

    join 優化後的SQL語句顯示
    select a.user_name,a.over,b.over AS over2 from a left join b ON a.user_name = b.user_name;
    mysql> select a.user_name,a.over as over3,b.user_name,b.over as over2 from a left join b on a.user_name = b.user_name where b.over is not null;
            +-----------+-----------------+--------+
            | user_name | over                      | over2    |
            +-----------+-----------------+--------+
            | 唐僧            | 旃檀功德佛          | NULL     |
            | 豬八戒        | 淨壇使者              | NULL     |
            | 孫悟空        | 齊天大聖              | 大嬸       |
            | 沙僧            | 金身羅漢              | NULL     |
            +-----------+-----------------+--------+
            4 rows in set (0.00 sec)

六、使用join優化聚合子查詢

    未優化之前的語句
    mysql> select a.user_name,c.timestr,c.kills
    -> from a join c
    -> on a.id = c.user_id
    -> where c.kills = (select max(c.kills) from c where a.id = c.user_id);
    +-----------+------------+-------+
    | user_name | timestr         | kills      |
    +-----------+------------+-------+
    | 沙僧            | 2013-01-10 |          3 |
    | 孫悟空        | 2013-01-11  |        20 |
    | 豬八戒        | 2013-01-07 |         17 |
    +-----------+------------+-------+
    3 rows in set (0.00 sec)
                                            

    優化之後的語句
    mysql> select a.user_name,c.timestr,c.kills from a join c on a.id = c.user_id group by a.user_name,c.timestr,c.kills having c.kills = max(c.kills);
    +-----------+------------+-------+
    | user_name | timestr         |      kills |
    +-----------+------------+-------+
    | 沙僧            | 2013-01-10 |          3 |
    | 孫悟空        | 2013-01-11 |         20 |
    | 豬八戒        | 2013-01-07 |         17 |
    +-----------+------------+-------+
                                                    ------ 以上均顯示 關係中每個最大的值


七、如何實現分組選擇?

   什麼是分組選擇?分組選擇就是將資料進行分類 在分類中提取分類中包含的資料
    mysql> select a.user_name,c.timestr,c.kills from a join c on a.id = c.user_id order by c.timestr desc limit 2;
    +-----------+------------+-------+
    | user_name | timestr        | kills      |
    +-----------+------------+-------+
    | 豬八戒        | 2013-01-12 |        10 |
    | 豬八戒        | 2013-01-11 |           5 |
    +-----------+------------+-------+

    mysql> select a.user_name,c.timestr,c.kills from a join c on a.id = c.user_id where kills = (select max(c.kills) from a where a.id = c.user_id) order by c.kills desc;
    +-----------+-------------+-------+
    | user_name | timestr           | kills      |
    +-----------+-------------+-------+
    | 孫悟空        | 2013-01-11   |    20     |
    | 豬八戒        | 2013-01-07  |    17      |
    | 豬八戒        | 2013-01-05  |    12     |
    | 豬八戒        | 2013-01-10   |    10     |
    | 豬八戒        | 2013-01-12   |    10     |
    | 豬八戒        | 2013-01-11    |     5     |
    | 沙僧            | 2013-01-10   |     3     |
    | 豬八戒        | 2013-01-01   |     2     |
    | 沙僧            | 2013-01-06  |     1      |
    +-----------+-------------+-------+
    9 rows in set (0.00 sec)
                                                        ------ 以上是查詢出 最早日期的兩條殺怪數量

    以上查詢的缺陷是
        問題:    1. 如果分類或是使用者很多的情況下則需要多次執行同一查詢
                2. 增加應用程式同資料庫的互動次數
                3. 增加了資料庫執行查詢的次數,不符合批處理的原則
                4. 增加了網路流量
        優化
        mysql> select a.user_name,c.timestr,c.kills from (select c.user_id,c.timestr,c.kills,(select count(*) from c join a where c.user_id = a.id and c.kills <= c.kills) as cnt from c group by c.user_id,c.timestr,c.kills) c join a on a.id = c.user_id order by c.kills desc limit 2;

        拆分理解:select a.user_name,c.timestr,c.kills from c join a on a.id = c.user_id;
        拆分理解:select c.user_id,c.timestr,c.kills,(select count(*) from c join a where c.user_id = a.id and c.kills <= c.kills) as cnt from c group by c.user_id,c.timestr,c.kills
        +-----------+------------+-------+
        | user_name | timestr    | kills |
        +-----------+------------+-------+
        | 孫悟空    | 2013-01-11 |    20 |
        | 豬八戒    | 2013-01-07 |    17 |
        +-----------+------------+-------+
        2 rows in set (0.01 sec)