Join 和 and
在使用left join时,on and和on where条件的区别如下:
1、on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录。
2、where条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有left join的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉,on后的条件用来生成左右表关联的临时表,where后的条件对临时表中的记录进行过滤。
表结构
SQL> create table A (id int, type int);
SQL> select * from A;
ID TYPE
---------- ----------
1 1
2 1
3 2
SQL> create table B(id int ,class int);
SQL> select * from B;
ID CLASS
---------- ----------
1 1
2 2
不使用条件
SQL> select * from A left join B on A.id = b.id;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 1 1 1
2 1 2 2
3 2
使用条件where
SQL> select * from A left join B on A.id = B.id where A.type = 1;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 1 1 1
2 1 2 2
根据上面那段话的解释,where字句是在生成临时表以后再进行过滤的,也就是可以理解为就是一个左连接:
select * from A left join B on A.id = B.id,然后加上where A.type = 1对临时表进行过滤,除掉A.type不为1的数据。
使用and
SQL> select * from A left join B on A.id = B.id and A.type = 1; (这需要操作确认)
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 1 1 1
2 1 2 2
3 2
因为左连接不管on and语句是否为真都必须返回左表所有的记录,所以and A.type=1;没有起到任何作用。
SQL> select * from A left join B on A.id = B.id and B.class = 1;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 1 1 1
3 2
2 1
根据上面那段话的解释:on条件是在生成临时表时使用的条件,它不管on中的条件是否为真,都会返回左边表中的记录。
显然左连接再加上新的条件:B.class = 1筛选掉第二行记录,结果正确。
使用 where:
SQL> select * from A left join B on A.id = B.id where B.class = 1;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 1 1 1
where是生成临时表以后再进行过滤,对左右表都进行筛选。
如果是and,先不管过滤规则,先把左边表数据全部返回,然户过滤规则只对右表产生过滤。
再来看看内连接inner join on and和 on where的区别:
在使用inner join时,不管是对左表还是右表进行筛选,on and和on where都会对生成的临时表左右两边同时进行过滤。
表结构
SQL> select * from A;
ID TYPE
---------- ----------
1 2
2 1
3 2
SQL> select * from B;
ID CLASS
---------- ----------
1 1
2 2
inner join 的特性就是只返回有匹配的
SQL> select * from A inner join B on A.id = B.id;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 2 1 1
2 1 2 2
SQL>
SQL> select * from A inner join B on A.id = B.id where A.type = 1;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
2 1 2 2
SQL>
SQL> select * from A inner join B on A.id = B.id and B.class = 1;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 2 1 1
SQL>
SQL> select * from A inner join B on A.id = B.id where B.class = 1;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 2 1 1
发现会对左右两边同时过滤。
多次join同一张表的处理: join and or
select * from (
select nod.*, concat_ws(",",vi.vip, vi2.vip) as vip, vi.relation_id as aaa from node nod
left join cluster clu on clu.name = nod.cluster_name and clu.owner = "sulijun6"
left join virtual_ip vi on nod.uniq_id = vi.relation_id and nod.role in ("master", "slave")
left join virtual_ip vi2 on nod.group_id = vi2.relation_id and nod.role = "roleless"
) as aa
select my_db.db_name, my_db.description,
node.ip as ip, node.port as port, node.`role` as role,
app.app_name_en, app.app_name_cn, app.owner,
group_concat(distinct(account.hosts)) as app_hosts
from my_db
left join app on app.cluster_name = my_db.cluster_name
left join account on account.cluster_uniq_id = my_db.cluster_uniq_id
left join ha_group hg on hg.cluster_uniq_id = my_db.cluster_uniq_id
left join proxy_group pg on pg.cluster_uniq_id = my_db.cluster_uniq_id
left join node on (node.group_id = hg.uniq_id and node.`role` in ('master', 'slave')) or (node.group_id = pg.uniq_id and node.`role` = 'roleless')
group by app.app_name_en, my_db.db_name, node.ip
group_concat: 没有 group by 也可以使用
mysql> select * from student;
+----+----------+--------+---------+----------------------------+----------------------------+------------+
| id | name | gender | address | create_date | update_date | country_id |
+----+----------+--------+---------+----------------------------+----------------------------+------------+
| 2 | fromjdbc | 2 | HeNan | 2020-12-25 15:13:18.000000 | 2020-12-25 15:13:18.000000 | 1 |
| 3 | Michael | 1 | BeiJing | 2020-12-25 15:13:55.000000 | 2020-12-25 17:07:56.024261 | 2 |
| 4 | cpx | 1 | BeiJing | 2020-12-30 19:46:41.000000 | 2020-12-30 19:46:41.000000 | 2 |
| 5 | cpxx | 1 | BeiJing | 2020-12-30 19:46:50.000000 | 2022-06-07 10:30:33.432000 | 1 |
| 6 | aa | 2 | aaa | 2022-10-26 19:06:26.000000 | 2022-10-26 19:06:26.000000 | 1 |
| 8 | jdbc1 | 1 | SH | 2022-10-26 08:18:29.438000 | 2022-10-26 08:18:29.438000 | 1 |
| 9 | 11111 | 1 | SH | 2022-10-26 08:21:22.657000 | 2022-10-26 08:21:23.255000 | 1 |
| 10 | jdbc1 | 1 | SH | 2022-10-26 08:23:51.336000 | 2022-10-26 08:23:51.860000 | 1 |
| 11 | jdbc0 | 1 | SH | 2022-10-26 08:25:48.981000 | 2022-10-26 08:25:48.981000 | 1 |
| 12 | jdbc1 | 1 | SH | 2022-10-26 08:25:48.981000 | 2022-10-26 08:25:48.981000 | 1 |
+----+----------+--------+---------+----------------------------+----------------------------+------------+
10 rows in set (0.00 sec)
mysql>
mysql> select group_concat(name SEPARATOR ',') from student;
+------------------------------------------------------------+
| group_concat(name SEPARATOR ',') |
+------------------------------------------------------------+
| fromjdbc,Michael,cpx,cpxx,aa,jdbc1,11111,jdbc1,jdbc0,jdbc1 |
+------------------------------------------------------------+
1 row in set (0.00 sec)
mysql>
find_in_set
FIND_IN_SET(str,strlist),该函数的作用是查询字段(strlist) 中是否包含(str)的结果,返回结果为 null或记录 。
SELECT FIND_IN_SET('b', 'a,b,c,d');
// 结果:2. 因为 b 在strlist集合中2的位置, a是位置1