1. 程式人生 > 其它 >MySQL必知必會筆記——查詢的進階知識

MySQL必知必會筆記——查詢的進階知識

查詢進階知識

第十五章 聯結表

SQL最強大的功能之一就是能在資料檢索查詢的執行中聯結(join)表。聯結是利用SQL的SELECT能執行的最重要的操作。

例如:兩個表,一個儲存供應商資訊,另一個儲存產品資訊。vendors表包含所有供應商資訊,每個供應商佔一行,每個供應商應具有唯一的標識,稱為主鍵(primary key)。products表只儲存產品資訊,除了儲存供應商ID之外不儲存其他的供應商資訊。vendors表的主鍵又叫products的外來鍵,它將vendors表與products表關聯,利用供應商ID能從vendors表中找出相應供應商的詳細資訊。

外來鍵:外來鍵為某個表中的一列,它包含另一個表的主鍵值,定義了兩個表之間的關係。

# 建立聯結,兩個表用WHERE子句聯結
SELECT  vend_name, prod_name, prod_price
FROM vendors, products
WHERE vendors.vend_id = products.vend_id
ORDER BY vend_name, prod_name;

笛卡兒積:由沒有連結條件的表關係返回的結果為笛卡爾積,檢索出的行的數目將是第一個表中的行數乘以第二個表中的行數。

# 笛卡爾積
SELECT vend_name, prod_name, prod_price
FROM vendors, products
ORDER BY vend_name, prod_name;

內部連結

等值聯結:基於兩個表之間的相等測試,也叫內部連結

SELECT vend_name, prod_name, prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id;
  • 這個結果等效於上面的建立聯結的sql
  • 推薦使用這種語法,更加明確。可確保不會忘記聯結條件,有時候這樣做也能影響效能。

聯結多個表

-- 顯示編號為20005的訂單中的物品。訂單物品儲存在orderitems表中,按每個產品的ID儲存。
它引用products表中的產品。這些產品通過供應商ID聯結到vendors表中相應的供應商
SELECT prod_name, vend_name, prod_price, quantity
FROM orderitems, products, vendors
WHERE products.vend_id = vendors.vend_id
AND orderitems.prod_id = products.prod_id
AND order_num = 20005;

不要聯結不必要的表。聯結的表越多,效能下降越厲害。

下面的一個巢狀查詢sql語句

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 = 'TNT2'));

等效於:

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';

關於外來鍵的補充:

保持資料一致性,完整性,主要目的是控制儲存在外來鍵表中的資料。使兩張表形成關聯,外來鍵只能引用外表中列的值!

1.建立表的過程中建立外來鍵

create table team(
id int primary key auto_increment,
name varchar(40)
);
create table star(
id int ,
name varchar(40),
team_id int,
foreign key (team_id) references team(id)
);

外來鍵語法:FOREIGN KEY(ordersid) references orders(id)

insert into team values(null,‘Toronto Raptors’),(null,‘Milwaukee Bucks’),(null,‘Boston Celtics’),(null,‘Golden State Warriors’),(null,‘Oklahoma City Thunder’),(null,‘Dallas Mavericks’);
insert into star values(2,‘科懷-倫納德’,1),(7,‘洛瑞’,1),(34,‘阿德託昆博’,2),(22,‘米德爾頓’,2),(11,‘歐文’,3),(20,‘海沃德’,3),(35,‘杜蘭特’,4),(30,‘庫裡’,4),(0,‘威斯布魯克’,5),(13,‘保羅-喬治’,5),(77,‘盧克-東契奇’,6),(41,‘諾維斯基’,6);

2.表已存在,增加外來鍵

語法:ALTER TABLE yourSecondTableName ADD CONSTRAINT yourConstraintname FOREIGN KEY(yourForeignKeyColumnName) REFERENCES yourFirstTableName (yourPrimaryKeyColumnName);

示例:

ALTER TABLE orders
ADD CONSTRAINT fk_irderitems_customers
FOREIGN KEY (cust_id) REFERENCES customers(cust_id);

3.刪除外來鍵
alter table 表名 drop foreign key 外來鍵名;

4.測試

我們用1建立的兩張表來做示例,插入一條資料

insert into star VALUES(99, "test01", 6);

這條語句可以執行成功,但如果我們插入下面這條語句:

insert into star VALUES(100, "test02", 7);

系統會報錯:

Cannot add or update a child row: a foreign key constraint fails (`test`.`star`, CONSTRAINT `star_ibfk_1` FOREIGN KEY (`team_id`) REFERENCES `team` (`id`))

即:無法新增或更新子行:外來鍵約束失敗。因為父表team中的id沒有7,這裡新增隊伍id為7就會失敗。

我們再執行以下的語句:

delete from star where team_id = 6;

我們可以把star表中的相應資料刪掉。但是在執行下面的語句時會報錯:

delete from team where id = 5;

-- 報錯資訊:
-- Cannot delete or update a parent row: a foreign key constraint fails (`test`.`star`, CONSTRAINT `star_ibfk_1` FOREIGN KEY (`team_id`) REFERENCES `team` (`id`))

這是因為team表的id與star表team_id相關,刪掉team表id為5的行,但是star表中仍然有資料時team_id = 5的,此時就會報錯。但是因為我們之前刪了star表中team_id為6的行,所以我們再刪除team表id=6的行就不會出錯了。

