2021年3月11日 星期四

MySQL新手入門超級手冊學習筆記

  銜接上一篇網誌文章所述,在對的時間離職,在對的時間參加BDSE15課程,最終如願提升資訊技術實力,又認識許多新朋友,在看似完好的BDSE15課程體驗之中,仍發現不足之處,最明顯的就是資料庫知識技術,這一系列的課程無論師資、教材等,皆未達基礎水準,因此趕緊閱讀這本由張益裕編著之《MySQL新手入門超級手冊》,希望能彌補課程之不足。

  其實大約兩年前,我曾經在Codedata閱讀本書作者張益裕這一系列共二十篇的MySQL文章,可能是作者專欄技術文章寫得太好,加上當初自己程度太弱,工作上也不常使用SQL,無法再濃縮整理出學習筆記,因此兩年後的現在,我居然已經快要忘光這些SQL的語法;透過這次機會,以上一篇網誌文章當作基礎,再補充整理出以下應該要學會的技術重點,希望把SQL徹底學好。

補充BDSE15課程不足之處

 

第一章-資料庫概論與MySQL

l   本書範例程式:
http://books.gotop.com.tw/download/AED002931

 

第二章-基礎查詢

l   查詢敘述順序:
SELECT
想要查詢的欄位
FROM
想要查詢的表格
WHERE
查詢條件
GROUP BY
分組設定
HAVING
分組條件
ORDER BY
排序設定
LIMIT
限制設定

 

第三章-運算式與函式

l   連接字串:
SET sql_mode = 'PIPES_AS_CONCAT';
SELECT 'Hello!' || 'MySQL!';

l   函式名稱和左括號之間加入空格也不會出錯:
SET sql_mode = 'IGNORE_SPACE';

l   使用GROUP BY子句的時候可以搭配WITH ROLLUP,計算全部紀錄的數量:
SELECT Continent, COUNT(*) Amount
FROM country
GROUP BY Continent WITH ROLLUP;

l   沒有使用群組函式的欄位,一定要全部出現在GROUP BY子句中:
SET sql_mode = 'ONLY_FULL_GROUP_BY';
--
下例將出錯
SELECT Continent, Region, COUNT(*) Amount
FROM country
GROUP BY Continent;

 

第四章-結合與合併查詢

l   如果兩個表格結合的欄位名稱是一樣的話,就可以使用USING
#
寫法一
SELECT empno, ename, dname
FROM cmdev.emp e, cmdev.dept d
WHERE e.deptno = d.deptno;
#
寫法二
SELECT empno, ename, dname
FROM cmdev.emp e INNER JOIN cmdev.dept d
ON e.deptno = d.deptno;
#
寫法三
SELECT empno, ename, dname
FROM cmdev.emp e INNER JOIN cmdev.dept d
USING (deptno);

l   使用UNION把多個查詢的結果合成一個查詢:
SELECT Region, Name, Population
FROM country
WHERE Region = 'Southeast Asia' AND Population < 2000000
UNION
SELECT Region, Name, Population
FROM country
WHERE Region = 'Eastern Asia' AND Population < 1000000;

 

第五章-資料維護

l   新增敘述:
#
寫法一
INSERT INTO cmdev.dept (deptno, dname)
VALUES (90, 'SHIPPING');
#
寫法二
INSERT INTO cmdev.dept
SET deptno = 90, dname = 'SHIPPING';

l   INSERT後面使用IGNORE,如果新增的紀錄違反主索引鍵規則的話,就不會新增紀錄也不會有錯誤:
INSERT IGNORE INTO cmdev.dept
VALUES (50, 'MIS', DEFAULT);

l   ON DUPLICATE KEY UPDATE可以用來指定在違反重複索引值的規定時要執行的修改工作,此例第一欄與第二欄為主索引鍵,第三欄為counter
INSERT INTO cmdev.travel
VALUES (7900, 'BOSTON', 1)
ON DUPLICATE KEY UPDATE counter = counter + 1;

