您好,欢迎来到99网。
搜索
您的当前位置:首页SQLleftjoin左表合并去重技巧总结

SQLleftjoin左表合并去重技巧总结

来源:99网
SQLleftjoin左表合并去重技巧总结

建表:

CREATE TABLE `table1` (

`id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(60) DEFAULT NULL, `age` varchar(200) DEFAULT NULL,

`sponsor_id` varchar(20) DEFAULT NULL COMMENT '业务发起⼈', `gmt_create_user` int(11) NOT NULL COMMENT '创建⼈id',

`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime DEFAULT NULL COMMENT '修改时间', `gmt_modified_user` int(11) DEFAULT NULL COMMENT '修改⼈id', PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COMMENT='测试表1';CREATE TABLE `table2` (

`kid` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(60) DEFAULT NULL,

`sponsor_id` varchar(20) DEFAULT NULL COMMENT '业务发起⼈', `type` int(11) NOT NULL COMMENT '创建⼈id',

`gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `gmt_modified` datetime DEFAULT NULL COMMENT '修改时间', `gmt_modified_user` int(11) DEFAULT NULL COMMENT '修改⼈id', PRIMARY KEY (`kid`)

) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COMMENT='测试表2';

插⼊数据:

INSERT INTO `table1`(`id`, `name`, `age`, `sponsor_id`, `gmt_create_user`, `gmt_create`, `gmt_modified`, `gmt_modified_user`) VALUES (1, 't1', '11', '10', 1, '2018-10-10 20:34:03', NULL, NULL);INSERT INTO `table1`(`id`, `name`, `age`, `sponsor_id`, `gmt_create_user`, `gmt_create`, `gmt_modified`, `gmt_modified_user`) VALUES (2, 't2', '12', '10', 2, '2018-10-10 20:34:03', NULL, NULL);INSERT INTO `table1`(`id`, `name`, `age`, `sponsor_id`, `gmt_create_user`, `gmt_create`, `gmt_modified`, `gmt_modified_user`) VALUES (3, 't3', '13', '10', 3, '2018-10-10 20:34:03', NULL, NULL);INSERT INTO `table1`(`id`, `name`, `age`, `sponsor_id`, `gmt_create_user`, `gmt_create`, `gmt_modified`, `gmt_modified_user`) VALUES (4, 't4', '14', '20', 4, '2018-10-10 20:34:03', NULL, NULL);

INSERT INTO `table2`(`kid`, `name`, `sponsor_id`, `type`, `gmt_create`, `gmt_modified`, `gmt_modified_user`) VALUES (1, 't1', '10', 1, '2018-10-10 20:38:10', NULL, NULL);INSERT INTO `table2`(`kid`, `name`, `sponsor_id`, `type`, `gmt_create`, `gmt_modified`, `gmt_modified_user`) VALUES (2, 't2', '10', 1, '2018-10-10 20:38:10', NULL, NULL);INSERT INTO `table2`(`kid`, `name`, `sponsor_id`, `type`, `gmt_create`, `gmt_modified`, `gmt_modified_user`) VALUES (3, 't3', '10', 1, '2018-10-10 20:38:10', NULL, NULL);INSERT INTO `table2`(`kid`, `name`, `sponsor_id`, `type`, `gmt_create`, `gmt_modified`, `gmt_modified_user`) VALUES (4, 't4', '10', 1, '2018-10-10 20:38:10', NULL, NULL);INSERT INTO `table2`(`kid`, `name`, `sponsor_id`, `type`, `gmt_create`, `gmt_modified`, `gmt_modified_user`) VALUES (5, 't5', '10', 1, '2018-10-10 20:38:10', NULL, NULL);INSERT INTO `table2`(`kid`, `name`, `sponsor_id`, `type`, `gmt_create`, `gmt_modified`, `gmt_modified_user`) VALUES (6, 't6', '10', 1, '2018-10-10 20:38:10', NULL, NULL);INSERT INTO `table2`(`kid`, `name`, `sponsor_id`, `type`, `gmt_create`, `gmt_modified`, `gmt_modified_user`) VALUES (7, 't7', '10', 2, '2018-10-10 20:38:10', NULL, NULL);INSERT INTO `table2`(`kid`, `name`, `sponsor_id`, `type`, `gmt_create`, `gmt_modified`, `gmt_modified_user`) VALUES (8, 't1', '11', 1, '2018-10-10 20:38:10', NULL, NULL);

查询异常:

SELECT a.*, b.type FROM table1 a

LEFT JOIN table2 b ON a.sponsor_id = b.sponsor_id WHERE b.type = 1

AND a.sponsor_id = 10;

简单说明问题出现的原因:

MySQL left join 语句格式为: A LEFT JOIN B ON 条件表达式left join 是以A表为基础,A表即左表,B表即右表。

左表(A)的记录会全部显⽰,⽽右表(B)只会显⽰符合条件表达式的记录,如果在右表(B)中没有符合条件的记录,则记录不⾜的地⽅为NULL。

使⽤left join, A表与B表所显⽰的记录数为 1:1 或 1:0,A表的所有记录都会显⽰,B表只显⽰符合条件的记录。 但如果B表符合条件的记录数⼤于1条,就会出现1:n的情况,这样left join后的结果,记录数会多于A表的记录数。

所以解决办法 都是从⼀个出发点出发,使A表与B表所显⽰的记录数为 1:1对应关系。

解决⽅法:

使⽤⾮唯⼀标识的字段做关联1 DISTINCT

select DISTINCT(id) from a left join b on a.id=b.aid DISTINCT查询结果是 第⼀个表唯⼀的数据 重复的结果没显⽰出来

SELECT

DISTINCT(a.id), a.*, b.type FROM table1 a

LEFT JOIN table2 b ON a.sponsor_id = b.sponsor_id WHERE b.type = 1

AND a.sponsor_id = 10;

SELECT

DISTINCT a.*, b.type FROM table1 a

LEFT JOIN table2 b ON a.sponsor_id = b.sponsor_id WHERE b.type = 1

AND a.sponsor_id = 10;

2 GROUP BY

select * from a left join(select id from b group by id) as b on a.id=b.aid 拿出b表的⼀条数据关联 使A表与B表所显⽰的记录数为 1:1对应关系。

SELECT a.*, b.type FROM table1 a

LEFT JOIN ( SELECT * FROM table2 GROUP BY sponsor_id ) AS b ON a.sponsor_id = b.sponsor_id WHERE b.type = 1

AND a.sponsor_id = 10;

3 max取唯⼀

select * from a left join (select max(id) from table group by id) as b on a.id=b.aid 拿出b表的最后⼀条数据关联

SELECT a.*, b.type FROM

table1 a

LEFT JOIN ( SELECT MAX( kid ), type, sponsor_id FROM table2 GROUP BY sponsor_id ) AS b ON a.sponsor_id = b.sponsor_id WHERE b.type = 1

AND a.sponsor_id = 10;

4 IN巧⽤

SELECT a.* FROM table1 a WHERE

a.sponsor_id IN ( SELECT sponsor_id FROM table2 WHERE type = 1 AND sponsor_id = 10 );SELECT a.*, 1 FROM table1 a WHERE

a.sponsor_id IN ( SELECT sponsor_id FROM table2 WHERE type = 1 AND sponsor_id = 10 );

相信对于熟悉SQL的⼈来说,LEFT JOIN⾮常简单,采⽤的时候也很多,但是有个问题还是需要注意⼀下。假如⼀个主表M有多个从表的话A B C …..的话,并且每个表都有筛选条件,那么把筛选条件放到哪⾥,就得注意喽。⽐如有个主表M,卡号是主键。

卡号

客户号

622312345678100110016223123456781002100262231234567810031003

有个从表A,客户号、联系⽅式是联合主键,其中联系⽅式,1-座机,2-⼿机号码客户号联系⽅式1001100110021003

1211

联系号码010-7858618810123456010-837433010-837433

如果想要查询所有卡号对应的⼿机号码两个字段,很简单,SQL语句如下:

SELECT A.卡号,B.⼿机号码FROM A

LEFT JOIN B

ON A.客户号=B.客户号WHERE B.联系⽅式='2'

相信很多⼈这样写,估计实际⼯作中也会看到这样的语句,并不是说这么写⼀定会错误,实际SQL表达的思想⼀定是要符合业务逻辑的。

前⾯已经说清楚,所有卡号对应的⼿机号码。所有卡号,所以⾸先肯定以A表作为主表,并且左关联B表,这样A表所有的卡号⼀定会显⽰出来,但是如果B表的筛选条件放到最外层,这样就相当于将A表关联B表⼜做了⼀遍筛选,结果就是

卡号

⼿机号码

622312345678100118810123456

就会筛选出来这么⼀条数据,丢失了A表中其他的卡号。

实际⼯作中表结构肯定没这么简单,关联的表也会很多,当有很多条件时,最好这么写

SELECT A.卡号,B.⼿机号码FROM ALEFT JOIN (

SELECT * FROM B B.联系⽅式='2' )B

ON A.客户号=B.客户号

这么写的话,A表中的数据肯定会完全保留,⼜能与B表的匹配,不会丢失数据。PS:

1、表结构

表A 表B

2、Left Join

⽰例:2.1

Select * From A left join B on A.aid = B.bid;

left join是以A表的记录为基础的,A可以看成左表,B可以看成右表,left join是以左表为准的。 换句话说,左表A的记录将会全部表⽰出来,⽽右表B只会显⽰符合搜索条件的记录(例⼦中为: A.aid = B.bid),B表记录不⾜的地⽅均为NULL.

A表所有记录都会显⽰,A表中没有被匹配的⾏(如aid=5、6的⾏)相应内容则为NULL。

返回的记录数⼀定⼤于A表的记录数,如A表中aid=7⾏被B表匹配了3次(因为B表有三⾏bid=7)。

注意:在Access中A.aid、B.bid不能缩写成aid、bid,否则会提⽰“不⽀持链接表达式”,这⼀点不同于Where查询。

3、Right Join

⽰例:3.1

Select * From A right join B on A.aid = B.bid;

仔细观察⼀下,就会发现,和left join的结果刚好相反,这次是以右表(B)为基础的,A表不⾜的地⽅⽤NULL填充。

4、Inner Join

⽰例:4.1

Select * From A inner join B on A.aid = B.bid;

这⾥只显⽰出了 A.aid = B.bid的记录.这说明inner join并不以谁为基础,它只显⽰符合条件的记录。inner join 等同于Where查询如:

Select * From A, B Where A.aid = B.bid

5、表的关联修改和删除

5.1修改⽰例:5.1.1

update A left join B on A.aid = B.bidset A.aname = B.bname

上述SQL实际操作的表为\"Select * From A left join B on A.aid = B.bid\",因此Access会提⽰更新13条记录(Select查询出的记录就是13条)。对⽐“⽰例:2.1”返回的结果,分析update后的A表:

aid=5、6的记录,被更新为NULL

aid=7的记录,被更新了3次,依次是“b1997-1”、“b1997-2”、“b1997-3”,因此其结果为最后⼀次更新“b1997-3”

对于上述SQL同样可以将“A.aname = B.bname”改成“B.bname = A.aname”,执⾏后B表将会被修改,但是执⾏后B表会增加三⾏“0, a2005-1;0, a2005-2;0,a2006”,这也不难理解,因为Left Join执⾏后,B表会出现三⾏空值。⽰例:5.1.2

Where条件查询在上⾯的SQL中同样可以使⽤,其作⽤的表也是Select查询出的关联表。如下SQL

update A left join B on A.aid = B.bidset A.aname = B.bnamewhere A.aid <> 5

执⾏后A表的结果:

对⽐第⼀次update可以发现,aid=5的并没有被更新。

这⾥只讲述left join,因为right join 和 inner join的处理过程等同于left join。另外Access中update语句中不能含有From关键字,这⼀点不同于其他数据库。5.2删除

在Access中是不可以通过Left Join、Right Join、Inner Join来删除某张表的记录⽰例:5.2.2

Delete From A inner join B on A.aid = B.bidwhere B.bname = \"b1991\"

上述SQL的本意是删除A表中aid=1的记录,但执⾏后表A和表B均未发⽣任何变化。若想实现此⽬的,下述SQL可以实现

Delete From A

Where A.aid In (Select bid From B Where B.bname=\"b1991\")

6、笛卡尔积

如果A表有20条记录,B表有30条记录,则⼆者关联后的笛卡尔积⼯20*30=600条记实录。也就是说A表中的每条记录都会于B表的所有记录关联⼀次,三种关联⽅式实际上就是对“笛卡尔积”的处理⽅式不同。

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 99spj.com 版权所有 湘ICP备2022005869号-5

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务