TSQL - 如何找到日期之间缺少的月份?

时间:2014-10-20 21:35:25

标签: sql sql-server tsql

我有下表:

UserID | DeptNumber | BeginDate           | EndDate             |
123456 | 1000010001 | 2013-11-15 00:00:00 | 2014-04-24 00:00:00 |
789012 | 1000010002 | 2014-04-25 00:00:00 | 2014-07-01 00:00:00 |
345678 | 1000010003 | 2014-07-02 00:00:00 | NULL                |

我如何填写遗失的月份,以便我有这样的事情:

UserID | DeptNumber | Month
123456 | 1000010001 | 11 
123456 | 1000010001 | 12
123456 | 1000010001 | 1
123456 | 1000010001 | 2
123456 | 1000010001 | 3
789012 | 1000010002 | 4
789012 | 1000010002 | 5
789012 | 1000010002 | 6
345678 | 1000010003 | 7
345678 | 1000010003 | 8
345678 | 1000010003 | 9
345678 | 1000010003 | 10

2 个答案:

答案 0 :(得分:1)

如果enddate不为null且日期类似于'2014-10-30'那么这可能对您有所帮助

CREATE TABLE #tblName
  (
     UserID     INT,
     startdate  DATETIME,
     endate     DATETIME,
     DeptNumber BIGINT
  )

INSERT INTO #tblName
VALUES      (123456,'2013-11-15 00:00:00','2014-04-24 00:00:00',1000010001),
            (789012,'2014-04-25 00:00:00','2014-07-01 00:00:00',1000010002),
            (345678,'2014-07-02 00:00:00','2014-10-30 00:00:00',1000010003)

DECLARE @mindate DATETIME,
        @maxdate DATETIME

SELECT @mindate = Min(startdate),
       @maxdate = Max(endate)
FROM   #tblName;

WITH cte
     AS (SELECT @mindate startdate
         UNION ALL
         SELECT Dateadd(mm, 1, startdate) startdate
         FROM   cte
         WHERE  startdate <= @maxdate)
SELECT userid,
       DeptNumber,
       Datepart(mm, a.startdate) [Month]
FROM   cte a
       JOIN #tblName b
         ON a.startdate BETWEEN b.startdate AND b.endate 

输出

userid  DeptNumber  Month

123456  1000010001  11
123456  1000010001  12
123456  1000010001  1
123456  1000010001  2
123456  1000010001  3
123456  1000010001  4
789012  1000010002  5
789012  1000010002  6
345678  1000010003  7
345678  1000010003  8
345678  1000010003  9
345678  1000010003  10

答案 1 :(得分:1)

这应该适用于NULL结束日期,例如您提供的示例。

DECLARE @Data TABLE (UserID INT, DeptNumber BIGINT, BeginDate DATETIME, EndDate DATETIME)
INSERT @Data VALUES
    (123456, 1000010001, '2013-11-15', '2014-04-24'),
    (789012, 1000010002, '2014-04-25', '2014-07-01'),
    (345678, 1000010003, '2014-07-02', NULL)
DECLARE
    @MinDate DATETIME = (
        SELECT
            CONVERT(DATE, CONVERT(VARCHAR(10), YEAR(MIN(BeginDate)))
                + '-' + CONVERT(VARCHAR(10), MONTH(MIN(BeginDate)))
                + '-1') AS [Day]
        FROM @Data
    ), @MaxDate DATETIME = (SELECT DATEADD(YY, 2, MAX(EndDate)) FROM @Data)
;WITH Months AS (
    SELECT @MinDate AS [Day]
    UNION ALL
    SELECT 
        DATEADD(MM, 1, [Day])
    FROM Months
    WHERE DATEADD(MM, 1, [Day]) <= @MaxDate
)
    SELECT DISTINCT
        Users.UserID,
        Users.DeptNumber,
        MONTH([Day]) AS [Month]
    FROM Months
        CROSS JOIN @Data Users
        LEFT OUTER JOIN @Data Data
            ON (Users.UserID = Data.UserID AND Users.DeptNumber = Data.DeptNumber)
                AND (Data.BeginDate IS NULL OR Data.BeginDate >= [Day])
                AND (Data.EndDate IS NULL OR Data.EndDate <= [Day])
    WHERE Data.UserID IS NULL