【问题标题】:Data aggregation with left-outer join具有左外连接的数据聚合
【发布时间】:2015-03-11 15:15:31
【问题描述】:

我正在尝试按分支、按周提取一些带有事务计数的数据,这些数据稍后将用于提供一些动态 .Net 图表。

我有一个日历表、一个分支表和一个事务表。

这是我的数据库信息(仅包括相关列):

分支表:

ID (int), Branch (varchar)

日历表:

Date (datetime), WeekOfYear(int)

交易表:

Date (datetime), Branch (int), TransactionCount(int)

所以,我想做如下的事情:

Select b.Branch, c.WeekOfYear, sum(TransactionCount)
FROM BranchTable b
LEFT OUTER JOIN TransactionTable t
    on t.Branch = b.ID
JOIN Calendar c
    on t.Date = c.Date
WHERE YEAR(c.Date) = @Year // (SP accepts this parameter)
GROUP BY b.Branch, c.WeekOfYear

现在,EXCEPT 可以在分支一周内没有任何交易时起作用,在这种情况下,该分支在该周返回 NO RECORD。我想要是获得那个分支,那周和总和为“0”。我试过 isnull(sum(TransactionCount), 0) - 但这也没有用。所以我会得到以下信息(为了说明目的,总结一下):

+--------+------------+-----+
| Branch | WeekOfYear | Sum |
+--------+------------+-----+
|      1 |          1 |  25 |
|      2 |          1 |  37 |
|      3 |          1 |  19 |
|      4 |          1 |   0 |  //THIS RECORD DOES NOT GET RETURNED, BUT I NEED IT!
|      1 |          2 |  64 |
|      2 |          2 |  34 |
|      3 |          2 |  53 |
|      4 |          2 |  11 |
+--------+------------+-----+

那么,为什么左外连接不起作用?不应该这样吗

任何帮助将不胜感激。谢谢!

编辑:样本表数据:

Branch表:

+----+---------------+
| ID |    Branch     |
+----+---------------+
|  1 | First Branch  |
|  2 | Second Branch |
|  3 | Third Branch  |
|  4 | Fourth Branch |
+----+---------------+

Calendar表:

+------------+------------+
|    Date    | WeekOfYear |
+------------+------------+
| 01/01/2015 |          1 |
| 01/02/2015 |          1 |
+------------+------------+

Transaction

+------------+--------+--------------+
|    Date    | Branch | Transactions |
+------------+--------+--------------+
| 01/01/2015 |      1 |           12 |
| 01/01/2015 |      1 |            9 |
| 01/01/2015 |      2 |            4 |
| 01/01/2015 |      2 |            2 |
| 01/01/2015 |      2 |           23 |
| 01/01/2015 |      3 |           42 |
| 01/01/2015 |      3 |           19 |
| 01/01/2015 |      3 |            7 |
+------------+--------+--------------+

【问题讨论】:

  • JOIN Calendar c也改成LEFT JOIN Calendar c
  • 您需要创建每个分支和周的完整列表,然后将其加入事务。
  • 我不知道该怎么做 - 分支表和日历表没有任何要加入的列
  • @Darka - 我试过了,但得到了相同的结果。
  • 您可以使用每个表格中的一些示例数据来编辑您的帖子吗?

标签: sql sql-server group-by outer-join


【解决方案1】:

如果您想返回一个包含每个分支和每周的查询,那么您需要首先创建一个完整的列表,然后对事务使用 LEFT JOIN 来获取计数。代码将类似于:

select bc.Branch, 
   bc.WeekOfYear, 
   TotalTransaction = coalesce(sum(t.TransactionCount), 0)
from
(
  select b.id, b.branch, c.WeekOfYear, c.date
  from branch b
  cross join Calendar c
  -- if you want to limit the number of rows returned use a WHERE to limit the weeks
  -- so far in the year or using the date column
  WHERE c.date <= getdate()
   and YEAR(c.Date) = @Year // (SP accepts this parameter)
) bc
left join TransactionTable t
  on t.Date = bc.Date
  and bc.id = t.branch
GROUP BY bc.Branch, bc.WeekOfYear

See Demo

此代码将在您的子查询中创建包含每个日期的每个分支的完整列表。获得此列表后,您可以加入交易以获取总交易计数,并且您可以根据需要返回每个日期。

【讨论】:

  • 一开始我也在考虑 CROSS JOIN,但他确实想限制他看到的日历记录,所以以 WHERE 子句作为连接条件的 INNER JOIN 似乎更合适。
  • 起初我认为这看起来很接近,但是当我想要 12 条记录时,此查询返回 265 条记录(4 个分支,2015 年迄今为 3 周)
  • @Stan 您可以通过在子查询上使用 where 子句来限制日历日期的数量 - 如果您只需要一年中的前几周,则包括 where weekofyear &lt; 4 或过滤 c.date将其与 getdate() 进行比较的列 -- 参见这个演示 -- sqlfiddle.com/#!3/318b3/7
  • @JoelCoehoorn INNER JOIN 执行与 CROSS JOIN 相同的功能,因为您没有将 branch 表连接到特定列上的 calendar 表 - 请参阅此演示 sqlfiddle.com/#!3/318b3/8 - 他们需要使用像我的编辑这样的额外过滤器来限制今年迄今为止的行数或过滤某些周。
  • 伙计们,看看乔尔的回答。这正是我所需要的。感谢您的帮助!
【解决方案2】:

在您引入交易之前引入日历:

SELECT b.Branch, c.WeekOfYear, sum(TransactionCount)
FROM BranchTable b 
INNER JOIN CalendarTable c ON YEAR(c.Date) = @Year
LEFT JOIN TransactionTable t ON t.Branch = b.ID AND t.Date = c.Date
GROUP BY b.Branch, c.WeekOfYear
ORDER BY c.WeekOfYear, b.Branch

【讨论】:

  • 我会测试一下。我要到下周才能回来工作,但如果可行,我一定会重新访问此页面并接受您的回答。
  • 这很好用!我必须做的唯一改变是 isnull(sum(TransactionCount), 0)
  • 您在此查询中遇到语法错误。它将在 ORDER BY 上引发错误。
  • 这是如何工作的,您不能在order by 中使用B.id。它会抛出 B.id is invalid in the ORDER BY... 顺便说一句不是我的 DV
  • 取决于您的数据库引擎。 Sql Server 非常乐意在 ORDER BY 子句中使用表别名。
猜你喜欢
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-07
  • 1970-01-01
  • 2018-03-15
相关资源
最近更新 更多