年度标准化带来空值

时间:2013-08-30 10:36:41

标签: sql sql-server-2008

我有以下查询:

SELECT DISTINCT
    YEAR(DateRegistered) as Years,
    Months.[MonthName], 
    COUNT(UserID)as totalReg 
FROM 
    Months WITH(NOLOCK)
LEFT OUTER JOIN
    UserProfile WITH(NOLOCK)
ON 
    Months.MonthID = MONTH(DateRegistered)
AND
    DateRegistered > DATEADD(MONTH, -12,GETDATE())

GROUP BY YEAR(DateRegistered), Months.[MonthName]
ORDER BY Months.[MonthName]

正如您所知,这将永远带回12个月的数据。因此它正在运行,尽管此方法存在错误。

它在没有数据的月份创建Null值,现在记录应该存在(查询的整个点),但是Year字段带来Nulls,这是我不想要的。

现在我明白问题是因为没有数据,怎么知道哪一年?

所以我的问题是 - 有没有办法对此进行排序并替换空值?我怀疑我必须彻底改变我的方法论。

**YEAR**    **MONTH**             **TOTAL**
2013    April                   1
2013    August                  1
NULL    December                0
2013    February                8
2013    January                 1
2013    July                    1
NULL    June                    0
2013    March                   4
NULL    May                     0
NULL    November                0
NULL    October                 0
2012    September               3

4 个答案:

答案 0 :(得分:3)

如果您需要12个月的数据,请构建1到12之间的数字列表,并将其用作getdate()的偏移量:

with nums as (
      select 12 as level union all
      select level - 1
      from nums
      where level > 1
    )
 select YEAR(thedate) as Years,
        Months.[MonthName], 
        COUNT(UserID) as totalReg 
 FROM (select DATEADD(MONTH, - nums.level, GETDATE()) as thedate
       from nums
      ) mon12 left outer join
      Months WITH (NOLOCK)
      on month(mon12.thedate) = months.monthid left outer join
      UserProfile WITH (NOLOCK)
      ON Months.MonthID = MONTH(DateRegistered) and
         DateRegistered > DATEADD(MONTH, -12, GETDATE())
GROUP BY YEAR(thedate), Months.[MonthName]
ORDER BY Months.[MonthName];

我发现查询有些奇怪。您正在定义当前日期的范围。但是,您似乎在日历边界上将这些月分开。我还发现表months很尴尬。你为什么不只是使用datename()month()函数?

答案 1 :(得分:1)

试试这个:

;With dates as (
Select  DateName(Month, getdate()) as [Month],
        DatePart(Year, getdate()) as [Year],
        1 as Iteration

Union All

Select  DateName(Month,DATEADD(MONTH, -Iteration, getdate())),
        DatePart(Year,DATEADD(MONTH, -Iteration, getdate())),
        Iteration + 1

from dates
where  Iteration < 12
)
SELECT DISTINCT
        d.Year,
        d.Month as [MonthName], 
        COUNT(up.UserID)as totalReg 
FROM dates d
LEFT OUTER JOIN UserProfile up ON d.Month = DateName(DateRegistered)
                                And d.Year = DatePart(Year, DateRegistered)
GROUP BY d.Year, d.Month
ORDER BY d.Year, d.Month

答案 2 :(得分:0)

您必须首先计算派生表(或CTE)中的计数,然后加入

未经测试的:

SELECT 
    COALESCE(dt.Years, YEAR(DATEADD(MONTH, -Months.MonthID, GETDATE()))),
    Months.[MonthName], 
    COALESCE(dt.totalReg, 0) 
FROM 
    Months WITH(NOLOCK)
LEFT OUTER JOIN
 (
   SELECT 
       YEAR(DateRegistered) AS Years,
       MONTH(DateRegistered) AS Mon,
       COUNT(UserID)AS totalReg
   FROM UserProfile WITH(NOLOCK)
   WHERE DateRegistered > DATEADD(MONTH, -12,GETDATE())
   GROUP BY 
       YEAR(DateRegistered),
       MONTH(DateRegistered)
 ) AS dt
ON Months.MonthID = dt.mon
ORDER BY 1, Months.MonthID

我将订单更改为Months.MonthID而不是MonthName,并且我添加了年份,因为您的结果可能会有2012年和2013年的8月。

答案 3 :(得分:0)

这是我尝试解决方案:

declare @UserProfile table
(
    id bigint not null identity(1,1) primary key clustered
    , name nvarchar(32) not null
    , dateRegistered datetime not null default(getutcdate())
)
insert @UserProfile
select 'person 1', '2011-01-23'
union select 'person 2', '2013-01-01'
union select 'person 3', '2013-05-27'

declare @yearMin int, @yearMax int
select @yearMin = year(MIN(dateRegistered))
, @yearMax= year(MAX(dateRegistered))
from @UserProfile

;with monthCte as
(
    select 1 monthNo, DATENAME(month, '1900-01-01') Name
    union all
    select monthNo + 1, DATENAME(month, dateadd(month,monthNo,'1900-01-01'))
    from monthCte
    where monthNo < 12
)
, yearCte as
(
    select @yearMin yearNo
    union all
    select yearNo + 1
    from yearCte
    where yearNo < @yearMax
)
select y.yearNo, m.Name, COUNT(up.id) UsersRegisteredThisPeriod
from yearCte y
cross join monthCte m
left outer join @UserProfile up
    on year(up.dateRegistered) = y.yearNo
    and month(up.dateRegistered) = m.monthNo
group by y.yearNo, m.monthNo, m.Name
order by y.yearNo, m.monthNo 

SQL小提琴版:http://sqlfiddle.com/#!6/d41d8/6640