delete from team where id = 6;

在操作有外來鍵關聯的表時,刪除父表的資料要先刪除子表相關聯的資料才能刪除成功。

第十六章 建立高階聯結

SELECT Concat(RTrim(vend_name),'('Rtrim(vend_country),')') AS vend_title
FROM vendors ORDER BY vend_name;

別名除了用於列名和計算欄位外,SQL還允許給表起別名,這樣做有兩個主要理由:

  • 縮短SQL語句
  • 允許在單條SELECT語句中多次使用相同的表。

例:

SELECT cust_name, cust_contact
FROM customers AS c, orders AS o, orderitems AS oi
WHERE c.cust_id = o.cust_id
AND oi.order_num = o.order_num
AND prod_id = 'TNT2';

使用不同型別的聯結

自聯結

自聯結通常作為外部語句用來替代從相同表中檢索資料時使用的子查詢語句。雖然最終的結果是相同的,但有時候處理聯結遠比處理子查詢快得多。

-- 子查詢
SELECT prod_id, prod_name
FROM products
WHERE vend_id = (SELECT vend_id FROM products WHERE prod_id = 'DTNTR');

-- 自聯結
SELECT p1.prod_id, p1.prod_name
FROM products AS p1, products AS p2
WHERE p1.vend_id = p2.vend_id
AND p2.prod_id = 'DTNTR';

自然聯結

無論何時對錶進行聯結,應該至少有一個列出現在不止一個表中(被聯結的列)。標準的聯結(內部聯結)返回所有資料,甚至相同的列多次出現,自然聯結排除多次出現,使每個列只返回一次。

自然聯結是這樣一種聯結,其中你只能選擇那些唯一的列,這一版是通過使用萬用字元,對所有其他表的列使用明確的字集來完成的。

SELECT c.*, o.order_num, o.order_date, oi.prod_id, oi.quantity, oi.item_price
FROM customers AS c, orders AS o, orderitems AS oi
WHERE c.cust_id = o.cust_id
AND oi.order_num = o.order_num
AND prod_id = 'FB';

外部聯結

-- 內部聯結
SELECT customers.cust_id, orders.order_num
FROM customers INNER JOIN orders
ON customers.cust_id = orders.cust_id;

-- 外部聯結
SELECT customers.cust_id, orders.order_num
FROM customers LEFT OUTER JOIN orders
ON customers.cust_id = orders.cust_id;

外部聯結語法類似。可以檢索所有客戶,包括沒有訂單的客戶。

在使用OUTER JOIN語法時,必須使用RIGHT或LEFT關鍵字指定包括其所有行的表。(RIGHT指出的是OUTER JOIN右邊的表,而LEFT指出的是OUTER JOIN左邊的表。)上面的例子中從customers中選擇所有的行。

SELECT customers.cust_id, orders.order_num
FROM customers RIGHT OUTER JOIN orders
ON customers.cust_id = orders.cust_id;

使用帶聚集函式的聯結

-- 檢索所有客戶及每個客戶所下的訂單數
SELECT customers.cust_name, customers.cust_id, COUNT(orders.order_num) AS num_ord
FROM customers INNER JOIN orders
ON customers.cust_id = orders.cust_id
GROUP BY customers.cust_id;

此SELECT語句使用INNER JOIN將customers和orders表互相關聯。GROUP BY子句按客戶分組資料,因此,函式呼叫COUNT(orders.order_num)對每個客戶的訂單計數,將它作為num_ord返回。

聚集函式也可以方便地與其他聯結一起使用。例:

SELECT customers.cust_name, customers.cust_id, COUNT(orders.order_num) AS num_ord
FROM customers LEFT OUTER JOIN orders
ON customers.cust_id = orders.cust_id
GROUP BY customers.cust_id;

這個例子使用左外部聯結來包含所有客戶,甚至包含那些沒有任何下訂單的客戶。

使用聯結和聯結條件

  • 注意所使用的聯結型別,一般我們使用內部聯結,但使用外部聯結也是有效的。
  • 保證使用正確的聯結條件,否則將返回不正確的資料。
  • 應該總是提供聯結條件,否則會得出笛卡爾積。
  • 在一個聯結中可以包含多個表,甚至對於每個聯結可以採用不同的聯結型別。應該在一起測試他們前分別測試每個聯結。

關於聯結的補充

第十七章 組合查詢

建立組合查詢

使用UNION

#單條語句
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5;

SELECT vend_id, prod_id, prod_price
FROM products
WHERE vend_id IN (1001,1002);

#組合上述語句
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
UNION
SELECT vend_id, prod_id, prod_price
FROM products
WHERE vend_id IN (1001, 1002);

#等於
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
OR vend_id IN (1001, 1002);

UNION規則

  • UNION 必須由兩條或兩條以上的SELECT語句組成,語句之間用關鍵字UNION分隔
  • UNION中的每個查詢必須包含先溝通的列、表示式或聚集函式
  • 列資料型別必須相容:型別不必完全向東,但必須是DBMS可以隱含地轉換的型別

包含或取消重複的行

UNION從查詢結果集中自動去除了重複的行,如果需要返回所有行,可以使用UNION ALL

對組合查詢結果排序

使用ORDER BY子句排序,只能使用一條ORDER BY子句,必須在最後一條SELECT語句之後。

第十八章 全文字搜尋