Reputation: 2278
I have a table with a PK that grows fairly quickly, but since rows are fairly consistently deleted, it becomes a very sparse table quickly as such:
ID VALUE
----------------
1 'Test'
5 'Test 2'
24 'Test 3'
67 'Test 4'
Is there a way that I can automatically insert the next value in the missing IDs so that I don't grow that ID extremely large? For example, I'd like to insert 'Test 5' with ID 2.
Upvotes: 1
Views: 2483
Reputation: 3275
I'm not suggesting doing what you're trying to do, but if you want to do it, this is how. I am only answering the question, not solving the problem.
In your proc, you'd what to lock your table while doing this so that you don't get one the sneaks in. By using something link this:
EXEC @result = sp_getapplock @Resource = @LockResource,
@LockMode = 'Exclusive'
AND
EXEC sp_releaseapplock @Resource = @LockResource
TABLE
DECLARE @table TABLE ( id INT, val VARCHAR(20) )
DATA
INSERT INTO @table
(
id,
val
)
SELECT 1,
'Test'
UNION ALL
SELECT 2,
'Test'
UNION ALL
SELECT 5,
'Test 2'
UNION ALL
SELECT 24,
'Test 3'
UNION ALL
SELECT 67,
'Test 4'
Queries
INSERT INTO @table
SELECT TOP 1
id + 1,
'TEST'
FROM @table t1
WHERE NOT EXISTS ( SELECT TOP 1
1
FROM @table
WHERE id = t1.id + 1 )
ORDER BY id
INSERT INTO @table
SELECT TOP 1
id + 1,
'TEST'
FROM @table t1
WHERE NOT EXISTS ( SELECT TOP 1
1
FROM @table
WHERE id = t1.id + 1 )
ORDER BY id
SELECT *
FROM @table
RESULT
id val
1 Test
2 Test
5 Test 2
24 Test 3
67 Test 4
3 TEST
4 TEST
Upvotes: 2
Reputation: 36421
I wouldn't do that.
As already explained by others in the comments, you gain nothing by re-filling gaps in the numbers.
Plus, you might even unintentionally mess up your data if you refer to these IDs anywhere else:
Let's say that there once was a row with ID 2
and you deleted it.
Then you insert a complete new row and re-use ID 2
.
Now if you have any data anywhere that references ID 2
, it suddenly links to the new value instead of the old one.
(Note to nit-pickers: Yes, this should not happen if referential integrity is set up properly. But this is not the case everywhere, so who knows...)
Upvotes: 2
Reputation: 89661
I deleted my answer about identity since they are not involved. It would be interesting to see if you are using this as a clustered index key, since to fill in gaps would violate the rule of thumb of strictly increasing values.
To just fill in gaps is relatively simple with a self-join and since you have a primary key, this query should run quickly to find the first gap (but of course, how are you handling simultaneous inserts and locks?):
SELECT lhs.ID + 1 AS firstgap
FROM tablename AS lhs
LEFT JOIN tablename AS rhs
ON rhs.ID = lhs.ID + 1
WHERE rhs.ID IS NULL
And inserting batches of records requires each insert to be done separately, while IDENTITY can handle that for you...
Upvotes: 1
Reputation: 254
As said before: don't worry about the unused ID's.
It is however good practise to optimize the table when a lot of deletes happen.
In MySQL you can do this with:
optimize table tablename
Upvotes: -2