l   REPLACE敘述在沒有違反索引值的規定時,效果跟INSERT敘述完全一樣,同樣會新增紀錄到表格中,但如果新增的紀錄違反主索引鍵規則的話,INSERT敘述會發生錯誤,REPLACE會執行修改紀錄的動作:
REPLACE INTO cmdev.dept
VALUES (50, 'MIS', DEFAULT);

l   要執行刪除表格中所有的紀錄:
#
寫法一
DELETE FROM cmdev.emp;
#
寫法二(效率好一些)
TRUNCATE TABLE cmdev.emp;

 

第六章-字元集與資料庫

l   查詢支援的字元集資訊:
SHOW CHARACTER SET;

l   查詢支援的Collation資訊:
SHOW COLLATION;

l   設定為自己指定的字元集與Collation
CREATE DATABASE mydb CHARACTER SET utf8 COLLATE utf8_unicode_ci;
ALTER DATABASE mydb CHARACTER SET utf8 COLLATE utf8_unicode_ci;

 

第八章-表格

l   使用其它表格建立一個新表格:
CREATE TABLE cityoftaiwan
SELECT Name, Population
FROM world.city
WHERE CountryCode = 'TWN';

l   建立暫存表格:
CREATE TEMPORARY TABLE IF NOT EXISTS cityoftaiwan LIKE world.city;

l   增加欄位:
ALTER TABLE mytable ADD newcolumn int FIRST;
ALTER TABLE mytable ADD newcolumn int AFTER two;

l   修改欄位:
# CHANGE
可以修改欄位的名稱與定義
ALTER TABLE mytable
CHANGE one changecolumn BIGINT AFTER two;
# MODIFY
只能修改欄位的定義
ALTER TABLE mytable
MODIFY one BIGINT AFTER three;

l   刪除欄位:
ALTER TABLE mytable DROP two;

l   修改表格名稱:
#
寫法一
ALTER TABLE mytable RENAME mynewtable;
#
寫法二
RENAME TABLE mytable TO mynewtable;

 

第九章-索引

l   建立索引:
#
寫法一
CREATE TABLE addressbook (
  id INT UNSIGNED PRIMARY KEY,
  name VARCHAR(20),
  tel VARCHAR(20),
  email VARCHAR(36) UNIQUE KEY
);
#
寫法二
CREATE TABLE addressbook (
  id INT UNSIGNED,
  name VARCHAR(20),
  tel VARCHAR(20),
  email VARCHAR(36),
  PRIMARY KEY (id),
  UNIQUE KEY (email),
  INDEX (name, tel)
);

l   流水號欄位:
#
寫法一
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE;
#
寫法二
id SERIAL;

 

第十一章-Views

l   View元件用來保存一個設定好的查詢敘述:
CREATE OR REPLACE VIEW CountryView (Continent, Region, Code, Code2, Name) AS
SELECT Continent, Region, Code, Code2, Name
FROM country
ORDER BY Continent, Region, Code;

l   View元件的規定與限制:
View
不可以跟Triggers建立連結。
FROM
子句中不可以使用子查詢。
不可以使用TEMPORARY表格。
不可以使用自行定義的變數、ProcedurePrepared statement參數。
在使用查詢敘述提供View元件的欄位時,也要注意欄位名稱重複的問題。
要使用View元件執行新增、修改或刪除的工作,不可以包含計算或函式的欄位,只允許一對一的結合查詢,ALGORITHM亦不可以設定為TEMPTABLE

l   執行新增或修改的時候,又可能會產生一些有問題的資料,可以為View元件加入WITH CHECK OPTION的設定:
CREATE OR REPLACE VIEW cmdev.EmpDept30View AS
SELECT empno, ename, job, manager, hiredate, salary, comm
FROM cmdev.emp
WHERE deptno = 30
--
選項有CASCADELOCAL
WITH CASCADE CHECK OPTION;

