Mysql 必知必會(huì)
查詢
-
檢索多個(gè)列
SELECT prod_id, prod_name, prod_price FROM Products;注意,多個(gè)字段名稱之間要用
,分割,最后一個(gè)字段不需要, -
關(guān)于通配符 * 號(hào)
一般而言,除非你確實(shí)需要表中的每一列,否則最好別使用 * 通配符。雖然使用通配符能讓你自己省事,不用明確列出所需列,但檢索不需 要的列通常會(huì)降低檢索和應(yīng)用程序的性能。
-
DISTINCT 關(guān)鍵字
SELECT DISTINCT vend_id FROM Products;對(duì)取到的結(jié)果里面
vend_id去重SELECT DISTINCT vend_id, prod_name FROM Products;去重,告訴DBMS只返回不同值,如果使用 DISTINCT 關(guān)鍵字,它必須直接放在列名的前面。
DISTINCT 關(guān)鍵字作用于所有的列,不僅僅是跟在其后的那一列。例如,你指定SELECT DISTINCT vend_id, prod_price,除非指定的兩列完全相同,否則所有的行都會(huì)被檢索出來(lái)。 -
LIMIT
SELECT prod_name FROM Products LIMIT 5;只取5行數(shù)據(jù)
SELECT prod_name FROM Products LIMIT 5 OFFSET 1;取5行數(shù)據(jù),從第一行開(kāi)始(注意:數(shù)據(jù)庫(kù)是從0開(kāi)始計(jì)數(shù)行的)
SELECT prod_name FROM Products LIMIT 5, 1;前一個(gè)數(shù)字代表從第幾行開(kāi)始,后一個(gè)數(shù)字代表取幾個(gè)數(shù)據(jù)
-
注釋
一共有三種類(lèi)型
/** 注釋 */ -- 注釋 # 注釋 -
ORDER BY
- 按單個(gè)列排序
- 按多個(gè)列排序
- 按照列位置排序
ORDER BY子句的位置
在指定一條ORDER BY子句時(shí),應(yīng)該保證它是SELECT語(yǔ)句中最后一條子句。如果它不是最后的子句,將會(huì)出現(xiàn)錯(cuò)誤消息。通過(guò)非選擇列進(jìn)行排序
通常,ORDER BY子句中使用的列 SELECT 選擇的列。但是,實(shí)際上并不一定要這樣,用其他列也是完全合法的SELECT prod_id, prod_price, prod_name FROM Products ORDER BY prod_price, prod_name;先按照 prod_price 進(jìn)行排序,當(dāng)價(jià)格相同的情況下,使用 prod_name 進(jìn)行排序
SELECT prod_id, prod_price, prod_name FROM Products ORDER BY 2, 3;ORDER BY 2表示按SELECT清單中的第二個(gè)列prod_name進(jìn)行排序。ORDER BY 2,3表示先按prod_price,再按prod_name進(jìn)行排序。(不建議使用這種方式,可讀性比較差)
-
DESC 和 ASC
SELECT prod_id, prod_price, prod_name FROM Products ORDER BY prod_price DESC, prod_name;DESC 降序,跟在字段名稱后面
DESC是 DESCENDING 的縮寫(xiě),這兩個(gè)關(guān)鍵字都可以使用。與DESC相對(duì)的是ASC(或ASCENDING),在升序排序時(shí)可以指定它。但實(shí)際 上,ASC沒(méi)有多大用處,因?yàn)樯蚴悄J(rèn)的。
Q:在對(duì)文本性數(shù)據(jù)進(jìn)行排序時(shí),A與a相同嗎?a位于B之前,還是Z之后 ?
A:這些問(wèn)題不是理論問(wèn)題,其答案取決于數(shù)據(jù)庫(kù)的設(shè)置方式。
在字典(dictionary)排序順序中,A被視為與a相同,這是大多數(shù)數(shù)據(jù)庫(kù)管理系統(tǒng)的默認(rèn)行為。但是,許多DBMS允許數(shù)據(jù)庫(kù)管理員在需要時(shí)改變這種行為(如果你的數(shù)據(jù)庫(kù)包含大量外語(yǔ)字符,可能必須這樣做)。
-
WHERE 字句
數(shù)據(jù)庫(kù)表一般包含大量的數(shù)據(jù),很少需要檢索表中的所有行。通常只會(huì)根據(jù)特定操作或報(bào)告的需要提取表數(shù)據(jù)的子集。只檢索所需數(shù)據(jù)需要指定搜索條件(search criteria),搜索條件也稱為過(guò)濾條件(filter condition)。提示:
SQL過(guò)濾與應(yīng)用過(guò)濾 數(shù)據(jù)也可以在應(yīng)用層過(guò)濾。為此,SQL的SELECT語(yǔ)句為客戶端應(yīng)用檢索出超過(guò)實(shí)際所需的數(shù)據(jù),然后客戶端代碼對(duì)返回?cái)?shù)據(jù)進(jìn)行循環(huán),提取出需要的行。
通常,這種做法極其不妥。優(yōu)化數(shù)據(jù)庫(kù)后可以更快速有效地對(duì)數(shù)據(jù)進(jìn)行過(guò)濾。而讓客戶端應(yīng)用(或開(kāi)發(fā)語(yǔ)言)處理數(shù)據(jù)庫(kù)的工作將會(huì)極大地 影響應(yīng)用的性能,并且使所創(chuàng)建的應(yīng)用完全不具備可伸縮性。此外,如果在客戶端過(guò)濾數(shù)據(jù),服務(wù)器不得不通過(guò)網(wǎng)絡(luò)發(fā)送多余的數(shù)據(jù),這將導(dǎo)致網(wǎng)絡(luò)帶寬的浪費(fèi)。SELECT prod_name, vend_id, prod_price FROM Products WHERE vend_id != 'DLL01'提示: 何時(shí)使用引號(hào) ? 如果仔細(xì)觀察上述 WHERE 子句中的條件,會(huì)看到有的值括在單引號(hào)內(nèi),而有的值未括起來(lái)。單引號(hào)用來(lái)限定字符串。如果將值與字符串類(lèi)型的列進(jìn)行比較,就需要限定引號(hào)。用來(lái)與數(shù)值列進(jìn)行比較的值不用引號(hào)。
SELECT prod_name, prod_price FROM Products WHERE prod_price BETWEEN 5 AND 10;從這個(gè)例子可以看到,在使用BETWEEN時(shí),必須指定兩個(gè)值——所需范圍的低端值和高端值。這兩個(gè)值必須用AND關(guān)鍵字分隔。BETWEEN匹配范圍 中所有的值,包括指定的開(kāi)始值和結(jié)束值。
-
NULL
在創(chuàng)建表時(shí),表設(shè)計(jì)人員可以指定其中的列能否不包含值。在一個(gè)列不包含值時(shí),稱其包含空值NULL。
NULL
無(wú)值(no value),它與字段包含0、空字符串或僅僅包含空格不同。SELECT cust_name FROM Customers WHERE cust_email IS NULL;確定值是否為NULL,不能簡(jiǎn)單地檢查是否= NULL。SELECT語(yǔ)句有一個(gè)特殊的WHERE子句,可用來(lái)檢查具有NULL值的列。這個(gè)WHERE子句就是IS NULL子句。
-
AND
SELECT prod_id, prod_price, prod_name FROM Products WHERE vend_id = 'DLL01' AND prod_price < 5;此SQL語(yǔ)句檢索由供應(yīng)商DLL01制造且價(jià)格小于等于4美元的所有產(chǎn)品的名稱和價(jià)格。這條SELECT語(yǔ)句中的WHERE子句包含兩個(gè)條件,用AND關(guān)鍵 字聯(lián)結(jié)在一起。AND指示DBMS只返回滿足所有給定條件的行。如果某個(gè)產(chǎn)品由供應(yīng)商DLL01制造,但價(jià)格高于4美元,則不檢索它。類(lèi)似地,如 果產(chǎn)品價(jià)格小于4美元,但不是由指定供應(yīng)商制造的也不被檢索
-
OR
符合任何一個(gè)條件的結(jié)果都會(huì)被檢索出來(lái)
SELECT prod_name, vend_id, prod_price FROM Products WHERE vend_id = 'DLL01' OR vend_id = 'BRS01'把廠商是 DLL01 或者是 BRS01 的商品檢索出來(lái)
-
求值順序
SELECT prod_name, vend_id, prod_price FROM Products WHERE (vend_id = 'DLL01' OR vend_id = 'BRS01') AND prod_price > 10;當(dāng) AND 和 OR 搭配使用的時(shí)候,需要注意他們的優(yōu)先級(jí),AND 的優(yōu)先級(jí)要比 OR 的高,所以有時(shí)候需要用 () 來(lái)約束查詢子條件
假如需要列出價(jià)格為10美元及以上,且由 DLL01 或 BRS01 制造的所有產(chǎn)品,需要用到下面的 SQL -
IN
SELECT prod_name, vend_id, prod_price FROM Products WHERE vend_id IN ('DLL01', 'BRS01')SELECT prod_name, vend_id, prod_price FROM Products WHERE vend_id = 'DLL01' OR vend_id = 'BRS01'上面兩個(gè) SQL 是一個(gè)意思
為什么要使用IN操作符?其優(yōu)點(diǎn)為:
- 在有很多合法選項(xiàng)時(shí),IN操作符的語(yǔ)法更清楚,更直觀。
- 在與其他AND和OR操作符組合使用IN時(shí),求值順序更容易管理。
- IN操作符一般比一組OR操作符執(zhí)行得更快(在上面這個(gè)合法選項(xiàng)很少的例子中,你看不出性能差異)。
- IN的最大優(yōu)點(diǎn)是可以包含其他SELECT語(yǔ)句,能夠更動(dòng)態(tài)地建立WHERE子句。第11課會(huì)對(duì)此進(jìn)行詳細(xì)介紹。
-
NOT
SELECT prod_name, vend_id, prod_price FROM Products WHERE NOT vend_id = 'DLL01'WHERE子句中的NOT操作符有且只有一個(gè)功能,那就是否定其后所跟的任何條件。因?yàn)镹OT從不單獨(dú)使用(它總是與其他操作符一起使用),所以
它的語(yǔ)法與其他操作符有所不同。NOT關(guān)鍵字可以用在要過(guò)濾的列前,而不僅是在其后。為什么使用NOT?
對(duì)于這里的這種簡(jiǎn)單的WHERE子句,使用NOT確實(shí)沒(méi)有什么優(yōu)勢(shì)。但在更復(fù)雜的子句中,NOT是非常有用的。例如,在與IN操作 符聯(lián)合使用時(shí),NOT可以非常簡(jiǎn)單地找出與條件列表不匹配的行。 -
通配符
-
%
SELECT prod_name, prod_price FROM Products WHERE prod_name LIKE 'Fish%';在搜索串中,%表示任何字符出現(xiàn)任意次數(shù)
-
_
SELECT prod_name, prod_price FROM Products WHERE prod_name LIKE '__ inch teddy bear';下劃線的用途與%一樣,但它只匹配單個(gè)字符,而不是多個(gè)字符
注意:
不要過(guò)度使用通配符。如果其他操作符能達(dá)到相同的目的,應(yīng)該使用其他操作符。
在確實(shí)需要使用通配符時(shí),也盡量不要把它們用在搜索模式的開(kāi)始處。把通配符置于開(kāi)始處,搜索起來(lái)是最慢的。 仔細(xì)注意通配符的位置。如果放錯(cuò)地方,可能不會(huì)返回想要的數(shù)據(jù)。
-
-
算數(shù)計(jì)算
SELECT prod_id, quantity, item_price, quantity * item_price AS expanded_price FROM OrderItems WHERE order_num = 20008可以在查詢的字段里面執(zhí)行 加減乘除 運(yùn)算
-
文本函數(shù)
-
upper 將字符串轉(zhuǎn)換為大寫(xiě)
SELECT vend_name, upper(vend_name) AS vend_name_upper FROM Vendors; LTRIM() 去掉字符串左邊的空格
RTRIM() 去掉字符串右邊的空格
-
CONCAT() 連接字符串
SELECT concat(vend_name, '(', vend_country, ')') FROM Vendors;可以把搜索的數(shù)據(jù)進(jìn)行一個(gè)格式化,省了一步在java中的操作
-
-
時(shí)間函數(shù)
例如數(shù)據(jù)值為:2012-05-01 00:00:00 ,下面每個(gè)函數(shù)取時(shí)間里面不同的年月日
year() month() day()SELECT order_num, cust_id FROM Orders WHERE year(order_date) = 2012 -
數(shù)值處理函數(shù)
ABS() 返回一個(gè)數(shù)的絕對(duì)值
SQRT() 返回一個(gè)數(shù)的平方根
-
統(tǒng)計(jì)函數(shù)
- AVG() 返回某列的平均值
SELECT avg(prod_price) AS avg_price FROM Products WHERE vend_id = 'DLL01'注意:
AVG() 只能用來(lái)確定特定數(shù)值列的平均值,而且列名必須作為函數(shù)參數(shù)給出。為了獲得多個(gè)列的平均值,必須使用多個(gè)AVG()函數(shù)。
-
AVG() 函數(shù)忽略列值為NULL的行
?
- COUNT() 返回某列的行數(shù)
- 使用COUNT(*)對(duì)表中行的數(shù)目進(jìn)行計(jì)數(shù),不管表列中包含的是空值(NULL)還是非空值。
- 使用COUNT(column)對(duì)特定列中具有值的行進(jìn)行計(jì)數(shù),忽略NULL值。
SELECT count(*) FROM Customers; SELECT count(cust_email) FROM Customers;?
- max() / min()
MAX()一般用來(lái)找出最大的數(shù)值或日期值,MIN() 相反
SELECT max(prod_price) AS max_price FROM Products;- sum()
SELECT sum(quantity * OrderItems.item_price) AS total_price FROM OrderItems WHERE order_num = '20008';- DISTINCT 在函數(shù)中的作用
SELECT avg(DISTINCT prod_price) AS avg_distinct FROM Products;這里先對(duì) prod_price 進(jìn)行一遍去重,然后再計(jì)算平均值
- 組合函數(shù)使用
SELECT count(*) AS num_items, max(prod_price) AS price_min, AVG(prod_price) AS price_avg FROM Products; -
GROUP BY
-
創(chuàng)建分組
SELECT vend_id, count(*) AS num_prod FROM Products GROUP BY vend_id; -
過(guò)濾分組
SELECT vend_id, count(*) AS num_prod FROM Products WHERE prod_price > 4 GROUP BY vend_id HAVING count(*) > 2;HAVING 對(duì)分組后的數(shù)據(jù)進(jìn)行過(guò)濾
注意:
- GROUP BY子句可以包含任意數(shù)目的列,因而可以對(duì)分組進(jìn)行嵌套,更細(xì)致地進(jìn)行數(shù)據(jù)分組。
- 如果在GROUP BY子句中嵌套了分組,數(shù)據(jù)將在最后指定的分組上進(jìn)行匯總。換句話說(shuō),在建立分組時(shí),指定的所有列都一起計(jì)算(所以不能從個(gè)別的列取回?cái)?shù)據(jù))。
- GROUP BY子句中列出的每一列都必須是檢索列或有效的表達(dá)式(但不能是聚集函數(shù))。如果在SELECT中使用表達(dá)式,則必須在GROUP BY子 句中指定相同的表達(dá)式。不能使用別名。
- 大多數(shù)SQL實(shí)現(xiàn)不允許GROUP BY列帶有長(zhǎng)度可變的數(shù)據(jù)類(lèi)型(如文本或備注型字段)。 除聚集計(jì)算語(yǔ)句外,SELECT語(yǔ)句中的每一列都必須在GROUP BY子句中給出。 如果分組列中包含具有NULL值的行,則NULL將作為一個(gè)分組返回。如果列中有多行NULL值,它們將分為一組。
- GROUP BY子句必須出現(xiàn)在WHERE子句之后,ORDER BY子句之前。
-
-
子查詢
利用子查詢進(jìn)行過(guò)濾:
Q:列出訂購(gòu)物品RGAN01的所有顧客SELECT cust_name, cust_contact FROM Customers WHERE cust_id IN (SELECT cust_id FROM Orders WHERE order_num IN (SELECT order_num FROM OrderItems WHERE prod_id = 'RGAN01'));警告:
只能單列作為子查詢的SELECT語(yǔ)句,企圖檢索多個(gè)列將返回錯(cuò)誤
性能:
在WHERE子句中使用子查詢能夠編寫(xiě)出功能很強(qiáng)且很靈活的SQL語(yǔ)句。對(duì)于能嵌套的子查詢的數(shù)目沒(méi)有限制,不過(guò)在實(shí)際使用時(shí)由于性能 的限制,不能嵌套太多的子查詢。 -
連接
SELECT vend_name, prod_name, prod_price FROM Vendors, Products WHERE Vendors.vend_id = Products.vend_id;返回笛卡兒積的聯(lián)結(jié),也稱叉聯(lián)結(jié)(cross join)
使用 WHERE 條件就是對(duì)兩個(gè)表形成的笛卡爾積進(jìn)行一次篩選
笛卡兒積(cartesian product)
由沒(méi)有聯(lián)結(jié)條件的表關(guān)系返回的結(jié)果為笛卡兒積。檢索出的行的數(shù)目將是第一個(gè)表中的行數(shù)乘以第二個(gè)表中的行數(shù)。?
內(nèi)連接
SELECT vend_name, prod_name, prod_price FROM Vendors INNER JOIN Products ON Vendors.vend_id = Products.vend_id;下面兩種SQL執(zhí)行出來(lái)的結(jié)果是一樣的
SELECT cust_name, cust_contact FROM Customers WHERE cust_id IN (SELECT cust_id FROM Orders WHERE order_num IN (SELECT order_num FROM OrderItems WHERE prod_id = 'RGAN01'));SELECT cust_name, cust_contact FROM Customers, Orders, OrderItems WHERE Customers.cust_id = Orders.cust_id AND Orders.order_num = OrderItems.order_num AND prod_id = 'RGAN01';?
自連接
Q:給與Jim Jones同一公司的所有顧客發(fā)送一封信件
SELECT c1.cust_name, c1.cust_contact, c1.cust_email FROM Customers AS c1, Customers AS c2 WHERE c1.cust_name = c2.cust_name AND c2.cust_contact = 'Jim Jones';自聯(lián)結(jié)通常作為外部語(yǔ)句,用來(lái)替代從相同表中檢索數(shù)據(jù)的使用子查詢語(yǔ)句。雖然最終的結(jié)果是相同的,但許多DBMS處理聯(lián)結(jié)遠(yuǎn)比處理子 查詢快得多。應(yīng)該試一下兩種方法,以確定哪一種的性能更好。
?
外鏈接
SELECT Customers.cust_id, Orders.order_num FROM Customers LEFT JOIN Orders ON Customers.cust_id = Orders.cust_id上面的例子使用LEFT OUTER JOIN從FROM子句左邊的表(Customers表) 中選擇所有行。為了從右邊的表中選擇所有行,需要使用RIGHT OUTER JOIN
Q:統(tǒng)計(jì)每個(gè)客戶的訂單數(shù)
SELECT Customers.cust_id, count(order_num) AS order_num FROM Customers LEFT JOIN Orders ON Customers.cust_id = Orders.cust_id GROUP BY Orders.cust_id; -
插入數(shù)據(jù)
INSERT INTO Customers (cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country) VALUES ('1000000006', 'Toy Land', '123 Any Street', 'New York', 'NY', '11111', 'USA');注意:要寫(xiě)列名,不要一套數(shù)據(jù)庫(kù)的表字段結(jié)構(gòu)
INSERT SELECT
可以把查詢到的數(shù)據(jù),一次性的插入,了解即可提示:
INSERT SELECT 中的列名 為簡(jiǎn)單起見(jiàn),這個(gè)例子在INSERT和SELECT語(yǔ)句中使用了相同的列名。但是,不一定要求列名匹配。事實(shí)上,DBMS一點(diǎn)兒也不關(guān)心SELECT返 回的列名。它使用的是列的位置,因此SELECT中的第一列(不管其列名)將用來(lái)填充表列中指定的第一列,第二列將用來(lái)填充表列中指定的 第二列,如此等等。 -
復(fù)制表
CREATE TABLE CustNew AS SELECT * FROM Customers;創(chuàng)建一個(gè)表 CustNew ,把 Customers 內(nèi)的數(shù)據(jù)復(fù)制一份過(guò)去
任何SELECT選項(xiàng)和子句都可以使用,包括WHERE和GROUP BY; 可利用聯(lián)結(jié)從多個(gè)表插入數(shù)據(jù); 不管從多少個(gè)表中檢索數(shù)據(jù),數(shù)據(jù)都只能插入到一個(gè)表中。
提示:進(jìn)行表的復(fù)制
復(fù)制表數(shù)據(jù)是試驗(yàn)新SQL語(yǔ)句前進(jìn)行表復(fù)制的很好工具。先進(jìn)行復(fù)制,可在復(fù)制的數(shù)據(jù)上測(cè)試SQL代碼,而不會(huì)影響實(shí)際的數(shù)據(jù)。 -
更新表
Q: 修改id是 1000000001 的顧客郵箱
UPDATE Customers SET cust_email = 'zz@qq.com' WHERE cust_id = '1000000001';UPDATE Customers SET cust_email = 'zz@qq.com', cust_name = 'zl' WHERE cust_id = '1000000001'; -
刪除表數(shù)據(jù)
DELETE FROM Customers WHERE cust_id = '1000000006';重要:
除非確實(shí)打算更新和刪除每一行,否則絕對(duì)不要使用不帶WHERE子句的UPDATE或DELETE語(yǔ)句。
保證每個(gè)表都有主鍵(如果忘記這個(gè)內(nèi)容,請(qǐng)參閱第12課),盡可能像WHERE子句那樣使用它(可以指定各主鍵、多個(gè)值或值的范圍)。
在UPDATE或DELETE語(yǔ)句使用WHERE子句前,應(yīng)該先用SELECT進(jìn)行測(cè)試,保證它過(guò)濾的是正確的記錄,以防編寫(xiě)的WHERE子句不正確。
使用強(qiáng)制實(shí)施引用完整性的數(shù)據(jù)庫(kù)(關(guān)于這個(gè)內(nèi)容,請(qǐng)參閱第12課),這樣DBMS將不允許刪除其數(shù)據(jù)與其他表相關(guān)聯(lián)的行。
有的DBMS允許數(shù)據(jù)庫(kù)管理員施加約束,防止執(zhí)行不帶WHERE子句的UPDATE或DELETE語(yǔ)句。如果所采用的DBMS支持這個(gè)特性,應(yīng)該使用它。 -
視圖
CREATE VIEW CustomProducts AS SELECT cust_name, cust_contact, prod_id FROM Customers, Orders, OrderItems WHERE Customers.cust_id = Orders.cust_id AND OrderItems.order_num = Orders.order_num;視圖為虛擬的表。它們包含的不是數(shù)據(jù)而是根據(jù)需要檢索數(shù)據(jù)的查詢。視圖提供了一種封裝SELECT語(yǔ)句的層次,可用來(lái)簡(jiǎn)化數(shù)據(jù)處理,重新格式化或保護(hù)基礎(chǔ)數(shù)據(jù)。
?
?
?
?