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 

我该如何解决?

4

3 回答 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,根据需要分组。第二个选择将返回每个第一组所需的amt值。id这些结果之间的左连接将给出所需的结果。由于性能问题,已将表添加t_main到第二个选择中。

另一种解决方案如下:

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结果连接的每一行执行内联。在大表的情况下,第二个解决方案的性能将比第一个更差。

于 2013-10-28T08:54:33.873 回答
6

由于很可能存在多种关系,您的新左外连接会强制在结果集中多次返回某些行。删除您的 SUM 并查看返回的行并准确计算出您需要哪些行(如果适用,可能会将其限制在特定类型的 t_ind 记录上??),然后相应地调整您的查询。

于 2013-10-28T05:37:01.523 回答
1

左外连接 - 驱动表行数

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

使用 MS SQL 服务器:

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

这给出了:

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

驱动表(t1)有 5 行,但返回 6 行,因为 id 2 有多个匹配项。

因此,如果使用按驱动表列分组的聚合函数,例如 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)。

对于多个表的左外连接,连接子句中表的顺序至关重要。

于 2018-06-05T11:14:42.847 回答