MariaDB 連接查詢與子查詢(6)
MariaDB數據庫管理系統是MySQL的一個分支,主要由開源社區在維護,采用GPL授權許可MariaDB的目的是完全兼容MySQL,包括API和命令行,MySQL由於現在閉源了,而能輕松成為MySQL的代替品.在存儲引擎方面,使用XtraDB來代替MySQL的InnoDB,MariaDB由MySQL的創始人Michael Widenius主導開發,他早前曾以10億美元的價格,將自己創建的公司MySQL AB賣給了SUN,此後,隨著SUN被甲骨文收購MySQL的所有權也落入Oracle的手中.MariaDB名稱來自MichaelWidenius的女兒Maria的名字.
MariaDB 連接查詢
連接是關系數據庫模型的主要特點,連接查詢是關系數據庫中最主要的查詢,主要包括內連接、外連接等.通過連接運算符可以實現多個表查詢,在關系數據庫管理系統中,表建立時各數據之間的關系不必確定,常把一個實體的所有信息存放在一個表中.當查詢數據時,通過連接操作查詢出存放在多個表中的不同實體的信息.當兩個或多個表中存在相同意義的字段時,便可以通過這些字段對不同的表進行連接查詢.
◆內連接查詢◆
內連接(INNER JOIN)使用比較運算符進行表間(某些列)數據的比較操作,並列出這些表中與連接條件相匹配的數據行,組合成新記錄,也就是說,在內連接查詢中,只有滿足條件的記錄才能出現在結果關系中.
為了演示效果的需要,首先穿件一個suppliers
MariaDB [lyshark]> create table suppliers -> ( -> s_id int not null auto_increment, -> s_name char(50) not null, -> s_city char(50) null, -> s_zip char(10) null, -> s_call char(50) not null, -> primary key(s_id) -> ); Query OK, 0 rows affected (0.09 sec)
需要插入演示的數據,SQL語句如下:
INSERT INTO suppliers(s_id,s_name,s_city,s_zip,s_call) values(101,'FastFruit.','TianJin','30000','4521');
INSERT INTO suppliers(s_id,s_name,s_city,s_zip,s_call) values(102,'LT Supplies','ShangHai','554780','3268');
INSERT INTO suppliers(s_id,s_name,s_city,s_zip,s_call) values(103,'ACME LyShark','Chongqing','447581','9985');
INSERT INTO suppliers(s_id,s_name,s_city,s_zip,s_call) values(104,'FNK INCS','XiZang','3526','4475');
INSERT INTO suppliers(s_id,s_name,s_city,s_zip,s_call) values(105,'GOOD SET','ZhongSHan','4478511','6666');
INSERT INTO suppliers(s_id,s_name,s_city,s_zip,s_call) values(106,'JUST Eat Ours','TaiYuang','33325469','5555');
INSERT INTO suppliers(s_id,s_name,s_city,s_zip,s_call) values(107,'docker INC','ZhengZhou','1124574','4851');
內連接實例: 在lyshark表
和suppliers表
之間使用內連接查詢.
1.在查詢之前先來看一下表結構吧.
MariaDB [lyshark]> desc lyshark;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| Uid | char(10) | NO | PRI | NULL | |
| Gid | int(11) | NO | | NULL | |
| Name | char(255) | NO | | NULL | |
| Price | decimal(8,2) | NO | | NULL | |
+-------+--------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
MariaDB [lyshark]> desc suppliers;
+--------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+----------+------+-----+---------+----------------+
| s_id | int(11) | NO | PRI | NULL | auto_increment |
| s_name | char(50) | NO | | NULL | |
| s_city | char(50) | YES | | NULL | |
| s_zip | char(10) | YES | | NULL | |
| s_call | char(50) | NO | | NULL | |
+--------+----------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
由上面的查詢結果可看到,lyshark表
和suppliers
表中都有相同數據類型的字段ID
,兩個表通過Gid與s_id
字段建立聯系.
2.接下來從lyshark表
查詢Name,Price字段
,從suppliers表
查詢s_id,s_name字段
,SQL語句如下:
MariaDB [lyshark]> select suppliers.s_id,s_name,Name,Price
-> from lyshark,suppliers
-> where lyshark.Gid = suppliers.s_id;
+------+---------------+------------+-------+
| s_id | s_name | Name | Price |
+------+---------------+------------+-------+
| 101 | FastFruit. | apple | 5.20 |
| 103 | ACME LyShark | apricot | 2.20 |
| 101 | FastFruit. | blackberry | 10.20 |
| 104 | FNK INCS | berry | 7.60 |
| 107 | docker INC | xxxx | 3.60 |
| 102 | LT Supplies | orange | 11.20 |
| 105 | GOOD SET | melon | 8.20 |
| 101 | FastFruit. | cherry | 3.20 |
| 104 | FNK INCS | lemon | 6.40 |
| 106 | JUST Eat Ours | mango | 15.70 |
| 105 | GOOD SET | xbabay | 2.60 |
| 105 | GOOD SET | xxtt | 11.60 |
| 103 | ACME LyShark | coconut | 9.20 |
| 102 | LT Supplies | bannana | 10.30 |
| 102 | LT Supplies | grape | 5.30 |
| 107 | docker INC | xbababa | 3.60 |
+------+---------------+------------+-------+
16 rows in set (0.01 sec)
在這裏,SELECT語句
與前面所介紹的一個最大的差別是,SELECT後面指定的列分別屬於兩個不同的表,(Name,Price)在表 lyshark中
,而另外兩個字段在表 suppliers
中,同時FROM子句列出了兩個表lyshark 和 suppliers
.WHERE 子句在這裏作為過濾條件,指明只有兩個表中的s_id
字段值相等的時候才符合連接查詢的條件.從返回的結果可以看到,顯示的記錄是由兩個表中不同列值組成的新記錄.
內連接(INNER JOIN)實例: 在lyshark表
和suppliers表
之間,使用INNER JOIN
語法進行內連接查詢,SQL語句如下:
MariaDB [lyshark]> select suppliers.s_id,s_name,Name,Price
-> from lyshark INNER JOIN suppliers
-> ON lyshark.Gid=suppliers.s_id;
+------+---------------+------------+-------+
| s_id | s_name | Name | Price |
+------+---------------+------------+-------+
| 101 | FastFruit. | apple | 5.20 |
| 103 | ACME LyShark | apricot | 2.20 |
| 101 | FastFruit. | blackberry | 10.20 |
| 104 | FNK INCS | berry | 7.60 |
| 107 | docker INC | xxxx | 3.60 |
| 102 | LT Supplies | orange | 11.20 |
| 105 | GOOD SET | melon | 8.20 |
| 101 | FastFruit. | cherry | 3.20 |
| 104 | FNK INCS | lemon | 6.40 |
| 106 | JUST Eat Ours | mango | 15.70 |
| 105 | GOOD SET | xbabay | 2.60 |
| 105 | GOOD SET | xxtt | 11.60 |
| 103 | ACME LyShark | coconut | 9.20 |
| 102 | LT Supplies | bannana | 10.30 |
| 102 | LT Supplies | grape | 5.30 |
| 107 | docker INC | xbababa | 3.60 |
+------+---------------+------------+-------+
16 rows in set (0.01 sec)
本案例和上面的查詢結果是一樣的,在這裏兩表之間的關系通過INNER JOIN
指定,使用這種語法的時候連接的條件使用ON
子句,ON和WHERE後面指定的條件相同.
自連接實例: 查詢供應商Uid=‘a1‘
的水果的種類,SQL語句如下:
如果在一個連接查詢中,涉及的兩個表都是同一張表,這種查詢稱為自連接查詢
,自連接是一種特殊的內連接,它是指相互連接的表在物理上為同一張表,但可以在邏輯上分為兩張表.
MariaDB [lyshark]> select f1.Uid,f1.Name
-> from lyshark AS f1,lyshark AS f2
-> where f1.Gid = f2.Gid and f2.Uid='a1';
+-----+------------+
| Uid | Name |
+-----+------------+
| a1 | apple |
| b1 | blackberry |
| c0 | cherry |
+-----+------------+
3 rows in set (0.01 sec)
此處查詢的兩個表是相同的表,為了防止產生二義性,對表使用了別名,lyshark
表第1次出現的別名為fl,第2次出現的別名為f2,使用SELECT語句返回列時明確指出返回以n為前綴的列的全名,WHERE連接兩個表,並按照第2個表的Gid
對數據進行過濾,返回所需數據.
◆外連接查詢◆
外連接查詢將查詢多個表中相關聯的行,內連接時,返回查詢結果集合中的僅是符合查詢條件和連接條件的行.但有時候需要包含沒有關聯的行中數據,即返回查詢結果集合中的不僅包含符合連接條件的行,而且還包括左表(左外連接或左連接)
,右表(右外連接或右連接)
,或兩個連接表(全外連接)
中的所有數據行,外連接分為左外連接右外連接:
● LEFT JOIN(左連接):返回包括左表中的所有記錄和右表中連接字段相等的記錄.
● RIGHT JOIN(右連接):返回包括右表中的所有記錄和左表中連接字段相等的記錄.
接著下面先來創建兩個測試表orders和customers
,SQL語句如下:
MariaDB [lyshark]> create table orders
-> (
-> o_num int not null auto_increment,
-> o_date datetime not null,
-> c_id int not null,
-> primary key(o_num)
-> );
Query OK, 0 rows affected (0.02 sec)
MariaDB [lyshark]> create table customers (c_id int not null );
Query OK, 0 rows affected (0.01 sec)
接著插入需要演示的數據,SQL語句如下:
INSERT INTO orders(o_num,o_date,c_id) VALUES(30001,'2018-09-01',10001);
INSERT INTO orders(o_num,o_date,c_id) VALUES(30002,'2018-09-02',10003);
INSERT INTO orders(o_num,o_date,c_id) VALUES(30003,'2018-09-03',10004);
INSERT INTO orders(o_num,o_date,c_id) VALUES(30004,'2018-09-04',10005);
INSERT INTO orders(o_num,o_date,c_id) VALUES(30005,'2018-09-05',10001);
INSERT INTO customers(c_id) VALUES(10001);
INSERT INTO customers(c_id) VALUES(10002);
INSERT INTO customers(c_id) VALUES(10003);
INSERT INTO customers(c_id) VALUES(10004);
INSERT INTO customers(c_id) VALUES(10005);
左連接(lEFT JOIN)
左連接的結果包括LEFT OUTER
子句中指定的左表的所有行,而不僅僅是連接列所匹配的行,如果左表的某行在右表中沒有匹配行,則在相關聯的結果中,右表的所有選擇列表列均為空值.
如下:在customers表
和orders表
中,查詢所有客戶,包括沒有訂單的客戶,SQL語句如下:
MariaDB [lyshark]> select customers.c_id,orders.o_num
-> from customers LEFT OUTER JOIN orders
-> ON customers.c_id=orders.c_id;
+-------+-------+
| c_id | o_num |
+-------+-------+
| 10001 | 30001 |
| 10003 | 30002 |
| 10004 | 30003 |
| 10005 | 30004 |
| 10001 | 30005 |
| 10002 | NULL |
+-------+-------+
6 rows in set (0.00 sec)
結果顯示了6條記錄,編號10002的用戶並沒有達成交易,所有該條記錄只取出了ordes
表中相應的值,而從customers
表中取出的值為空值NULL
.
右連接(RIGHT JOIN)
右連接是左連接的反向連接,將返回右表的所有行,如果右表的某行在作表中沒有匹配行,作表將返回空值.
實例: 在customers
表和orders
表中,查詢所有訂單,包括沒有客戶的訂單,SQL語句如下:
MariaDB [lyshark]> select customers.c_id,orders.o_num
-> from customers RIGHT OUTER JOIN orders
-> ON customers.c_id=orders.c_id;
+-------+-------+
| c_id | o_num |
+-------+-------+
| 10001 | 30001 |
| 10001 | 30005 |
| 10003 | 30002 |
| 10004 | 30003 |
| NULL | 30004 |
+-------+-------+
5 rows in set (0.00 sec)
結果顯示6條記錄,30004訂單客戶取消了訂單,對應的customers表
中並沒有該客戶的信息,所以該條記錄只取出了orders表
中相應的值,而從customers表
中取出的值為空值NULL.
◆復合連接查詢◆
復合條件連接查詢是在連接查詢的過程中,通過添加過濾條件,限制查詢的結果,使查詢結果更精確.
實例: 在lyshark
表和suppliers
表之間,使用INNER JOIN
語法進行內連接查詢,並對查詢結果排序,SQL語句如下:
MariaDB [lyshark]> select suppliers.s_id,s_name,Name,Price
-> from lyshark INNER JOIN suppliers
-> ON lyshark.Gid = suppliers.s_id
-> ORDER BY lyshark.Gid;
+------+---------------+------------+-------+
| s_id | s_name | Name | Price |
+------+---------------+------------+-------+
| 101 | FastFruit. | apple | 5.20 |
| 101 | FastFruit. | blackberry | 10.20 |
| 101 | FastFruit. | cherry | 3.20 |
| 102 | LT Supplies | grape | 5.30 |
| 102 | LT Supplies | bannana | 10.30 |
| 102 | LT Supplies | orange | 11.20 |
| 103 | ACME LyShark | apricot | 2.20 |
| 103 | ACME LyShark | coconut | 9.20 |
| 104 | FNK INCS | lemon | 6.40 |
| 104 | FNK INCS | berry | 7.60 |
| 105 | GOOD SET | xbabay | 2.60 |
| 105 | GOOD SET | xxtt | 11.60 |
| 105 | GOOD SET | melon | 8.20 |
| 106 | JUST Eat Ours | mango | 15.70 |
| 107 | docker INC | xxxx | 3.60 |
| 107 | docker INC | xbababa | 3.60 |
+------+---------------+------------+-------+
16 rows in set (0.00 sec)
MariaDB 子查詢
子查詢指一個查詢語句嵌套在另一個查詢語句內部的查詢,在SELECT子句中先計算子查詢,子查詢結果作為外層另一個查詢的過濾條件,查詢可以基於一個表或者多個表.
一般的子查詢中常用的操作符有ANY(SOME),ALL,IN,EXISTS
.子查詢可以添加到SELECT、UPDATE和DELETE
語句中,而且可以進行多層嵌套.子查詢中也可以使用比較運算符,如<,<=,>,>=,!=
等.
◆IN 子查詢◆
IN關鍵字進行子查詢時,內層查詢語句僅僅返回一個數據列,這個數據列裏的值將提供給外層查詢語句進行比較操作.
IN查詢1: 查詢lyshark表
中的Uid=‘a1‘
的GId號,並以Gid作為查詢條件查詢suppliers表
中s_id字段
的s_city
字段的數值.
MariaDB [lyshark]> select Gid from lyshark where Uid='a1';
+-----+
| Gid |
+-----+
| 101 |
+-----+
1 row in set (0.00 sec)
MariaDB [lyshark]> select * from suppliers;
+------+---------------+-----------+----------+--------+
| s_id | s_name | s_city | s_zip | s_call |
+------+---------------+-----------+----------+--------+
| 101 | FastFruit. | TianJin | 30000 | 4521 |
| 102 | LT Supplies | ShangHai | 554780 | 3268 |
| 103 | ACME LyShark | Chongqing | 447581 | 9985 |
| 104 | FNK INCS | XiZang | 3526 | 4475 |
| 105 | GOOD SET | ZhongSHan | 4478511 | 6666 |
| 106 | JUST Eat Ours | TaiYuang | 33325469 | 5555 |
| 107 | docker INC | ZhengZhou | 1124574 | 4851 |
+------+---------------+-----------+----------+--------+
7 rows in set (0.00 sec)
MariaDB [lyshark]> select s_city from suppliers where s_id IN
-> (select Gid from lyshark where Uid='a1');
+---------+
| s_city |
+---------+
| TianJin |
+---------+
1 row in set (0.02 sec)
IN查詢2: 查詢lyshark表
中,Gid字段是(101和105)編號
的內容.
MariaDB [lyshark]> select Gid,Name from lyshark where Gid IN(101,105);
+-----+------------+
| Gid | Name |
+-----+------------+
| 101 | apple |
| 101 | blackberry |
| 105 | melon |
| 101 | cherry |
| 105 | xbabay |
| 105 | xxtt |
+-----+------------+
6 rows in set (0.00 sec)
NOT IN查詢: 這個查詢結果正好和上面的例子相反.
MariaDB [lyshark]> select Gid,Name from lyshark where Gid NOT IN(101,105,102);
+-----+----------+
| Gid | Name |
+-----+----------+
| 103 | apricot |
| 104 | berry |
| 107 | xxxx |
| 104 | lemon |
| 999 | lysharks |
| 106 | mango |
| 103 | coconut |
| 107 | xbababa |
+-----+----------+
8 rows in set (0.00 sec)
◆ANY 子查詢◆
ANY和SOME關鍵字是同義詞,表示滿足其中任意一個條件,他們允許創建一個表達式對子查詢的返回值進行比較,只要滿足內層子查詢中任何一個比較條件,就返回一個結果作為外層查詢的條件.
為了進行下面的實驗,先來創建一下SQL語句表格:
MariaDB [lyshark]> create table tab1(num1 int not null);
Query OK, 0 rows affected (0.02 sec)
MariaDB [lyshark]> create table tab2(num2 int not null);
Query OK, 0 rows affected (0.00 sec)
INSERT INTO tab1 VALUES(1),(5),(13),(27);
INSERT INTO tab2 VALUES(6),(14),(11),(20);
ANY 實例: 返回tab2
表的所有num2列,然後將tab1
中的num1的值與之進行比較,只要大於num2的任何1個值,即為符合查詢結果.
MariaDB [lyshark]> select num1 from tab1 where num1 > ANY(select num2 from tab2);
+------+
| num1 |
+------+
| 13 |
| 27 |
+------+
2 rows in set (0.01 sec)
在子查詢中,返回的是tab2的所有num2列結果(6,14,11,20),然後將tab1中的num1列的值與之進行比較,只要大於num2列的任意一個數即為符合條件的結果.
◆ALL 子查詢◆
ALL關鍵字與ANY不同,使用ALL時需要同時滿足所有內層查詢的條件,ALL關鍵字接在一個比較操作符的後面,表示與子查詢返回的所有值比較為TRUE,則返回TRUE.
ALL實例: 返回tab2
表中比tab2
表num2列所有值都打的值,SQL語句如下:
MariaDB [lyshark]> select num1 from tab1 where num1 > ALL(select num2 from tab2);
+------+
| num1 |
+------+
| 27 |
+------+
1 row in set (0.02 sec)
以上,大於所有num2列的num1值只有27,則返回27.
◆EXISTS 子查詢◆
EXISTS關鍵字後面的參數是一個任意的子查詢,系統對子查詢進行運算以判斷它是否返回行,如果至少返回一行,那麽EXISTS的結果為true
,此時外層查詢語句將進行查詢.如果子查詢沒有返回任何行,那麽EXISTS返回的結果是false
,此時外層語句將不進行查詢.
EXISTS 實例1: 查詢lyshark
表中所有記錄,查詢suppliers
表中是否存在s_id=107
的記錄,如果存在,則查詢lyshark
表中的記錄,否則不查詢,SQL語句如下:
MariaDB [lyshark]> select * from lyshark
-> where EXISTS
-> (select s_name from suppliers where s_id=107);
+---------+-----+------------+--------+
| Uid | Gid | Name | Price |
+---------+-----+------------+--------+
| a1 | 101 | apple | 5.20 |
| a2 | 103 | apricot | 2.20 |
| b1 | 101 | blackberry | 10.20 |
| b2 | 104 | berry | 7.60 |
| b5 | 107 | xxxx | 3.60 |
| bs1 | 102 | orange | 11.20 |
| bs2 | 105 | melon | 8.20 |
| c0 | 101 | cherry | 3.20 |
| l2 | 104 | lemon | 6.40 |
| lyshark | 999 | lysharks | 999.00 |
| m1 | 106 | mango | 15.70 |
| m2 | 105 | xbabay | 2.60 |
| m3 | 105 | xxtt | 11.60 |
| o2 | 103 | coconut | 9.20 |
| t1 | 102 | bannana | 10.30 |
| t2 | 102 | grape | 5.30 |
| t4 | 107 | xbababa | 3.60 |
+---------+-----+------------+--------+
17 rows in set (0.01 sec)
由結果可以看到,內層查詢結果表明suppliers
表中存在s_id =107
表達式返回true
,外層查詢語句接收true
之後對表lyshark
進行查詢,並返回所有的記錄.
EXISTS 實例2: 查詢suppliers
表中是否存在s_id=107
的字段,如果存在,則查詢lyshark
表中的Price
大於10.02的記錄,SQL語句如下:
MariaDB [lyshark]> select * from lyshark
-> where Price >10.02 AND EXISTS
-> (select s_name from suppliers where s_id=107);
+---------+-----+------------+--------+
| Uid | Gid | Name | Price |
+---------+-----+------------+--------+
| b1 | 101 | blackberry | 10.20 |
| bs1 | 102 | orange | 11.20 |
| lyshark | 999 | lysharks | 999.00 |
| m1 | 106 | mango | 15.70 |
| m3 | 105 | xxtt | 11.60 |
| t1 | 102 | bannana | 10.30 |
+---------+-----+------------+--------+
6 rows in set (0.00 sec)
NOT EXISTS 實例: 查詢suppliers
表中是否存在s_id=107
的供應商,如果不存在則查詢lyshark
表中的記錄,SQL語句如下:
MariaDB [lyshark]> select * from lyshark
-> where NOT EXISTS
-> (select s_name from suppliers where s_id=107);
Empty set (0.00 sec)
如上:查詢語句select s_name from suppliers where s_id=107
返回false,則不再執行外層的查詢工作.
◆比較運算符子查詢◆
1111
MariaDB 其他查詢
合並查詢結果
為表和字段取別名
MariaDB 連接查詢與子查詢(6)