目前,我有12行,列名为“'值'”。像这样的样本(只是样本数据,真实数据会更):
Value
1
2
3
4
6
7
8
9
10
11
12
14
我想要的是选择它们以获得这样的结果:
Result Result_Miss
1-4, 6-12, 14 5, 13
我想避免使用游标逐行工作。
答案 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