在值列表中查找缺少的整数

时间:2014-06-11 02:24:41

标签: sql-server sql-server-2008

目前,我有12行,列名为“'值'”。像这样的样本(只是样本数据,真实数据会更):

Value
1
2
3
4
6
7
8
9
10
11
12
14

我想要的是选择它们以获得这样的结果:

Result          Result_Miss
1-4, 6-12, 14   5, 13

我想避免使用游标逐行工作。

2 个答案:

答案 0 :(得分:3)

使用CTE捕获缺失值的动态,基于集合的方法,并根据缺失值写出可用范围。

- (我似乎无法让SqlFiddle与CTE合作,或者我会在这里发布一个) -

针对记录数量进行了重新设计:

如果您的值集合中总是有“1”

,则可以使用此功能
CREATE TABLE #OneTen
(
   Value INT NOT NULL
);

INSERT INTO #OneTen
VALUES (1), (2), (3), (4), (6), (8), (9), (10), (11), (12), (14);


WITH ExpectedActual AS
(
   SELECT ot.Value AS Actual, ROW_NUMBER() OVER (ORDER BY Value) AS Expected
   FROM #OneTen AS ot
)
, DegreesOff AS
(
   SELECT ea.Expected, ea.Actual, (ea.Actual - ea.Expected) AS Change
   FROM ExpectedActual AS ea
)
, Missing AS
(
   SELECT CASE
             WHEN MIN(do.Expected) = 1 THEN 0
             ELSE MIN(do.Expected) + do.Change - 1
          END AS Missing
      , ROW_NUMBER() OVER (ORDER BY MIN(do.Expected)) AS RowNumber
   FROM DegreesOff AS do
   GROUP BY do.Change
   UNION ALL
   SELECT MAX(do.Actual + 1), MAX(do.Change + 2) --Adding Last Value 1 higher than Actual so the code below that takes mNext.Missing - 1 brings it down to the proper value:
     --Change + 2 to account for 0 plus being 1 higher
   FROM DegreesOff AS do
)
SELECT STUFF((
   SELECT ', ' + CASE
                    WHEN m.Missing + 1 = mNext.Missing - 1 THEN CAST(m.Missing + 1 AS NVARCHAR(4))
                    ELSE CAST(m.Missing + 1 AS NVARCHAR(4)) + '-' + CAST(mNext.Missing - 1 AS NVARCHAR(4))
                 END
   FROM Missing AS m
   LEFT JOIN Missing AS mNext ON m.RowNumber = mNext.RowNumber - 1
   FOR XML PATH('')), 1, 2, '') AS Result
   , STUFF((
      SELECT ', ' + CAST(MIN(do.Expected + do.Change - 1) AS NVARCHAR(4))
   FROM DegreesOff AS do
   WHERE do.Change > 0
   GROUP BY do.Change
   FOR XML PATH('')), 1, 2, '') AS Result_Miss

答案 1 :(得分:1)

尝试以下脚本:

DDL

CREATE TABLE Numbers
(
   Value INT NOT NULL
);

INSERT INTO Numbers
VALUES (1), (2), (3), (4), (6), (7), (8), (9), (10), (12),(13);

脚本

DECLARE @MinValue INT
DECLARE @MaxValue INT
DECLARE @Temp TABLE(MissingValues INT)
DECLARE @MissingValues VARCHAR(50)


SELECT @MinValue = MIN(Value),
       @MaxValue = MAX(Value)
FROM Numbers


;WITH CTE AS
(
  SELECT @MinValue Value

  UNION ALL

  SELECT Value + 1
  FROM CTE
  WHERE Value + 1 <= @MaxValue
)
INSERT INTO @Temp
SELECT CTE.Value
FROM CTE 
LEFT JOIN Numbers N
ON CTE.Value = N.Value
WHERE N.Value IS NULL
OPTION (MAXRECURSION 1000)

SELECT @MissingValues = 
            STUFF((  SELECT ',' + CAST(MissingValues AS VARCHAR)
                     FROM @Temp 
                     FOR XML PATH('')),1,1,'')



INSERT INTO @Temp
SELECT @MinValue - 1

UNION ALL

SELECT @MaxValue + 1

;WITH CTE AS
(
  SELECT MissingValues,
         ROW_NUMBER() OVER(ORDER  BY MissingValues ASC) RN
  FROM @Temp
)
,Ranges AS
(
  SELECT CAST(T1.MissingValues + 1 AS VARCHAR) + '-' +
         CAST(T2.MissingValues - 1 AS VARCHAR) Ranges
  FROM CTE AS T1
  INNER JOIN CTE AS T2
  ON T1.RN = T2.RN - 1
)
SELECT STUFF((  SELECT ',' + R.Ranges
                FROM Ranges R
                FOR XML PATH('')),1,1,'') Result,
       @MissingValues AS Result_Miss