Reputation: 136
I have a table like below:
╔══════════════════════════════════════╦═══════════════════════╗
║ Id ║ ContiguousSubnetStart ║
╠══════════════════════════════════════╬═══════════════════════╣
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 10.60.66.8 ║
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 1 ║
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 10.60.66.18 ║
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 1 ║
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 1 ║
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 1 ║
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 1 ║
║ B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 ║ 10.60.88.28 ║
║ B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 ║ 1 ║
║ B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 ║ 1 ║
║ B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 ║ 1 ║
╚══════════════════════════════════════╩═══════════════════════╝
I would like this table to transform into:
╔══════════════════════════════════════╦═══════════════════════╗
║ Id ║ ContiguousSubnetStart ║
╠══════════════════════════════════════╬═══════════════════════╣
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 10.60.66.8 ║
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 10.60.66.8 ║
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 10.60.66.18 ║
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 10.60.66.18 ║
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 10.60.66.18 ║
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 10.60.66.18 ║
║ 53DC370E-8C7D-4526-9292-35125443E4B1 ║ 10.60.66.18 ║
║ B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 ║ 10.60.88.28 ║
║ B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 ║ 10.60.88.28 ║
║ B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 ║ 10.60.88.28 ║
║ B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 ║ 10.60.88.28 ║
╚══════════════════════════════════════╩═══════════════════════╝
without using cursors. ip-address
followed by 1's represent one group.
Upvotes: 1
Views: 179
Reputation: 375
You could also do a WHILE loop with a row count, not sure which would be better performance wise for your environment.
CREATE TABLE #Test
(
Id UNIQUEIDENTIFIER ,
ContiguousSubnetStart VARCHAR(100)
)
INSERT INTO #Test
VALUES ( '53DC370E-8C7D-4526-9292-35125443E4B1', '10.60.66.8' ),
( '53DC370E-8C7D-4526-9292-35125443E4B1', '1' ),
( '53DC370E-8C7D-4526-9292-35125443E4B1', '10.60.66.18' ),
( '53DC370E-8C7D-4526-9292-35125443E4B1', '1' ),
( '53DC370E-8C7D-4526-9292-35125443E4B1', '1' ),
( '53DC370E-8C7D-4526-9292-35125443E4B1', '1' ),
( '53DC370E-8C7D-4526-9292-35125443E4B1', '1' ),
( 'B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7', '10.60.88.28' ),
( 'B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7', '1' ),
( 'B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7', '1' ),
( 'B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7', '1' )
SELECT *, [RN] = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) INTO #NewTable FROM #Test
DECLARE @Count INT = (SELECT MAX(RN) FROM #NewTable)
DECLARE @CurrentRow INT = 1
WHILE @Count > 0
BEGIN
UPDATE #NewTable
SET ContiguousSubnetStart = (SELECT ContiguousSubnetStart FROM #NewTable WHERE RN = @CurrentRow - 1)
WHERE ContiguousSubnetStart = '1'
AND RN = @CurrentRow
SET @CurrentRow = @CurrentRow + 1
SET @Count = @Count - 1
END
Result Set:
===========================================================
| 53DC370E-8C7D-4526-9292-35125443E4B1 | 10.60.66.8 | 1 |
| 53DC370E-8C7D-4526-9292-35125443E4B1 | 10.60.66.8 | 2 |
| 53DC370E-8C7D-4526-9292-35125443E4B1 | 10.60.66.18 | 3 |
| 53DC370E-8C7D-4526-9292-35125443E4B1 | 10.60.66.18 | 4 |
| 53DC370E-8C7D-4526-9292-35125443E4B1 | 10.60.66.18 | 5 |
| 53DC370E-8C7D-4526-9292-35125443E4B1 | 10.60.66.18 | 6 |
| 53DC370E-8C7D-4526-9292-35125443E4B1 | 10.60.66.18 | 7 |
| B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 | 10.60.88.28 | 8 |
| B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 | 10.60.88.28 | 9 |
| B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 | 10.60.88.28 | 10 |
| B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 | 10.60.88.28 | 11 |
===========================================================
Upvotes: 0
Reputation: 35780
Such manipulations need some column on which you can order rows in order to get desired result. In the example I have manually added such a column rn
using window function row_number
:
DECLARE @t TABLE
(
Id UNIQUEIDENTIFIER ,
ContiguousSubnetStart VARCHAR(100)
)
INSERT INTO @t
VALUES ( '53DC370E-8C7D-4526-9292-35125443E4B1', '10.60.66.8' ),
( '53DC370E-8C7D-4526-9292-35125443E4B1', '1' ),
( '53DC370E-8C7D-4526-9292-35125443E4B1', '10.60.66.18' ),
( '53DC370E-8C7D-4526-9292-35125443E4B1', '1' ),
( '53DC370E-8C7D-4526-9292-35125443E4B1', '1' ),
( '53DC370E-8C7D-4526-9292-35125443E4B1', '1' ),
( '53DC370E-8C7D-4526-9292-35125443E4B1', '1' ),
( 'B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7', '10.60.88.28' ),
( 'B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7', '1' ),
( 'B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7', '1' ),
( 'B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7', '1' )
;WITH cte AS(SELECT *, ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) rn FROM @t)
SELECT oa.Id, oa.ContiguousSubnetStart
FROM cte t1
OUTER APPLY(SELECT TOP 1 *
FROM cte t2
WHERE t1.Id = t2.Id AND t2.ContiguousSubnetStart <> '1' AND t2.rn <= t1.rn
ORDER BY rn DESC)oa
If you select from cte
you will see:
Id ContiguousSubnetStart rn
53DC370E-8C7D-4526-9292-35125443E4B1 10.60.66.8 1
53DC370E-8C7D-4526-9292-35125443E4B1 1 2
53DC370E-8C7D-4526-9292-35125443E4B1 10.60.66.18 3
53DC370E-8C7D-4526-9292-35125443E4B1 1 4
53DC370E-8C7D-4526-9292-35125443E4B1 1 5
53DC370E-8C7D-4526-9292-35125443E4B1 1 6
53DC370E-8C7D-4526-9292-35125443E4B1 1 7
B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 10.60.88.28 8
B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 1 9
B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 1 10
B6F8484C-B8F9-4CB0-B6BF-395A7599FFB7 1 11
If you have such a column like incrementing identity or date column using which you can unambigiously order the data in your table just use that column instead of rn
and you won't need cte any more. Say that column name is SomeOrderingColumn
, then your statement will look like:
SELECT oa.Id, oa.ContiguousSubnetStart
FROM TableName t1
OUTER APPLY(SELECT TOP 1 *
FROM TableName t2
WHERE t1.Id = t2.Id AND t2.ContiguousSubnetStart <> '1'
AND t2.SomeOrderingColumn <= t1.SomeOrderingColumn
ORDER BY SomeOrderingColumn DESC)oa
Without that ordering column you may still get the desired result, but that will not be guarantied under all circumstances and you can encounter some day that you are getting wrong results. This was discussed many times and you can find out that you are guarantied to get ordered results only and only if you explicitly use ORDER BY
clause. But you can not order your data with guid
or ip
columns. So you will have to add one more column to your table that will guaranty ordering like incrementing ID
or DateTime
column.
Upvotes: 6