【问题标题】:How to get the date for the previous month which are closed in the current month如何获取本月关闭的上个月的日期
【发布时间】:2014-06-11 07:04:38
【问题描述】:

我正在使用 SSRS 报告构建器应用程序为我的系统创建 BI 报告,该报告跟踪每个月记录和关闭的事件数量。

下面是我需要创建查询的表

Month      Logged  Received  Closed  Remaining
January    200     220       150     70
February   150     220       200     20
March      110     130       100     30
April      200     230       200     30

每列定义如下:

Logged= 当月打开事件,例如从 2014 年 1 月 1 日到 2014 年 1 月 31 日打开(仅包含当月数据)

已收到 = 已记录的事件 + 前几个月的未关闭事件,例如当前月份的 2 月为 150 + 上个月剩余的 70 将给我总共收到的 220。

Closed=本月开启本月关闭的事件+上个月本月关闭的剩余事件

Remaining= 已收到 - 已关闭

我使用的代码没有给我前几个月的关闭事件,它也只给了我当月关闭的事件

以下是我用于查询的代码:

SELECT  group_id, YEAR(Opendate) AS Year, MONTH(Opendate) AS Month,
        COUNT(CASE WHEN Month(Closedate) = Month(Opendate)
            AND Month(closedate)> Month (opendate) THEN 1 ELSE NULL END) AS closed, 
        COUNT(*) AS Logged, 
FROM    Incidents
WHERE   (Opendate >= @YearStart) AND (Opendate <= @YearEnd)
GROUP BY YEAR(Opendate), MONTH(Opendate), group_id
ORDER BY Year, Month,group_id 

Logged 在已关闭、已接收和剩余的情况下工作正常。


我尝试使用Union 并获得了记录和关闭的数据

Select count(*) logged,year(opendate) as year1,MONTH(opendate) as 
month1,'Logged' as status1
From Incidents 
where opendate is not null 
GROUP BY year(opendate),MONTH(opendate)
UNION 
Select count(*) closed,year(Closedate) as year1,MONTH(Closedate) as 
month1,'All_Closed' as status1
From Incidents 
where Closedate is not null
GROUP BY year(Closedate),MONTH(Closedate)
UNION 
Select count(*) Remaining,year(opendate) as year1,MONTH(opendate) as 
month1,'Current_Month_Not_Closed' as status1
From Incidents 
where Month(Closedate) > MONTH(Opendate)
GROUP BY year(opendate),MONTH(opendate)
UNION 
Select count(*) Month_Closed,year(opendate) as year1,MONTH(opendate) as 
month1,'Current_Month_Close' as status1
From Incidents 
where MONTH(Closedate) = MONTH(Opendate)  
GROUP BY year(opendate),MONTH(opendate)
order by year1,month1

我收到的数据如下:

logged | year1 | month1 | status1
-------+-------+--------+-------------------------
  1093 |  2014 |      1 | Logged
  1089 |  2014 |      1 | All_Closed
   997 |  2014 |      1 | Current_Month_Close
    96 |  2014 |      1 | Current_Month_Not_Closed
  1176 |  2014 |      2 | Logged
  1176 |  2014 |      2 | All_Closed
    91 |  2014 |      2 | Current_Month_Not_Closed
  1085 |  2014 |      2 | Current_Month_Close
  1340 |  2014 |      3 | Logged
  1327 |  2014 |      3 | All_Closed
   107 |  2014 |      3 | Current_Month_Not_Closed
  1232 |  2014 |      3 | Current_Month_Close
   116 |  2014 |      4 | Current_Month_Not_Closed
  1320 |  2014 |      4 | Current_Month_Close
  1424 |  2014 |      4 | All_Closed
  1441 |  2014 |      4 | Logged
  1167 |  2014 |      5 | Current_Month_Close
   105 |  2014 |      5 | Current_Month_Not_Closed
  1277 |  2014 |      5 | Logged
  1283 |  2014 |      5 | All_Closed

【问题讨论】:

  • 我会努力更新你的

标签: sql sql-server-2008 reporting-services


【解决方案1】:

为了获得可靠的数据,将日历表作为锚点可以提供帮助,如果门票可以在其开放日期后几个月内有效,或者可能有一个月没有创建门票,则需要使用日历表。

以假数据为例

CREATE TABLE Incidents (
  id int identity(1, 1)
, group_id nvarchar(100)
, Opendate Datetime
, Closedate Datetime
)

INSERT INTO Incidents
VALUES ('Service Desk', '20140107', '20140120')
     , ('Service Desk', '20140117', '20140123')
     , ('Service Desk', '20140127', '20140313')
     , ('Service Desk', '20140310', '')
-- from an OP comment the open tickets have the Closedate '' (1900-01-01)

如果没有日历表(或临时表或 CTE),则无法在结果集中添加 2 月,即使该月的第三条记录是“已接收”和“剩余”。

创建日历有多种方法,在这种情况下,我们需要一些关于月份的信息,但不需要关于天的信息,因此不会生成这些信息。

declare @YearStart date = '20140101'
declare @YearEnd date = '20140430'

;WITH D(N) AS (
          SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 
UNION ALL SELECT 8 UNION ALL SELECT 9
)
SELECT EOM
     = DATEADD(D, -1, DATEADD(M, u.N + 10 * t.N + 1
             , DATEADD(Y, DATEDIFF(Y, 0, @YearStart), 0)))
     , pMonth = u.N + 10 * t.N
FROM   D u
       CROSS JOIN D t
WHERE  u.N + 10 * t.N <= DATEDIFF(M, @YearStart, @YearEnd)

这里EOM是月底的日期,它将用于检查事件是否在当月结束,pMonth是从@YearStart开始的累进月份。