l   View元件的演算法預設為UNDEFINED
# MERGE
最後是使用整合以後的敘述
CREATE ALGORITHM = MERGE VIEW cmdev.EmpSalaryView AS
SELECT * FROM cmdev.emp WHERE salary >= 1500;
# TEMPTABLE
先執行View元件儲存的查詢敘述,將結果儲存為一個暫時的表格
CREATE ALGORITHM = TEMPTABLE VIEW cmdev.EmpSalaryView AS
SELECT * FROM cmdev.emp WHERE salary >= 1500;

 

第十二章-Prepared Statements

l   Prepared Statements的規定與限制:
LIMIT
子句指定的數字不可以使用變數。
用戶端離線以後,所設定的使用者變數與Prepared Statements都會被清除。
建立Prepared Statements時,不可以指定它是屬於哪一個資料庫。

l   步驟一,設定使用者變數:
#
寫法一,使用=:=都可以
SET @my_code = 'USA';
#
寫法二,只能使用:=
SELECT @my_code := 'JPN';

l   步驟二,請伺服器準備好這個敘述:
PREPARE my_country FROM
'SELECT Code, Name, GNP FROM country WHERE Code = ?';

l   步驟三,執行這個已經在伺服器準備好的敘述:
EXECUTE my_country USING @my_code;

l   刪除指定的Prepared Statement
#
使用DROP亦可
DEALLOCATE PREPARE my_country;

 

第十三章-Stored Routines - Stored Procedures

l   MySQL資料庫管理系統把Stored ProceduresStored Functions合稱為Stored RoutinesSQL Script是一個包含許多SQL敘述的檔案,可以把想要執行的SQL敘述都集中在一個檔案。

l   範例一,建立無參數的Stored Procedures元件:
DELIMITER $$
CREATE PROCEDURE my_world_count ()
BEGIN
  SELECT COUNT(*) countrycount FROM country;
  SELECT COUNT(*) languagecount FROM countrylanguage;
  SELECT COUNT(*) citycount FROM city;
END $$
DELIMITER ;

l   範例一,呼叫無參數的Stored Procedures元件:
CALL my_world_count();

l   範例一,刪除Stored Procedures元件:
DROP PROCEDURE IF EXISTS my_world_count;

l   範例二,建立有參數的Stored Procedures元件:
-- IN
:輸入、input用的參數
-- OUT
:輸出、output用的參數
-- INOUT
:輸入與輸出、inputoutput用的參數
CREATE PROCEDURE test_param (IN pi_in INT, OUT po_out INT, INOUT pio_inout INT)
BEGIN
  SELECT pi_in, po_out, pio_inout;
  SET pi_in = 99, po_out = 99, pio_inout = 99;
END

l   範例二,呼叫有參數的Stored Procedures元件:
-- OUT
INOUT參數必須指定變數名稱,這是因為OUTINOUT參數在執行完成後會回傳資料,才可以接收
CALL test_param(1, @my_out, @my_inout);
SELECT @my_out, @my_inout;

l   範例三,建立有參數的Stored Procedures元件:
CREATE PROCEDURE country_count2 (IN pi_con VARCHAR(26), OUT po_count INT)
BEGIN
  SELECT COUNT(*) INTO po_count
  FROM country
  WHERE Continent = pi_con;
END

l   範例三,呼叫有參數的Stored Procedures元件:
CALL country_count2('Asia', @my_count);
SELECT @my_count;

 

第十三章-Stored Routines - Stored Functions

l   範例一,建立無參數的Stored Functions元件:
-- RETURNS
回傳型態,RETURN回傳值
DELIMITER $$
CREATE FUNCTION my_date2 ()
RETURNS VARCHAR(64)
BEGIN
  DECLARE d, t, w VARCHAR(24);
  SET d = DATE_FORMAT(CURDATE(), '%Y/%m/%d');
  SET t = TIME_FORMAT(CURDATE(), '%H/%i/%s');
  SET w = DAYNAME(CURDATE());
  RETURN CONCAT(d, ' ', t, ' ', w);
END $$
DELIMITER ;

l   範例一,呼叫無參數的Stored Functions元件:
SELECT my_date2();

l   範例一,刪除Stored Functions元件:
DROP FUNCTION IF EXISTS my_date2;

