首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > SQL Server >

left jion sum有关问题

2012-09-02 
left jion sum问题SQL code--测试数据如下create table tbla(typename varchar(50))insert into tblaselec

left jion sum问题

SQL code
--测试数据如下create table tbla(    typename varchar(50))insert into tblaselect 'dt-051' union allselect 'dt-052' union allselect 'dt-053' union allselect 'dt-054' union allselect 'dt-055' union allselect 'dt-056'create table tblb(    typename varchar(50),    num int,)insert into tblbselect 'dt-056',30 union allselect 'dt-056',20 union allselect 'dt-051',10 union allselect 'dt-052',30 union allselect 'dt-053',20 union allselect 'dt-051',30create table tblc(    typename varchar(50),    num int,)insert into tblcselect 'dt-056',30 union allselect 'dt-055',20 union allselect 'dt-056',20 union allselect 'dt-055',30 union allselect 'dt-051',50 union allselect 'dt-053',10select a.typename as 型号,sum(isnull(b.num,0)) as 共领料 from tbla as a left join tblb as b on b.typename = a.typename group by a.typenameorder by a.typename asc--结果没有问题/*dt-051    40dt-052    30dt-053    20dt-054    0dt-055    0dt-056    50*/select a.typename as 型号,sum(isnull(c.num,0)) as 共入库 from tbla as a left join tblc as c on c.typename = a.typename group by a.typenameorder by a.typename asc--结果没有问题/*dt-051    50dt-052    0dt-053    10dt-054    0dt-055    50dt-056    50*/--但是select a.typename as 型号,sum(isnull(b.num,0)) as 共领料,sum(isnull(c.num,0)) as 共入库 from tbla as a left join tblb as b on b.typename = a.typename left join tblc as c on c.typename = a.typename group by a.typename,b.typename,c.typenameorder by a.typename asc--结果就出现问题了/*dt-051    40    100dt-052    30    0dt-053    20    10dt-054    0    0dt-055    0    50dt-056    100    100*/--正常结果如下/*dt-051    40    50dt-052    30    0dt-053    20    10dt-054    0    0dt-055    0    50dt-056    50    50*/--问题出在哪--使用如下的sql语句 结果就是正确的 区别在哪求解释select a.typename,isnull(b.sumnum,0) as 共领料,isnull(c.sumnum,0) as 共入库from tbla as aleft join (select typename,sum(num) as sumnum from tblb group by typename)b on b.typename = a.typenameleft join (select typename,sum(num) as sumnum from tblc  group by typename)c on c.typename = a.typenameorder by a.typename asc--结果/*dt-051    40    50dt-052    30    0dt-053    20    10dt-054    0    0dt-055    0    50dt-056    50    50*/


[解决办法]
因为有2重一对多的关联,影响了最终的记录笔数.
以dt-051为例,
第一次left join tblb,是1笔(tbla的)*2笔(tblb的)得到2笔,
第二此left join tblc,是2笔(已关联得到的)*1笔(tblc的),
最终得到2笔入库num=50的,故错误结果里dt-051的入库=100.

