Is there any other better way to perform this operation?
-- USE EXAMPLE: EXEC GetFirstIdInGap @tableName ='Employees',@column='IdEmployee'
CREATE PROCEDURE GetFirstIdInGap
(@tableName sysname,
@column sysname)
AS
IF @tableName IS NOT NULL and @column IS NOT NULL
BEGIN
DECLARE @col varchar(50), @col2 varchar(50)
SET @col = 'A.' + @column;
SET @col2 = 'A2.' + @column;
EXEC ('SELECT ISNULL((MIN('+@col+') - 1),(SELECT ISNULL(MAX('+@column+')+1,1) FROM '+@tableName+'))
AS '+@column+'
FROM '+@tableName+' AS a
LEFT JOIN '+@tableName+' AS a2
ON '+@col2+' = '+@col+' - 1
WHERE '+@col2+' IS NULL AND '+@col+' > 1');
END
GO
It gets the first free ID (if there are gaps) or the last one + 1 given a @tableName and @column. If there are no rows, it returns as the first ID 开发者_JAVA百科= 1.
UPDATE:
For those who have asked about why do I need gaps of ID's, I am gonna explain my problem (although I didn't want to dig into it). I work with C# Winforms applications against other firmware applications which have serious memory restrictions. One of those restrictions is that I can only use a maximum code value of 65536. Those codes are equivalent of database ID's, and in some cases the firmware code had reached the value of 65536. That's why gap reusing would be wonderful for me.
t is your table
select
coalesce((select min(id)+1 from t mt where not exists(select 1 from t where id+1 = mt.id )), 1) firstgap
Here is an approach that doesn't require a numbers table (even one with more than 1,000 rows):
CREATE PROCEDURE dbo.GetFirstIdInGap_2
@table SYSNAME,
@column SYSNAME
AS
BEGIN
SET NOCOUNT ON;
DECLARE @sql NVARCHAR(MAX) = N';WITH c AS
(
SELECT n = ' + @column + ',
rn = ROW_NUMBER() OVER (ORDER BY ' + @column + ')
FROM ' + @table + '
)
SELECT ' + @column + ' = 1 + COALESCE(
(SELECT MIN(c.n) FROM c INNER JOIN c AS n
ON n.rn = c.rn + 1 WHERE n.n - c.n > 1),
(SELECT MAX(c.n) FROM c),
0);';
EXEC sp_executesql @sql;
END
GO
t
is your table
select min(isnull(id,0)+1) from t where isnull(id,0) + 1 not in (select isnull(id,0) from t)
精彩评论