l   範例二,建立有參數的Stored Functions元件:
CREATE FUNCTION my_summary (p_num INT, p_num2 INT)
RETURNS INT
BEGIN
  RETURN p_num + p_num2;
END;

l   範例二,呼叫有參數的Stored Functions元件:
SELECT my_summary(3, 5);

 

第十四章-Stored Routines的變數與流程

l   判斷IF
CREATE PROCEDURE test_weight3 (IN p_weight INT)
BEGIN
  IF p_weight > 100 THEN SELECT 'You are heavy!';
  ELSEIF p_weight < 100 THEN SELECT 'Good!';
  ELSE SELECT 'Standard!';
  END IF;
END;

l   判斷CASE
CREATE FUNCTION get_season (p_num INT)
RETURNS VARCHAR(7)
BEGIN
  DECLARE season VARCHAR(7);
  CASE p_num
  WHEN 1 THEN SET season = 'Spring';
  WHEN 2 THEN SET season = 'Summer';
  WHEN 3 THEN SET season = 'Autumn';
  WHEN 4 THEN SET season = 'Winter';
  END CASE;
  RETURN season;
END;

l   迴圈WHILE
CREATE FUNCTION summary_while (p_num INT)
RETURNS INT
BEGIN
  DECLARE v_count INT DEFAULT 1;
  DECLARE v_total INT DEFAULT 0;
  WHILE v_count <= p_num DO
    SET v_total = v_total + v_count;
    SET v_count = v_count + 1;
  END WHILE;
  RETURN v_total;
END;

l   迴圈REPEAT
CREATE FUNCTION summary_repeat (p_num INT)
RETURNS INT
BEGIN
  DECLARE v_count INT DEFAULT 1;
  DECLARE v_total INT DEFAULT 0;
  REPEAT
    SET v_total = v_total + v_count;
    SET v_count = v_count + 1;
    UNTIL v_count > p_num
  END REPEAT;
  RETURN v_total;
END;

l   迴圈LOOP
CREATE FUNCTION summary_loop (p_num INT)
RETURNS INT
BEGIN
  DECLARE v_count INT DEFAULT 1;
  DECLARE v_total INT DEFAULT 0;
  my_label: LOOP
    SET v_total = v_total + v_count;
    SET v_count = v_count + 1;
    IF
      v_count > p_num THEN LEAVE my_label;
    END IF;
  END LOOP my_label;
  RETURN v_total;
END;

l   ITERATE可以回到指定標籤範圍的開始位置,不可以使用在BEGIN-END區塊中:
CREATE FUNCTION summary_iterate (p_num INT)
RETURNS INT
BEGIN
  DECLARE v_count INT DEFAULT 0;
  DECLARE v_total INT DEFAULT 0;
  my_label: WHILE v_count <= p_num DO
    SET v_count = v_count + 1;
    IF
      v_count % 2 = 0 THEN ITERATE my_label;
    END IF;
    SET v_total = v_total + v_count;
  END WHILE my_label;
  RETURN v_total;
END;

 

第十五章-Stored Routines進階

l   區塊中宣告的位置:
BEGIN
  DECLARE
變數名稱[,...] 變數型態 [DEFAULT]
  DECLARE ... CONDITION FOR ...
  DECLARE CURSOR
名稱 CURSOR FOR 查詢敘述
  DECLARE ... HANDLER FOR ...
  ...
END;

l   HANDLER用來處理Stored Routines中可能會發生的錯誤:
CREATE PROCEDURE cmdev.test_handler2 (
  p_deptno INT, p_dname VARCHAR(16), p_location VARCHAR(16)
)
BEGIN
  -- EXIT
是離開HANDLER所屬區塊,CONTINUE則為繼續往後執行
  DECLARE EXIT HANDLER FOR SQLSTATE '23000'
  BEGIN
    SELECT 'ERROR!';
  END;
  INSERT INTO cmdev.dept VALUES (p_deptno, p_dname, p_location);
  SELECT 'Success!';