[解决办法]
SQL code
--看如下sqlselect a.typename as 型号,isnull(b.num,0) as 共领料,isnull(c.num,0) as 共入库 from tbla as a left join tblb as b on b.typename = a.typename left join tblc as c on c.typename = b.typename --结果集如下型号                                                 共领料         共入库-------------------------------------------------- ----------- -----------dt-051                                             10          50dt-051                                             30          50dt-052                                             30          0dt-053                                             20          10dt-054                                             0           0dt-055                                             0           0dt-056                                             30          30dt-056                                             30          20dt-056                                             20          30dt-056                                             20          20(10 row(s) affected)--此时你在用sum,那么它的操作时累加的所以会出现这个问题
[解决办法]
提供另一种写法,
SQL code
create table tbla( typename varchar(50))insert into tblaselect 'dt-051' union allselect 'dt-052' union allselect 'dt-053' union allselect 'dt-054' union allselect 'dt-055' union allselect 'dt-056'create table tblb( typename varchar(50),  num int)insert into tblbselect 'dt-056',30 union allselect 'dt-056',20 union allselect 'dt-051',10 union allselect 'dt-052',30 union allselect 'dt-053',20 union allselect 'dt-051',30create table tblc( typename varchar(50),  num int)insert into tblcselect 'dt-056',30 union allselect 'dt-055',20 union allselect 'dt-056',20 union allselect 'dt-055',30 union allselect 'dt-051',50 union allselect 'dt-053',10select a.typename as 型号,       isnull(bb.outqty,0) as '共领料',       isnull(cc.inqty,0) as '共入库'from tbla as a outer apply(select sum(num) outqty from tblb as b             where b.typename=a.typename) bb outer apply(select sum(num) inqty from tblc as c             where c.typename=a.typename) cc/*型号                                                    共领料         共入库-------------------------------------------------- ----------- -----------dt-051                                             40          50dt-052                                             30          0dt-053                                             20          10dt-054                                             0           0dt-055                                             0           50dt-056                                             50          50(6 row(s) affected)*/ 


[解决办法]

SQL code
--对待这种问题,我建议先聚合然后再JOINWITH B AS(    SELECT typename,SUM(num) AS num FROM tblb GROUP BY typename),C AS(    SELECT typename,SUM(num) AS num FROM tblc GROUP BY typename)SELECT     A.typename,    ISNULL(B.num,0)  AS 共领料,    ISNULL(C.num,0) AS 共入库 FROM tbla AS ALEFT JOIN B    ON A.typename = B.typenameLEFT JOIN C    ON A.typename = C.typename        typename                                           共领料         共入库-------------------------------------------------- ----------- -----------dt-051                                             40          50dt-052                                             30          0dt-053                                             20          10dt-054                                             0           0dt-055                                             0           50dt-056                                             50          50(6 row(s) affected)
[解决办法]
要知道left join 的执行是先求笛卡尔积 然后再用WHERE条件过滤

你这里left join 了两次。造成了一对多的多次关联,SO。。
[解决办法]
要警惕多次left join可能带来的风险,看下面的结果你就明白了
SQL code
select *from tbla as a left join tblb as b on b.typename = a.typename left join tblc as c on c.typename = a.typename /*typename                                           typename                                           num         typename                                           num-------------------------------------------------- -------------------------------------------------- ----------- -------------------------------------------------- -----------dt-051                                             dt-051                                             10          dt-051                                             50dt-051                                             dt-051                                             30          dt-051                                             50dt-052                                             dt-052                                             30          NULL                                               NULLdt-053                                             dt-053                                             20          dt-053                                             10dt-054                                             NULL                                               NULL        NULL                                               NULLdt-055                                             NULL                                               NULL        dt-055                                             20dt-055                                             NULL                                               NULL        dt-055                                             30dt-056                                             dt-056                                             30          dt-056                                             30dt-056                                             dt-056                                             30          dt-056                                             20dt-056                                             dt-056                                             20          dt-056                                             30dt-056                                             dt-056                                             20          dt-056                                             20(11 row(s) affected)*/
[解决办法]
第一种SQL语句是先联合再汇总,而第二种SQL语句是先汇总再联合。
以dt-051为例,tbla联合tblb时是两条条记录,如下所示:
dt-05110
dt-05130
dt-05230
dt-05320
dt-054NULL
dt-055NULL
dt-05630
dt-05620
再联合tblc时,还是两条记录,如下所示,这样汇总tblc的[num]列就会翻倍。


dt-0511050
dt-0513050
dt-05230NULL
dt-0532010
dt-054NULLNULL
dt-055NULL20
dt-055NULL30
dt-0563030
dt-0563020
dt-0562030
dt-0562020。
而第二种语句汇总后再联合就不会有这种问题。
[解决办法]
楼上的已经很详细了,希望楼主顺利解决问题。
[解决办法]
简单的是说就是它 join b 的结果再去和c join

最近sql 板块有活跃起来了哈。

热点排行