《MySQL必知必會》19~23章
第十九~第二十三章
第十九章
INSERT 是用來插入(或新增)行到資料庫表的,有以下幾種方式
· 插入完整的行
· 插入行的一部分
· 插入多行
· 插入某些查詢的結果
可針對每個表或每個使用者利用MySQL的安全機制禁止使用INSERT語句
插入完整的行,要求表名和插入新行的值
INSERT INTO customers
VALUES(NULL,'Pep E. LaPew','100 Main Street','Los Angeles','CA','90046','USA',NULL,NULL);
這種格式下,每個列必須提供一個值,次序也應該與定義列的次序相同,沒有值則填NULL(假定該列允許為空值),若某列由MySQL自動增量,也指定為NULL,但這種語法不安全(表的結構以後可能會變動),應儘量避免使用
更安全的方法
INSERT INTO customers(cust_name,cust_address,cust_city,cust_state,cust_zip,cust_country,cust_contact,cust_email)
VALUES('Pep E. LaPew',NULL);
VALUES中的值以之前指定的次序(不需要按照原有表的次序)填寫,這種方法即使表的結構改變也能正確工作,因為cust_id的值是不必要的,所以可以不用出現
若滿足以下條件之一在INSERT語句中可以省略
· 該列定義為允許NULL值(無值或者空值)
· 在表定義中給出預設值,表示如果不給出值,將使用預設值
若資料檢索更重要,可以在INSERT和INTO之間新增關鍵字LOW_PRIORITY降低INSERT的優先順序
插入多行可以使用多條INSERT語句多次插入,或者,只要每條INSERT語句中的列名和次序相同,可以如下形式
INSERT INTO customers(cust_name,cust_country)
VALUES(
'Pep E. LaPew','90046'
'USA'
),(
'M,Martian','42 Galaxy Way','New York','NY','11213','USA'
);
每組值用一對圓括號括起來,用逗號分隔,該方法比使用多條INSERT語句更快
插入檢索出的資料,由一條INSERT語句和SELECT語句組成,比如我們想從一個表中合併客戶列表到customers表中,不需要每次讀取一行再插入(假設有一個名為custnew的表,結構與customers相同,要注意custnew表中的cust_id不能與customers中的重複或者省略這列值在匯入到另一個表時有MySQL生成)
INSERT INTO customers(cust_id,cust_email,cust_name,cust_country)
SELECT cust_id,cust_country
FROM custnew;
若這個表為空,則不插入,這是合法的,也可以在INSERT和SELECT省略cust_id這一列,有MySQL生成值
INSERT和SELECT中的列名不一定要相同,MySQL使用的是列的位置,SELECT中的第一列將用來填充INSERT指定的第一列……這對於從使用不同列名的表匯入資料是非常有用的
在INSERT SELECT中SELECT語句可包含WHERE子句來過濾插入的資料
第二十章
更新(修改)表中的資料可以使用UPDATE,可以更新特定的行或者更新所有行
UPDATE主要由更新的表、列名和新的值、確定更新行的過濾條件三部分組成,注意WHERE子句的重要性
如客戶10005現在有了電子郵件地址,需要更新
UPDATE customers
SET cust_email = '[email protected]'
WHERE cust_id = 10005;
若沒有WHERE子句,將會更新所有行
更新更多的列
UPDATE customers
SET cust_name = 'The Fudds',cust_email = '[email protected]'
WHERE cust_id = 10005;
在UPDATE中也可以使用子查詢
在更新多行時,為避免一行或多行出現錯誤而取消整個操作(取消後之前更新的行恢復到原有值)可以寫作UPDATE IGNORE customers…
為刪除某個列的值,可以將其設為NULL(前提是允許為NULL)
UPDATE customers
SET cust_email = NULL
WHERE cust_id = 10005;
用DELETE刪除特定行或者所有行,同樣不要省略WHERE子句
DELETE FROM customers
WHERE cust_id = 10006;
若不加WHERE子句,將刪除表中每個客戶
DELETE刪除整行而不是列,刪除列使用UPDATE,但DELETE不刪除表本身
刪除所有行用TRUNCATE TABLE語句,速度更快(實際是刪除原來的表並重新生成一個表,而不是逐行刪除)
更新和刪除的原則
· 除非確實打算修改每行,否則必須使用WHERE子句
· 保證每個表都有主鍵,儘可能像WHERE子句那樣使用
· 可以先使用SELECT來測試使用的WHERE是否過濾正確的行,保證正確性
· 使用強制實施引用完整性的資料庫,這樣MySQL將不允許刪除具有與其他表相關聯資料的行
· MySQL沒有撤銷按鈕,小心使用UPDATE和DELETE
第二十一章
可以用CREATE TABLE來建立表,事實上,使用互動式工具時,介面工具生成相應的MySQL語句並執行
建立一個新表需要給出表的名字,表列的名字和定義,或者可以給出更多資訊
CREATE TABLE customers
(
cust_id int NOT NULL AUTO_INCREMENT,cust_name char(50) NOT NULL,cust_address char(50) NULL,cust_city char(50) NULL,cust_state char(5) NULL,cust_zip char(10) NULL,cust_country char(50) NULL,cust_contact char(50) NULL,custy_email char(255) NULL,PRIMARY KEY (cust_id)
) ENGINE=InnoDB;
縮排的大小和各列之間的空格沒有規定
表名緊跟在CREATE TABLE後,表的定義在圓括號之中,每列的定義以列名開始,後跟列的資料型別,表的主鍵可以在建立表時指定
在建立新表時,指定的表名必須不存在,若要防止意外覆蓋已有的表,先手工刪除該表,可以在表名後給出IF NOT EXISIT,檢查表名是否存在並在表名不存在時建立
如果指定了NOT NULL,則在插入時必須有值,NULL為預設設定,如果不指定NOT NULL,則認為指定的是NULL
要注意NULL不是空串,NULL值是沒有值,如果指定’’(兩個單引號,中間沒有字元),這在NOT NULL列中是允許的
如果主鍵使用多個列,則這些列的組合值必須唯一,在建立表時用逗號分隔各列
CREATE TABLE orderitems
(
order_num int NOT NULL,order_item int NOT NULL,prod_id char(10) NOT NULL,quantity int NOT NULL,item_price decimal(8,2)NOT NULL,PRIMARY KEY(order_num,order_item)
) ENGINE=InnoDB;
主鍵也可以在建立表之後定義,只能使用不允許NULL的列
AUTO_INCREMENT告訴MySQL,本列每增加一行時自動增量,這樣給每個行分配一個唯一的cust_id,每個表只允許一個AUTO_INCREMENT列,而且它必須被索引(如:通過使它成為主鍵)
覆蓋AUTO_INCREMENT,可以簡單地在INSERT語句中指定一個值,只要之前沒有出現過即可,該值將代替自動生成的值,後續的增量將開始使用該手工插入的值
SELECT last_insert_id()
該語句返回最後一個AUTO_INCREMENT值
如果插入行時沒有給出值,MySQL允許指定此時使用的預設值
CREATE TABLE orderitems
(
order_num int NOT NULL,order_item char(10) NOT NULL,prod_id char(10) NOT NULL,quantity int NOT NULL DEFAULT 1,item_price decimal(8,PRIMARY KEY (order_num,order_item)
) ENGINE=InnoDB;
在不給出數量的情況下使用數量1,但不允許使用函式作為預設值,只支援常量
MySQL有一個具體管理和處理資料的內部引擎 ,在使用CREATE TABLE或者SELECT等語句時,由該引擎來處理請求,MySQL有多種引擎,具有不同的功能和特性,如果忽略ENGINE=語句,則使用預設引擎(很可能是MyISAM)
· InnoDB是一個可靠的事務處理引擎,不支援全文字搜尋
· MEMORY在功能上等同於MyISAM,但資料儲存在記憶體上(不是磁碟)中,速度很快,適合於臨時表
· MyISAM效能極高,支援全文字搜尋,但不支援事務處理
引擎型別可以混用,如一個表用MyISAM,另一個用InnoDB,但有一個缺陷,外來鍵不能跨引擎,即用一個引擎的表不能引用使用不同引擎的表的外來鍵
可使用ALTER TABLE更新表
給vendors表增加一個名為vend_phone的列,必須明確其資料型別
ALTER TABLE vendors
ADD vend_phone CHAR(20);
刪除剛剛新增的列
ALTER TABLE vendors
DROP COLUMN vend_phone;
還可以定義外來鍵
ALTER TABLE orderitems
ADD CONSTRAINT fk_orderitems_orders
FOREIGN KEY (order_num)
REFERENCES orders (order_num);
ALTER TABLE orderitems
ADD CONSTRAINT fk_orderitems_products
FOREIGN KEY (prod_id)
REFERENCES products (prod_id);
ALTER TABLE orders
ADD CONSTRAINT fk_orders_customers
FOREIGN KEY (cust_id)
REFERENCES customers (cust_id);
ALTER TABLE products
ADD CONSTRAINT fk_products_vendors
FOREIGN KEY (vend_id)
REFERENCES vendors (vend_id);
如果是對單個表進行多個更改,可以使用單條ALTER TABLE語句,每個更改用逗號分隔
複雜的表結構更改一般需要手動刪除過程,應該在使用ALTER TABLE改動表前做好備份,資料庫表的更改不能撤銷
刪除表(整個表而不是其內容),不能撤銷,永久刪除
DROP TABLE customers2;
重命名錶
RENAME TABLE customers2 TO customers;
對多個表重新命名
RENAME TABLE backup_customers TO customers,backup_vendors TO vendors,backup_products TO products;
第二十二章
檢視是虛擬的表,不同的是檢視只包含使用時動態檢索資料的查詢
SELECT cust_name,cust_contact
FROM customers,orders,orderitems
WHERE customers.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num
AND prod_id = 'TNT2';
如果把上述整個查詢包裝成一個名為productcustomers的虛擬表就會方便很多
SELECT cust_name,cust_contact
FROM productcustomers
WHERE prod_id = 'TNT2';
作為檢視,不包含表中的任何列或資料,它包含的是一個SQL查詢
可以用與表基本相同的方式利用它們,可以執行SELECT操作,過濾排序資料,聯結到其他表或者檢視,等等
使用檢視可以簡化操作,在編寫查詢後可以多次重用,它僅使用表的一部分,保護資料
檢視的使用規則和限制
· 命名要唯一,但數目沒有限制
· 檢視可以巢狀,可以從其他檢視中檢索資料的查詢來構造一個檢視
· ORDER BY可以用在檢視中,如果該檢視的SELECT語句中也含有ORDER BY,則原有的ORDER BY會被覆蓋
檢視用CREATE VIEW語句來建立
用SHOW CREATE VIEW viewname; 來檢視建立檢視的語句
用DROP VIEW viewname; 刪除檢視
更新檢視時,可以先用DROP再用CREATE,也可以直接用CREATE OR REPLACE VIEW,如果要更新的檢視不存在,則第2條更新語句會建立一個檢視,若存在,則會替換
檢視最常見的應用之一是隱藏複雜的SQL,這通常會涉及聯結
CREATE VIEW productcustomers AS
SELECT cust_name,prod_id
FROM customers,orderitems
WHERE customers.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num;
這個檢視返回已訂購了任意產品的所有客戶的列表
執行
SELECT * FROM productcustomers
將列出訂購了任意產品的客戶
為了檢索產品TNT2的客戶
SELECT cust_name,cust_contact
FROM productcustomers
WHERE prod_id = 'TNT2';
可以用檢視重新格式化檢索出的資料
CREATE VIEW vendorlocations AS
SELECT Contact(RTrim(vend_name),' (',RTrim(vend_country),')')
AS vend_title
FROM vendors
ORDER BY vend_name;
這條語句使用與以前的SELECT語句相同的查詢建立檢視,為了檢索出以建立所有郵件標籤的資料
SELECT *
FROM vendorlocations;
可以用檢視過濾不想要的資料,比如過濾沒有電子郵件的客戶
CREATE VIEW customeremaillist AS
SELECT cust_id,cust_email
FROM customers
WHERE cust_email IS NOT NULL;
現在可以像使用其他表一樣使用該檢視
SELECT *
FROM customeremaillist;
如果在使用檢視時也有WHERE子句,則和檢視中的WHERE子句會自動組合
檢視對於簡化計算欄位的使用特別有用
CREATE VIEW orderitemsexpanded AS
SELECT order_num,prod_id,quantity,item_price,quantity*item_price AS expanded_price
FROM orderitems;
為檢索訂單20005的詳細內容
SELECT *
FROM orderitemexpanded
WHERE order_num = 20005;
檢視是可更新的,可以使用INSERT、UPDATE和DELETE,更新一個檢視將更新其基表,如果對檢視增加或刪除行,實際是對其基表增加或刪除行,但並非所有檢視都可以更新,如果檢視定義中有如下操作,則不能進行檢視更新
· 分組(GROUP BY和HAVING)
· 聯結
· 子查詢
· 並
· 聚集函式(Min(),Count(),Sum()等)
· DISTINCT
· 匯出(計算)列
第二十三章
儲存過程簡單來說,就是為以後的使用而儲存的一條或多條MySQL語句的集合
使用儲存過程的優點:簡單、安全、高效能
MySQL把執行儲存過程稱為呼叫,使用CALL接受儲存過程的名字以及需要傳遞給它的任意此引數
CALL productpricing(@pricelow,@pricehigh,@priceaverage);
儲存過程可以顯示結果,也可以不顯示結果
建立一個返回產品平均價格的儲存過程
CREATE PROCEDURE productpricing()
BEGIN
SELECT Avg(prod_price) AS priceaverage
FROM products;
END;
如果儲存過程接受引數,可以在()中列出來,BEGIN和END用來限定儲存過程體,這個建立的過程不返回資料,只是為以後使用而建立
在命令列的模式下,由於程式碼裡有兩個分號,會出現錯誤,可以臨時更改分隔符,除了\以外,任何字元都可以用作語句分隔符
DELIMITER //
CREATE PROCEDURE productpricing()
BEGIN
SELECT Avg(prod_price) AS priceaverage
FROM products;
END //
DELIMITER ;
使用這個過程
CALL productpricing();
儲存過程實際上是一種函式
儲存過程建立以後,被儲存在伺服器上供使用,直至被刪除,刪除語句如下
DROP PROCEDURE productpricing;
注意最後沒有()
如果不確定要刪除的過程是否存在,使用DROP PROCEDURE IF EXISTS
一般儲存過程並不顯示結果,而是把結果傳給指定的變數
以下是productpricing的修改版(若先前已有,需要先刪除)
CREATE PROCEDURE productpricing(
OUT pl DECIMAL(8,2),OUT ph DECIMAL(8,OUT pa DECIMAL(8,2)
)
BEGIN
SELECT Min(prod_price)
INTO pl
FROM products;
SELECT Max(prod_price)
INTO ph
FROM products;
SELECT Avg(prod_price)
INTO pa
FROM products;
END;
SELECT語句中,INTO子句和FROM子句順序可調換
此儲存過程接受3個引數,每個引數必須具有指定的型別,這裡使用十進位制,關鍵字OUT指出相應的引數用來從儲存過程中傳出一個值,MySQL還支援IN(傳遞給儲存過程)、INOUT(傳入和傳出),SELECT語句檢索值,並通過INTO儲存到相應變數
呼叫此儲存過程
CALL productpricing(@pricelow,@priceaverage);
為了顯示檢索出的產品的平均價格
SELECT @priceaverage;
獲得三個值
SELECT @pricehigh,@pricelow,@priceaverage;
使用IN和OUT引數,ordertotal接受訂單號並返回該訂單的合計
CREATE PROCEDURE ordertotal(
IN onumber INT,OUT ototal DECIMAL(8,2)
)
BEGIN
SELECT Sum(item_price*quantity)
FROM order_items
WHERE order_num = onumber
INTO ototal;
END;
INTO子句可以跟在SELECT之後
呼叫新的儲存過程
CALL ordertotal(20005,@total);
顯示合計
SELECT @total;
為了得到另一個訂單的合計顯示,再次呼叫儲存過程,重新顯示變數
CALL ordertotal(20009,@total);
SELECT @total;
建立智慧儲存過程
CREATE PROCEDURE ordertotal(
IN onumber INT
IN taxable BOOLEAN
OUT ototal DECIMAL(8,2)
) COMMENT 'Obtain order total,optionally adding tax'
BEGIN
DECLARE total DECIMAL(8,2);
DECLARE taxrate INT DEFAULT 6;
SELECT Sum(item_price*quantity)
FROM orderitems
WHERE order_num = onumber
INTO total;
IF taxable THEN
SELECT total+(total/100*taxrate) INTO total;
END IF;
SELECT total INTO ototal;
END;
IF語句檢查是否需要增加營業稅到區域性變數total,最後用另一個SELECT語句將total儲存到ototal
COMMENT值不是必須的,如果給出將在SHOW PROCEDURE STATUS的結果中顯示
試驗此儲存過程
CALL ordertotal(20005,@total);
SELECT @total;
CALL ordertotal(20005,1,@total);
SELECT @total;
BOOLEAN值非零(包括負數)為真,0為假
IF還支援ELSEIF和ELSE(前者使用THEN子句,後者不使用)
為顯示用來建立一個儲存過程的CREATE語句
SHOW CREATE PROCEDURE ordertotal;
為了獲得包括何時、由誰建立等詳細資訊的儲存過程列表
SHOW PROCEDURE STATUS
上述語句列出所有儲存過程,可以用LIKE過濾
SHOW PROCEDURE STATUS LIKE 'ordertotal';