MariaDB 连接查询与子查询

Posted LyShark

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MariaDB 连接查询与子查询相关的知识,希望对你有一定的参考价值。

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表,SQL语句如下:

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 连接查询与子查询的主要内容,如果未能解决你的问题,请参考以下文章

如何将查询与子查询连接起来?

连接查询与子查询

与子查询相比,为啥左外连接查询给出不同的结果?

Mysql 慢查询组与子查询连接

SQL 内连接与子查询

SQL 查询时间复杂度 - 连接与子查询