【问题标题】:TSQL Query 12 months of Data - Include Months without recordsTSQL 查询 12 个月的数据 - 包括没有记录的月份
【发布时间】:2017-03-13 19:16:08
【问题描述】:

我正在尝试为这 12 个月期间每个月提交的所有问题创建一个 12 个月的网格视图。

SELECT 
    YEAR(h.metaInsert) [Year], 
    MONTH(h.metaInsert) [Month], 
    DATENAME(MONTH,h.metaInsert) [Month Name], 
    COUNT(1) [Total Documents]
FROM 
    Document_Count_History AS h
WHERE 
    YEAR(h.metaInsert) = 2017
GROUP BY 
    YEAR(h.metaInsert), MONTH(h.metaInsert), DATENAME(MONTH, h.metaInsert)
ORDER BY 
    1, 2

这会完美地返回拥有它的月份的数据,但对于那些在该特定月份有 0 条记录的人,我没有返回任何数据。

我的目标是查看所有 12 个月以及文档数量。如果没有文档,则该月只是一个 0,但它会包含在结果集中。

我怎样才能拿走我所拥有的并应用缺少的月份?

【问题讨论】:

  • 您需要LEFT JOIN 和月份列表。

标签: sql-server tsql stored-procedures sql-server-2012


【解决方案1】:

您可以使用类似的方法为您的查询生成月份序列:

declare @StartDate     date = '20170101'
       ,@NumberOfYears int  = 1;

;with Months as (
select top (12*@NumberOfYears) 
    [Month] = dateadd(Month, row_number() over (order by number) -1, @StartDate)
   , NextMonth = dateadd(Month, row_number() over (order by number), @StartDate)
  from master.dbo.spt_values
)

select 
    year(m.Month) [Year], 
    Month(m.Month) [Month], 
    datename(Month,m.Month) [Month Name], 
    count(h.*) [Total Documents]

from Months as m
  left join Document_Count_History AS h
    on h.metaInsert >= m.Month
   and h.metaInsert < m.NextMonth
--where h.metaInsert >= '20170101'
group by m.Month
order by m.Month

虽然您可能需要考虑添加日历表或日期维度。

日历和数字表参考:

示例月份表:

create table dbo.Months(
    MonthStart date not null primary key
  , NextMonthStart date not null
  , [Year] smallint not null
  , [Month] tinyint not null
  , [MonthName] varchar(16) not null
);

declare @StartDate     date = '20100101'
       ,@NumberOfYears int  = 30;

insert dbo.Months(MonthStart,NextMonthStart,[Year],[Month])
  select top (12*@NumberOfYears) 
    [MonthStart] = dateadd(month, row_number() over (order by number) -1, @StartDate)
    , NextMonthStart = dateadd(month, row_number() over (order by number), @StartDate)
    , [year] = year(dateadd(month, row_number() over (order by number) -1, @StartDate))
    , [Month] = Month(dateadd(month, row_number() over (order by number) -1, @StartDate))
    , MonthName =  datename(Month,dateadd(month, row_number() over (order by number) -1, @StartDate))
  from master.dbo.spt_values;

您的查询将简化为:

select 
    m.[Year], 
    m.[Month], 
    m.[MonthName], 
    count(h.*) [Total Documents]
from Months as m
  left join Document_Count_History AS h
    on h.metaInsert >= m.MonthStart
   and h.metaInsert < m.NextMonthStart
where m.Year = 2017
group by m.Month, m.Year, m.MonthName
order by m.MonthStart

【讨论】:

  • 现在测试这个 - 不是提供开始日期,我可以只过一年吗?我一次只需要看一年,所以我认为这会用startDatenumberOfYears 逻辑清理
  • 您可以使用 Months 表进一步简化逻辑,而不是每次需要时都生成它。 @SBB
  • 我找到了我们正在使用的日历表,但它不包含下个月的开始。尝试将此添加到我的加入中:` 和 h.metaInsert
  • @SBB 如果您的日历是单独的日期,那么它将是on h.metaInsert &gt;= c.Date and h.metaInsert &lt; dateadd(day,1,c.Date),而group by 负责将其汇总到年和月。除非h.metaInsertdate 类型,否则您可以使用h.metaInsert = c.Date
  • @SBB 乐于助人!
【解决方案2】:

您需要一个日期维度。具体来说,您需要一个包含月份所有值的表。然后,您可以在获取总数的表上进行左连接,并提取一个总和值。

【讨论】:

    猜你喜欢
    • 2015-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-10
    • 1970-01-01
    相关资源
    最近更新 更多