查找缺失的时间段并确定是否连续

时间:2015-03-05 14:57:18

标签: sql sql-server tsql

我目前正在制定一项要求,找出失踪期,然后确定它是否在失踪期之前是连续的

以下是我的示例表结构。

第一步:在以下示例表中查看最近6个月(2014 7 - 2014 12)。它错过了两个月8& 11.以第一个实例8开始。

第二步:从失去第一个实例开始的6个月后返回 - (2014 2- 2014 7) - 看看他们是否在任何月份失踪。如果否(一切都是连续的) - 如果是,则选择/包括此记录(缺少几个月) - 不要选择此记录。

Year   Month   
2014    1
2014    2
2014    3
2014    4
2014    5
2014    6
2014    7
2014    9
2014    10
2014    12

我可以选择最后6条记录并按行号分区,看看它是否缺少任何记录。但我不知道如何找到连续的,也选择缺失的时期。

我正在尝试在Transact-SQL中进行尽可能多的过滤,以便我可以专注于c#上的其他验证。

我创建的查询是为了找到第一个缺失的期间(未完成)

SELECT f.TYEAR,f.TMONTH, f.TMONTH+1 AS MISSING FROM #TEMPTABLE AS F
LEFT OUTER JOIN #TEMPTABLE AS F2 ON f.TMONTH+1 = f2.TMONTH
WHERE f2.TAXPERIOD IS NULL

注意:上面的例子可以跨越两个日历年的b / w。 2013 mm - 2014 mm

2 个答案:

答案 0 :(得分:0)

我认为下面的代码应该可行,但我还没有正确测试它。但是你会得到这个想法 -

DECLARE @TmpBaseTable TABLE ([Year] SMALLINT, [Month] TINYINT)
DECLARE @TmpSixMonthTable TABLE (TmpYear SMALLINT, TmpMonth TINYINT)
DECLARE @TmpDate DATE
DECLARE @MissingYear SMALLINT
DECLARE @MissingMonth TINYINT
DECLARE @TmpCount TINYINT


INSERT INTO @TmpBaseTable ([Year], [Month])
SELECT 2014, 1 UNION ALL
SELECT 2014, 2 UNION ALL
SELECT 2014, 3 UNION ALL
SELECT 2014, 4 UNION ALL
SELECT 2014, 5 UNION ALL
SELECT 2014, 6 UNION ALL
SELECT 2014, 7 UNION ALL
SELECT 2014, 8 UNION ALL
SELECT 2014, 9 UNION ALL
SELECT 2014, 10 UNION ALL
SELECT 2014, 11 UNION ALL
SELECT 2014, 12 UNION ALL
SELECT 2015, 1 UNION ALL
SELECT 2015, 3 UNION ALL
SELECT 2015, 4

SELECT TOP 1 @TmpDate = CAST(CAST(tmpYear AS VARCHAR) + '-' + CAST(tmpMonth AS VARCHAR) + '-' + CAST(1 AS VARCHAR) AS DATE)
FROM
(
    SELECT ROW_NUMBER() OVER(ORDER BY [Year], [Month]) AS RowID, [Month] AS tmpMonth, [Year] AS tmpYear
    FROM @TmpBaseTable
)
tmp ORDER BY RowID DESC

INSERT INTO @TmpSixMonthTable  (TmpMonth, TmpYear)
SELECT DATEPART(MONTH, DATEADD (MONTH, -5, @TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -5, @TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -4, @TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -4, @TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -3, @TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -3, @TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -2, @TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -2, @TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -1, @TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -1, @TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -0, @TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -0, @TmpDate))

SELECT TOP 1 @MissingMonth = tmpSix.TmpMonth, @MissingYear = tmpSix.TmpYear FROM @TmpSixMonthTable tmpSix
LEFT OUTER JOIN @TmpBaseTable tmpBase ON tmpSix.TmpMonth = tmpBase.[Month] AND tmpSix.TmpYear = tmpBase.[Year]
WHERE tmpBase.[Year] IS NULL

SET @TmpDate = CAST(CAST(@MissingYear AS VARCHAR) + '-' + CAST(@MissingMonth AS VARCHAR) + '-' + CAST(1 AS VARCHAR) AS DATE)

DELETE FROM @TmpSixMonthTable

INSERT INTO @TmpSixMonthTable  (TmpMonth, TmpYear)
SELECT DATEPART(MONTH, DATEADD (MONTH, -6, @TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -6, @TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -5, @TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -5, @TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -4, @TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -4, @TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -3, @TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -3, @TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -2, @TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -2, @TmpDate)) UNION ALL
SELECT DATEPART(MONTH, DATEADD (MONTH, -1, @TmpDate)), DATEPART(YEAR, DATEADD (MONTH, -1, @TmpDate))


SELECT @TmpCount = COUNT(1) FROM @TmpSixMonthTable tmp1
INNER JOIN @TmpBaseTable tmp2 ON tmp1.TmpMonth = tmp2.[Month] AND tmp1.TmpYear = tmp2.[Year]

IF(@TmpCount = 6)
BEGIN
    SELECT tmp2.[Month], tmp2.[Year] FROM @TmpSixMonthTable tmp1
    INNER JOIN @TmpBaseTable tmp2 ON tmp1.TmpMonth = tmp2.[Month] AND tmp1.TmpYear = tmp2.[Year]
END

可以采用比这更聪明的方式:)

答案 1 :(得分:0)

这个已经过测试,我花了一些时间在它上面,请告诉我如果你对结果感到满意并投票如果是,欢呼:-) PS:表dbo.Months_and_Years包含你的数据(缺少2个月)

            CREATE TABLE dbo.Test_Table  ( 
            [Year] SMALLINT,
            [Month] TINYINT
            );

            INSERT INTO dbo.Test_Table
            VALUES 
            (2014, 1),
            (2014, 2),
            (2014, 3),
            (2014, 4),
            (2014, 5),
            (2014, 6),
            (2014, 7),
            (2014, 9),
            (2014, 10),
            (2014, 12);




            DECLARE @MinValue TINYINT = 1
            DECLARE @MaxValue TINYINT = 100

            WHILE @MinValue < = @MaxValue

            BEGIN
            DECLARE @Missing_Month TINYINT = (

                        SELECT TOP 1 A.RowID
                        FROM (
                        SELECT DENSE_RANK() OVER ( ORDER BY [month])  AS RowID ,
                         *
                        FROM dbo.Test_Table
                        ) AS A
                        WHERE A.RowID <> A.[Month]
                        )
            SELECT  @Missing_Month

            IF @Missing_Month IS NULL

            BREAK

            ELSE
            INSERT INTO dbo.Test_Table
            VALUES (2014, @Missing_Month)

            SET @MinValue = @MinValue + 1

            END


            -- Check your results ---
            SELECT A.*
            FROM dbo.Test_Table AS A
LEFT JOIN dbo.Months_and_Years AS B  ON A.[Month] = B.[Month]
            WHERE B.[Month] IS NULL;