与聚合的多个连接

时间:2015-11-02 13:30:05

标签: sql sql-server tsql

我有以下两个表格:

人:

EntityId    FirstName          LastName
----------- ------------------ -----------------
1           Ion                Ionel
2           Fane               Fanel
3           George             Georgel
4           Mircea             Mircel

SalesQuotaHistory

SalesQuotaId EntityId    SalesQuota  SalesOrderDate
------------ ----------- ----------- -----------------------
1            1           1000        2014-01-01 00:00:00.000
2            1           1000        2014-01-02 00:00:00.000
3            1           1000        2014-01-03 00:00:00.000
4            3           3000        2013-01-01 00:00:00.000
5            3           3000        2013-01-01 00:00:00.000
7            4           4000        2015-01-01 00:00:00.000
8            4           4000        2015-01-02 00:00:00.000
9            4           4000        2015-01-03 00:00:00.000
10           1           1000        2015-01-01 00:00:00.000
11           1           1000        2015-01-02 00:00:00.000

我想在2014年和2015年为每个用户获取SalesQuota。

使用此查询我得到一个错误的结果:

SELECT p.EntityId
  , p.FirstName
  , SUM(sqh2014.SalesQuota) AS '2014'
  , SUM(sqh2015.SalesQuota) AS '2015'
FROM Person p
LEFT OUTER JOIN SalesQuotaHistory sqh2014
   ON p.EntityId = sqh2014.EntityId
    AND YEAR(sqh2014.SalesOrderDate) = 2014
LEFT OUTER JOIN SalesQuotaHistory sqh2015
   ON p.EntityId = sqh2015.EntityId
    AND YEAR(sqh2015.SalesOrderDate) = 2015
    GROUP BY p.EntityId, p.FirstName

   EntityId    FirstName      2014        2015
   ---------   -----------   ----------   --------------------
    1          Ion           6000         6000
    2          Fane          NULL         NULL
    3          George        NULL         NULL
    4          Mircea        NULL         12000

事实上,Id 1在2014年的总销售额为3000,在2015年为2000.

我在这里问的是......幕后真的发生了什么?在这种特定情况下的操作顺序是什么?

感谢我上一篇文章,我能够使用以下查询解决这个问题:

SELECT p.EntityId
   , p.FirstName
   , SUM(CASE WHEN YEAR(sqh.SalesOrderDate) = 2014 THEN sqh.SalesQuota ELSE 0 END) AS '2014'
   , SUM(CASE WHEN YEAR(sqh.SalesOrderDate) = 2015 THEN sqh.SalesQuota ELSE 0 END) AS '2015'
FROM Person p
LEFT OUTER JOIN SalesQuotaHistory sqh
   ON p.EntityId = sqh.EntityId
   GROUP BY p.EntityId, p.FirstName


EntityId    FirstName             2014        2015
----------- --------------------- ----------- -----------
1           Ion                   3000        2000
2           Fane                  0           0
3           George                0           0
4           Mircea                0           12000

但是没有理解第一次尝试的错误......我无法克服这个......

非常感谢任何解释。

3 个答案:

答案 0 :(得分:2)

如果您将选择更改为

,很容易看到发生了什么
SELECT *

并删除group by

你首先需要这样的东西

<强> Sql Fiddle Demo

SELECT p.[EntityId]
  , p.FirstName
  , COALESCE(s2014,0) as [2014]
  , COALESCE(s2015,0) as [2015]
FROM Person p
LEFT JOIN (SELECT EntityId, SUM(SalesQuota) s2014
           FROM SalesQuotaHistory 
           WHERE YEAR(SalesOrderDate) = 2014
           GROUP BY EntityId
          ) as s1
      ON p.[EntityId] = s1.EntityId
LEFT JOIN (SELECT EntityId, SUM(SalesQuota) s2015
           FROM SalesQuotaHistory 
           WHERE YEAR(SalesOrderDate) = 2015
           GROUP BY EntityId
          ) as s2
      ON p.[EntityId] = s2.EntityId

仅在存在idyear的情况下才加入结果数据。

<强>输出

| EntityId | FirstName | 2014 |  2015 |
|----------|-----------|------|-------|
|        1 |       Ion | 3000 |  2000 |
|        2 |      Fane |    0 |     0 |
|        3 |    George |    0 |     0 |
|        4 |    Mircea |    0 | 12000 |

答案 1 :(得分:1)

每年有多行,因此第一种方法是生成笛卡尔积。

例如,考虑EntityId 100:

1            1           1000        2014-01-01 00:00:00.000
2            1           1000        2014-01-02 00:00:00.000
3            1           1000        2014-01-03 00:00:00.000
10           1           1000        2015-01-01 00:00:00.000
11           1           1000        2015-01-02 00:00:00.000

联接的中间结果产生六行,其中包含SalesQuotaId

1     10
1     11
2     10
2     11
3     10
3     11

然后你可以做数学 - 由于多行,结果就会消失。

您似乎知道如何解决问题。条件聚合方法产生正确的答案。

答案 2 :(得分:1)

您可以通过添加WHERE条件来仅提高您查找数据的年份来提高查询速度:

SELECT p.EntityId
   , p.FirstName
   , SUM(CASE WHEN YEAR(sqh.SalesOrderDate) = 2014
         THEN sqh.SalesQuota ELSE 0 END) AS '2014'
   , SUM(CASE WHEN YEAR(sqh.SalesOrderDate) = 2015 
         THEN sqh.SalesQuota ELSE 0 END) AS '2015'
FROM Person p
LEFT OUTER JOIN SalesQuotaHistory sqh
   ON p.EntityId = sqh.EntityId
WHERE YEAR(sqh.SalesOrderDate) IN (2014, 2015)
GROUP BY p.EntityId, p.FirstName

否则,您找到的查询是可行的方法(干得好!)

相关问题