现在我们需要准备要使用的事件表中的数据

SELECT ID
     , OpenDate
     , Closedate = COALESCE(NULLIF(Closedate, ''), '99991231')
     , pOpenDate = DATEDIFF(M, @YearStart, OpenDate)
     , pClosedate = DATEDIFF(M, @YearStart
                  , COALESCE(NULLIF(Closedate, ''), '99991231'))
FROM   Incidents

Closedate 需要始终有一个高于 OpenDate 的值,因为这是使用常量日期 9999-12-31pOpenDatepClosedate,因为之前的 pMonth 是从 @ 开始的累进月份YearStart 分别为OpenDateClosedate

将这些放在一起就可以创建主查询

declare @YearStart date = '20140101'
declare @YearEnd date = '20140430'

;WITH D(N) AS (
          SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 
UNION ALL SELECT 8 UNION ALL SELECT 9
), CM AS (
  SELECT EOM
       = DATEADD(D, -1, DATEADD(M, u.N + 10 * t.N + 1
               , DATEADD(Y, DATEDIFF(Y, 0, @YearStart), 0)))
       , pMonth = u.N + 10 * t.N
  FROM   D u
         CROSS JOIN D t
  WHERE  u.N + 10 * t.N <= DATEDIFF(M, @YearStart, @YearEnd)
), I AS (
  SELECT ID
       , OpenDate
       , Closedate = COALESCE(NULLIF(Closedate, ''), '99991231')
       , pOpenDate = DATEDIFF(M, @YearStart, OpenDate)
       , pClosedate = DATEDIFF(M, @YearStart
                    , COALESCE(NULLIF(Closedate, ''), '99991231'))
  FROM   Incidents
)
SELECT MONTH(CM.EOM) [Month]
     , Logged = SUM(CASE WHEN pOpenDate = pMonth 
                         THEN 1 
                         ELSE 0 
                    END)
     , Received = Count(i.id)
     , Closed = SUM(CASE WHEN pClosedate = pMonth
                          AND i.Closedate < CM.EOM 
                         THEN 1 
                         ELSE 0 
                    END)
     , Remaining = SUM(CASE WHEN i.Closedate > CM.EOM
                            THEN 1 
                            ELSE 0 
                       END)
FROM   CM
       INNER JOIN I ON CM.pMonth
                    BETWEEN i.pOpenDate AND i.pClosedate
WHERE  CM.EOM <= @YearEnd
GROUP BY CM.EOM
ORDER BY CM.EOM

SQLFiddle Demo

使用JOIN@YearStart@YearEnd 之间的日历表中获取月份以及该月份中所有活动的事件。它们的属性是使用CASE 逻辑计算的,在Received 的情况下,如果票证处于活动状态,则它已被接收,因此不需要逻辑。

所有CASE都可以转换成BIT逻辑

declare @YearStart date = '20140101'
declare @YearEnd date = '20140430'

;WITH D(N) AS (
          SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 
UNION ALL SELECT 8 UNION ALL SELECT 9
), CM AS (
  SELECT EOM
       = DATEADD(D, -1, DATEADD(M, u.N + 10 * t.N + 1
               , DATEADD(Y, DATEDIFF(Y, 0, @YearStart), 0)))
       , pMonth = u.N + 10 * t.N
  FROM   D u
         CROSS JOIN D t
  WHERE  u.N + 10 * t.N <= DATEDIFF(M, @YearStart, @YearEnd)
), I AS (
  SELECT ID
       , OpenDate
       , Closedate = COALESCE(NULLIF(Closedate, ''), '99991231')
       , pOpenDate = DATEDIFF(M, @YearStart, OpenDate)
       , pClosedate = DATEDIFF(M, @YearStart
                    , COALESCE(NULLIF(Closedate, ''), '99991231'))
  FROM   Incidents
)
SELECT MONTH(CM.EOM) [Month]
     , Logged = SUM(1 - CAST(pOpenDate - pMonth AS BIT))
     , Received = Count(i.id)
     , Closed = SUM(1 - CAST(pClosedate - pMonth AS BIT))
     , Remaining = SUM(0 + CAST(i.pClosedate / (CM.pMonth + 1) AS BIT))
FROM   CM
       INNER JOIN I ON CM.pMonth
                 BETWEEN i.pOpenDate AND i.pClosedate
WHERE  CM.EOM <= @YearEnd
GROUP BY CM.EOM
ORDER BY CM.EOM;

SQLFiddle Demo

位逻辑基于CASTBIT 的工作方式:

  • 0 到 0
  • 其他一切都转到 1

基于此(使用 A 和 B 整数):

  • A = B 时,1 - CAST(A - B AS BIT) 为 1
  • A &gt; BCAST(A / (B + 1) AS BIT) 为1(0 + 是强制隐式转换为INT,因为BIT 不能是SUMmed)

【讨论】:

  • 试过上面的查询它没有给我所有的确切数据,记录,关闭,remainig,received
  • 我的事情不是从 '20140101 00:00:00' 到 '20140331 23:59:59'
  • 关闭函数应该是当月或前几个月打开的事件,但本月内关闭的事件不仅是同月打开和关闭的
  • 收到的是结转事件+当月登录
  • 其余为当月已收到事件-已关闭事件
【解决方案2】:

Received 将是在月底之前打开且在月初之前未关闭的票数。

count(case when OpenDate <= @EndOfMonth and 
                (@StartOfMonth >= CloseDate or CloseDate is null) then 1 end)
    as Received

关闭很简单:

count(case when CloseDate between @StartOfMonth and @EndOfMonth 
                then 1 end) as Closed

您应该能够弄清楚如何使用 Google 计算一个月的开始和结束。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多