SQL中有三種聯結,分別是:內聯結,自然聯結,外聯結.
聯結是針對不同表聯合起來的一種方式.應用的對象是:表(table)
為了方便驗證練習理解,首先展示所要用到的表的內容:
1.Customers表:
數據(可復制,創建表,插入數據):
CREATE TABLE Customers
(
cust_id char(10) NOT NULL ,
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 ,
cust_email char(255) NULL
);
-- ------------------------
-- Populate Customers table
-- ------------------------
INSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
VALUES('1000000001', 'Village Toys', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'John Smith', 'sales@villagetoys.com');
INSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
VALUES('1000000002', 'Kids Place', '333 South Lake Drive', 'Columbus', 'OH', '43333', 'USA', 'Michelle Green');
INSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
VALUES('1000000003', 'Fun4All', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'jjones@fun4all.com');
INSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
VALUES('1000000004', 'Fun4All', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Denise L. Stephens', 'dstephens@fun4all.com');
INSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
VALUES('1000000005', 'The Toy Store', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'Kim Howard');
-- ----------------------
展示:
2.Vendors:
-- -------------------
-- Create Orders table
-- -------------------
CREATE TABLE Orders
(
order_num int NOT NULL ,
order_date datetime NOT NULL ,
cust_id char(10) NOT NULL
);
-- ----------------------
-- Populate Vendors table
-- ----------------------
INSERT INTO Vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES('BRS01','Bears R Us','123 Main Street','Bear Town','MI','44444', 'USA');
INSERT INTO Vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES('BRE02','Bear Emporium','500 Park Street','Anytown','OH','44333', 'USA');
INSERT INTO Vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES('DLL01','Doll House Inc.','555 High Street','Dollsville','CA','99999', 'USA');
INSERT INTO Vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES('FRB01','Furball Inc.','1000 5th Avenue','New York','NY','11111', 'USA');
INSERT INTO Vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES('FNG01','Fun and Games','42 Galaxy Road','London', NULL,'N16 6PS', 'England');
INSERT INTO Vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES('JTS01','Jouets et ours','1 Rue Amusement','Paris', NULL,'45678', 'France');
-- -----------------------
3.Products:
-- ---------------------
-- Create Products table
-- ---------------------
CREATE TABLE Products
(
prod_id char(10) NOT NULL ,
vend_id char(10) NOT NULL ,
prod_name char(255) NOT NULL ,
prod_price decimal(8,2) NOT NULL ,
prod_desc text NULL
);
-- -----------------------
-- Populate Products table
-- -----------------------
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('BR01', 'BRS01', '8 inch teddy bear', 5.99, '8 inch teddy bear, comes with cap and jacket');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('BR02', 'BRS01', '12 inch teddy bear', 8.99, '12 inch teddy bear, comes with cap and jacket');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('BR03', 'BRS01', '18 inch teddy bear', 11.99, '18 inch teddy bear, comes with cap and jacket');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('BNBG01', 'DLL01', 'Fish bean bag toy', 3.49, 'Fish bean bag toy, complete with bean bag worms with which to feed it');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('BNBG02', 'DLL01', 'Bird bean bag toy', 3.49, 'Bird bean bag toy, eggs are not included');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('BNBG03', 'DLL01', 'Rabbit bean bag toy', 3.49, 'Rabbit bean bag toy, comes with bean bag carrots');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('RGAN01', 'DLL01', 'Raggedy Ann', 4.99, '18 inch Raggedy Ann doll');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('RYL01', 'FNG01', 'King doll', 9.49, '12 inch king doll with royal garments and crown');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('RYL02', 'FNG01', 'Queen doll', 9.49, '12 inch queen doll with royal garments and crown');
4.Orders
-- -------------------
-- Create Orders table
-- -------------------
CREATE TABLE Orders
(
order_num int NOT NULL ,
order_date datetime NOT NULL ,
cust_id char(10) NOT NULL
);
-- ---------------------
-- Populate Orders table
-- ---------------------
INSERT INTO Orders(order_num, order_date, cust_id)
VALUES(20005, '2012-05-01', '1000000001');
INSERT INTO Orders(order_num, order_date, cust_id)
VALUES(20006, '2012-01-12', '1000000003');
INSERT INTO Orders(order_num, order_date, cust_id)
VALUES(20007, '2012-01-30', '1000000004');
INSERT INTO Orders(order_num, order_date, cust_id)
VALUES(20008, '2012-02-03', '1000000005');
INSERT INTO Orders(order_num, order_date, cust_id)
VALUES(20009, '2012-02-08', '1000000001');
好吧,如上原始數據已經有了,現在我們來理解SQL幾種聯結之間的關系和細節.
1.為什么要使用聯結:
有時候為了方便存儲,我們會把數據分解為多個表.例如,現在某公司需要用到以下產品,別人對應的供應商和價格如下:
這一張表存了供應商的信息和產品以及價格.可以看到這個供應商給我們提供了兩種產品:QQ和郵箱;
這兩種產品都是出自於同一個供應商,因此我們存儲數據的時候,"供應商的地址"和"聯系人" 就被重復存儲了".現實應用中,一個供應商可能提供的產品遠遠超過2個,
這就會給我錄入數據和存儲數據和更新數據帶來很大的麻煩.譬如:這個提供多種產品的供應商的地址需要更新的時候
於是我們可以把張表分解成兩個表,關聯兩個表主鍵(方便查詢,也就是相關聯的共同的信息),如下:
1.
2.
這樣一來,后續要我更新某個供應商的地址和聯系人的時候,只需要對表2中的對應內容進行更新就好了.這樣分解表后的兩個表更直觀一些了,但是在我們處理查詢數據的時候,就要關聯兩個表中的
信息了,操作的復雜度就增大了.按照我們常規的處理方式,
如果我們要查提供某一個產品的供應商的全部信息,那就要先到表2中把供應商的地址和聯系人先查出來,然后再結合表1中對應產品的其他信息
這時我們一種方式是分步處理:
1,按照步驟來,首先在表1中查出對應產品的供應商
2.在表2中查出對應的供應商的地址和聯系人信息
另外一種是,嵌套子查詢,一步設置完查詢
但是這兩種方式,操作起來都不是太方便,在輸入的時候可能要多輸入一些條件和內容才能達到我們想要的結果.因此就有了聯結的概念.
如最上面所說,聯結有幾種方式:內聯結,自聯結,自然聯結,外聯結
內聯結(INNER JOIN):內聯結也可以稱為等值聯結.例如:
如以上兩個表格中,每個訂單包含訂單編號,客戶ID,訂單日期,在Orders表中存儲為一行,各訂單的物品存儲在相關的OrdersItems表中.Orders表不存儲顧客的信息,只存儲顧客ID.顧客的實際信息存儲在Customers
表中.
現在,假如需要列出訂購物品"RGAN01"的所有顧客,應該怎樣檢索?
步驟為下:
1.檢索包含物品RGAN01的所有訂單的編號.
2.檢索具有前一步驟列出的訂單編號的所有顧客 的ID
3.檢索前一步驟返回的所有顧客ID的顧客信息
方法一:以上每步可以單獨作為一個查詢來執行.可以把一個SELECT 語句返回的結果用於另外一條SELECT語句的WHERE子句.
方法二:也可以使用子查詢把3個查詢組合成一條語句
方法三:直接使用內聯結來關聯兩個表直接查詢.
方法一實現:
2.方法二實現:
3.方法三實現:
上面是通過 WHERE 語句來實現的,這里面等同於 INNER JOIN...ON (INNER JOIN基本上只用於聯結兩個表,不太適合多個表聯結).
INNER JOIN ...ON 的使用方式
2.自聯結
例如:現在要給Jim Jones同一公司的所有顧客發送一封信件.這個查詢要求首先找出Jim Jones工作的公司,然后找出在該公司工作的顧客.下面是實現代碼:
通過customers表可以看出,cust_contact 里面對應的 Jim Jones 的公司是,Fun4All,然后篩選出 Fun4All 公司的其他聯系人和客戶ID
以上是通過子查詢的方式實現的.
先對對比一下自聯結方式實現:
此處要非常小心一定是要c2來進行過濾
3.自然聯結
無論何時對表進行聯結,應該至少有一列不止出現在一個表中(被聯結的列).標准的聯結(前一課中介紹的內聯結)返回所有數據,相同的列甚至多次出現.
自然聯結排除多線出現,使每列只返回一次.
自然聯結要求只能選擇那些唯一的列,一般通過對一個表使用通配符(SELECT*),而對其他表的列使用明確的子集來完成.如:
在這個例子中,通配符只對第一個表使用,所有其他列明確列出,所以沒有重復的列被檢索出來.事實上,我們目前所學的每個內聯結都是自然聯結
4.外聯結
許多聯結將一個表中的行與另一個表中的行相關聯,但有時候需要包含沒有關聯行的那些行.
例如:
A.對每個顧客下的訂單進行計數,包括那些至今尚未下訂單的顧客;
B.列出所有產品以及訂購數量,包括沒有人訂購的產品
C.計算平均銷售規模,包括那些至今尚未下訂單的顧客.
這種聯結包含了那些在相關表中沒有關聯行的行的聯結方式就是外聯結
例如:
外聯結使用的時候,注意區分 LEFT OUTER JOIN 還是 RIGHT OUTER JOIN 就是設定展示哪邊的表的所有行.另外還可以使用FULL OUTER JOIN