多张表进行左外连接

4

我有以下SQL语句:

    select  
    a.desc
   ,sum(bdd.amount)
   from t_main c 
   left outer join t_direct bds on (bds.repid=c.id) 
   left outer join tm_defination def a on (a.id =bds.sId)
   where c.repId=1000000134
   group by a.desc;

当我运行它时,我得到了以下结果:
   desc       amount
   NW         12.00
   SW         10

当我尝试添加另一个左外连接来获取另一组值时:
   select  
    a.desc
   ,sum(bdd.amount)
   ,sum(i.amt)
   from t_main c 
   left outer join t_direct bds on (bds.repid=c.id) 
   left outer join tm_defination def a on (a.id =bdd.sId)
   left outer join t_ind i on (i.id=c.id)
   where c.repId=1000000134
   group by a.desc;

它基本上将数量字段加倍,如下所示:
         desc    amount   amt
         NW       24.00   234.00
         SE       20.00   234.00

虽然结果应该是:

        desc   amount   amt
        NW      12.00   234.00
        SE      10.00   NULL 

我该怎么解决这个问题?

您在使用表别名时使用了“bds”,但在查询中却使用了“bdd”,这可能会导致问题。 - Deepika Janiyani
谢谢,我已经纠正了。这是在发布时打错的。 - J. Davidson
1
问题可能是因为您正在对左外连接的一部分a字段进行分组。尝试在SELECT部分和GROUP BY部分都添加c.id - GregHNZ
3个回答

7
如果您确实需要按照所述接收数据,则可以使用子查询执行所需的计算。在这种情况下,您的代码可能如下所示:
select x.[desc], x.amount, y.amt
from
(
    select
         c.[desc]
       , sum (bdd.amount) as amount
       , c.id
    from t_main c 
    left outer join t_direct bds on (bds.repid=c.id) 
    left outer join tm_defination_def bdd on (bdd.id = bds.sId)
    where c.repId=1000000134
    group by c.id, c.[desc]
) x
left join
(
    select t.id, sum (t.amt) as amt 
    from t_ind t
    inner join t_main c
      on t.id = c.id
    where c.repID = 1000000134
    group by t.id
) y 
 on x.id = y.id

在第一个子查询中,您将获得前两列descamount的汇总数据,按所需进行分组。 第二个select将为第一个集合中每个id返回所需的amt值。 这些结果之间的左连接将给出所需的结果。添加t_main表到第二个select是因为性能问题。 另一种解决方案如下:
select
     c.[desc]
   , sum (bdd.amount) as amount
   , amt = (select sum (amt) from t_ind where id = c.id)
from #t_main c 
left outer join t_direct bds on (bds.repid=c.id) 
left outer join tm_defination_def bdd on (bdd.id = bds.sId)
where c.repId = 1000000134
group by c.id, c.[desc]

结果将是相同的。基本上,计算amt总和不再使用嵌套查询,而是针对结果联接的每一行执行内联计算。在处理大型表时,第二种解决方案的性能将会比第一种更差。

6

你的新左连接由于多个关系,可能会强制返回一些行多次出现在结果集中。移除SUM函数,仅检查返回的行,并确定您需要哪些行(如果适用,可以将其限制为某种类型的t_ind记录),然后相应地调整查询。


1

左外连接 - 驱动表行数

如果连接条件上有多个匹配项,左外连接可能返回比驱动表中更多的行。

使用 MS SQL-Server:

DECLARE @t1 TABLE ( id INT )
INSERT INTO @t1 VALUES ( 1 ),( 2 ),( 3 ),( 4 ),( 5 );

DECLARE @t2 TABLE ( id INT )
INSERT INTO @t2 VALUES ( 2 ),( 2 ),( 3 ),( 10 ),( 11 ),( 12 );

SELECT * FROM @t1 t1
LEFT OUTER JOIN @t2 t2 ON t2.id = t1.id

This gives:

1   NULL
2   2
2   2
3   3
4   NULL
5   NULL

在驾驶表(t1)中有5行,但由于id为2的多个匹配项,返回了6行。
因此,如果使用聚合函数(例如SUM()等)按驾驶表列分组,将得到错误的结果。
要解决这个问题,使用派生表或子查询来计算聚合值,如已经说明的那样。
左外连接 - 多个表
当存在多个表的左外连接或任何连接时,查询会按连接顺序生成一系列派生表。
SELECT * FROM t1
LEFT OUTER JOIN t2 ON t2.col2 = <...>
LEFT OUTER JOIN t3 ON t3.col3 = <...>

这相当于:
SELECT * FROM
(
   SELECT * FROM t1
   LEFT OUTER JOIN t2 ON t2.col2 = <...>
) dt1
LEFT OUTER JOIN t3 ON t3.col3 = <...>

在这里,对于两个查询,第一个左外连接的结果被放入一个派生表(dt1)中,然后再与第三个表(t3)进行左外连接。

对于多个表的左外连接,连接子句中表的顺序非常关键。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接