END;

l   CONDITION用來代表某一種問題:
CREATE PROCEDURE cmdev.test_handler5 (
  p_deptno INT, p_dname VARCHAR(16), p_location VARCHAR(16)
)
BEGIN
  DECLARE v_message VARCHAR(64) DEFAULT 'Success!';
  DECLARE c_null CONDITION FOR 1048;
  DECLARE c_dupkey CONDITION FOR 1062;
  DECLARE CONTINUE HANDLER FOR c_null
  BEGIN
    SET v_message = 'Cannot be null!';
  END;
  DECLARE CONTINUE HANDLER FOR c_dupkey
  BEGIN
    SET v_message = 'Duplicate key!';
  END;
  INSERT INTO cmdev.dept VALUES (p_deptno, p_dname, p_location);
  INSERT INTO deptlog (message) VALUES (v_message);
END;

l   CURSOR用來代表一個查詢的結果,然後使用CURSOR依序處理所有紀錄資料:
CREATE PROCEDURE cmdev.test_cursor ()
BEGIN
  DECLARE v_dname VARCHAR(16);
  DECLARE cur_dept CURSOR FOR
    SELECT dname FROM cmdev.dept;
  OPEN cur_dept;
  BEGIN
    DECLARE EXIT HANDLER FOR 1329 BEGIN END;
    LOOP
      FETCH cur_dept INTO v_dname;
    END LOOP;
  END;
  CLOSE cur_dept;
END;

 

第十六章-Triggers

l   Triggers可以把一些在特定狀況要執行的敘述儲存起來,每一個表格最多可以建立六種Trigger,每一種只能有一個:
BEFORE INSERT
BEFORE UPDATEBEFORE DELETE
AFTER INSERT
AFTER UPDATEAFTER DELETE

l   Triggers的規定與限制:
TEMPORARY
表格與VIEW不可以建立Trigger
不可以使用SELECT敘述。
不可以使用CALL敘述。
不可以使用與交易(transactions)相關的敘述,包含START TRANSACTIONCOMMITROLLBACK

l   建立Triggers
DELIMITER $$
DROP TRIGGER IF EXISTS cmdev.emp_before_update$$
CREATE TRIGGER cmdev.emp_before_update BEFORE UPDATE
ON cmdev.emp FOR EACH ROW
BEGIN
  DECLARE v_message VARCHAR(64) DEFAULT 'Before Update: ';
  -- OLD
關鍵字取得修改或刪除前的欄位值,NEW相反
  SET v_message = CONCAT(v_message, OLD.deptno, ' -> ', NEW.deptno);
  INSERT INTO emplog (message) VALUES (v_message);
END $$
DELIMITER ;

 

第十八章-錯誤處理與查詢

l   設定為Non-Strict模式資料庫會試著處理錯誤的資料:
SET SESSION sql_mode = '';

l   設定為Strict模式資料庫不會試著處理錯誤的資料:
SET SESSION sql_mode = 'STRICT_TRANS_TABLES';
SET GLOBAL sql_mode = 'STRICT_ALL_TABLES';

 

第十九章-匯入與匯出資料

l   使用SQL敘述匯出資料:
-- FIELDS ESCAPED BY '$'
$設為跳脫字元
-- LINE STARTING BY '>>>'
>>>設為每行開頭
SELECT * INTO OUTFILE 'C:/Masoloa/data/out/deptcsv.txt'
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\r'
FROM cmdev.dept;

l   使用SQL敘述匯入資料:
--
沒有使用IGNOREREPLACE,索引值重複時,將產生錯誤且馬上停止
-- IGNORE
指定要跳過的資料筆數
-- (
指定儲存的欄位)
-- SET
將處理後的資料儲存到欄位中
LOAD DATA LOCAL INFILE 'C:/Masoloa/data/in/newdeptcsv.txt'
IGNORE
INTO TABLE cmdev.dept
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\r'
IGNORE 1 LINES
(deptno, @v_dname)
SET dname = UPPER(@v_dname);

沒有留言:

張貼留言