Listing 1: CreateIntegersTable |
USE [master]
GO
IF OBJECTPROPERTY(OBJECT_ID('dbo.CreateIntegersTable'),'IsTableFunction') = 1
BEGIN
DROP FUNCTION dbo.CreateIntegersTable
END
GO
CREATE FUNCTION [dbo].[CreateIntegersTable]
(
@start_int BIGINT = 1,
@step_int BIGINT = 1,
@end_int BIGINT
)
RETURNS @FinishedIntegersTable TABLE
(
ints BIGINT
)
AS
BEGIN
/* Table variable @IntegersTable holds finished Integer list. */
DECLARE @IntegersTable TABLE
(
ints BIGINT
)
/* If the user picked an @start_int value less than 1, shift the @end_int value. */
IF (@start_int < 1)
SET @end_int = (@end_int + ABS(@start_int) + 1);
|
|
/* Common table expression to build list of Integers less than 32,767. */
WITH IntegersTableFill (ints) AS
(
SELECT
CAST(1 AS BIGINT) AS 'ints'
UNION ALL
SELECT (T.ints + @step_int) AS 'ints'
FROM IntegersTableFill T
WHERE ints <= (
CASE
WHEN (@end_int <= 32767) THEN @end_int
ELSE 32767
END
)
)
INSERT INTO @IntegersTable
SELECT ints
FROM IntegersTableFill
OPTION ( MAXRECURSION 32767 )
|
A |
/* This block handles @end_int > 32,767. */ |
|
IF (@end_int > 32767)
BEGIN
|
B |
DECLARE @last_int_inserted BIGINT
DECLARE @int_row_groups INT
DECLARE @current_row_group SMALLINT
/* Figure out how many row groups the function needs for @end_int rows. */
|
|
SELECT @int_row_groups = CEILING((LOG((@end_int * 1.0)/65534))/LOG(2)) + 1
|
C |
/* The WHILE loop uses variable @int_row_groups. */
SET @current_row_group = 1
WHILE (@current_row_group <= @int_row_groups)
BEGIN
SELECT @last_int_inserted = MAX(ints) FROM @IntegersTable
|
D |
/*
In each group, make row inserts into @IntegersTable,
starting at @last_int_inserted and ending at
@end_int in the last group.
*/
|
|
INSERT INTO @IntegersTable
SELECT ints + @last_int_inserted + (@step_int - 1)
FROM @IntegersTable
WHERE (ints + @last_int_inserted) <= @end_int
SET @current_row_group = @current_row_group + 1
|
E |
END
END
/* Reverse the Integer shift in @IntegersTable, then in @end_int. */
IF (@start_int <> 1)
|
|
UPDATE @IntegersTable
SET ints = (ints + (SIGN(@start_int) * ABS(@start_int)) - 1)
IF (@start_int < 1)
SET @end_int = (@end_int - ABS(@start_int) - 1)
|
F |
/* Trim @IntegersTable, then set up the function return value. */
DELETE FROM @IntegersTable
WHERE ints < @start_int OR
ints > @end_int
INSERT @FinishedIntegersTable SELECT ints FROM @IntegersTable
RETURN
END
|
|