Как сгенерировать диапазон чисел между двумя числами?

У меня есть два числа в качестве ввода от пользователя, например, 1000 и 1050.

Как мне сгенерировать числа между этими двумя числами, используя sql-запрос, в отдельных строках? Я хочу это:

 1000
 1001
 1002
 1003
 .
 .
 1050

Ответ 1

Выберите непостоянные значения с помощью ключевого слова VALUES. Затем используйте JOIN для генерации множества комбинаций (можно расширить для создания сотен тысяч строк и более).

SELECT ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n
FROM (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) ones(n),
     (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) tens(n),
     (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) hundreds(n),
     (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) thousands(n)
WHERE ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n BETWEEN @userinput1 AND @userinput2
ORDER BY 1

Demo

Более короткая альтернатива, которую не так легко понять:

WITH x AS (SELECT n FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) v(n))
SELECT ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n
FROM x ones,     x tens,      x hundreds,       x thousands
ORDER BY 1

Demo

Ответ 2

альтернативным решением является рекурсивный CTE:

DECLARE @startnum INT=1000
DECLARE @endnum INT=1050
;
WITH gen AS (
    SELECT @startnum AS num
    UNION ALL
    SELECT num+1 FROM gen WHERE num+1<[email protected]
)
SELECT * FROM gen
option (maxrecursion 10000)

Ответ 3

SELECT DISTINCT n = number 
FROM master..[spt_values] 
WHERE number BETWEEN @start AND @end

Демо

Обратите внимание, что эта таблица имеет максимум 2048, потому что тогда числа имеют пробелы.

Здесь немного лучше использовать системный вид (начиная с SQL-Server 2005):

;WITH Nums AS
(
  SELECT n = ROW_NUMBER() OVER (ORDER BY [object_id]) 
  FROM sys.all_objects 

)
SELECT n FROM Nums 
WHERE n BETWEEN @start AND @end
ORDER BY n;

Демо

или используйте пользовательскую таблицу номеров. Кредиты Аарону Бертрану, я предлагаю прочитать всю статью: Создать набор или последовательность без циклов

Ответ 4

Недавно я написал эту встроенную функцию оценки таблицы, чтобы решить эту проблему. Он не ограничен в других областях, кроме памяти и хранилища. Он не обращается к таблицам, поэтому нет необходимости читать или записывать диски вообще. Он добавляет значения объединений экспоненциально на каждой итерации, поэтому он очень быстр даже для очень больших диапазонов. Он создает десять миллионов записей за пять секунд на моем сервере. Он также работает с отрицательными значениями.

CREATE FUNCTION [dbo].[fn_ConsecutiveNumbers]
(   
    @start int,
    @end  int
) RETURNS TABLE 
RETURN 

select
    x268435456.X
    | x16777216.X
    | x1048576.X
    | x65536.X
    | x4096.X
    | x256.X
    | x16.X
    | x1.X
    + @start
     X
from
(VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15)) as x1(X)
join
(VALUES (0),(16),(32),(48),(64),(80),(96),(112),(128),(144),(160),(176),(192),(208),(224),(240)) as x16(X)
on x1.X <= @[email protected] and x16.X <= @[email protected]
join
(VALUES (0),(256),(512),(768),(1024),(1280),(1536),(1792),(2048),(2304),(2560),(2816),(3072),(3328),(3584),(3840)) as x256(X)
on x256.X <= @[email protected]
join
(VALUES (0),(4096),(8192),(12288),(16384),(20480),(24576),(28672),(32768),(36864),(40960),(45056),(49152),(53248),(57344),(61440)) as x4096(X)
on x4096.X <= @[email protected]
join
(VALUES (0),(65536),(131072),(196608),(262144),(327680),(393216),(458752),(524288),(589824),(655360),(720896),(786432),(851968),(917504),(983040)) as x65536(X)
on x65536.X <= @[email protected]
join
(VALUES (0),(1048576),(2097152),(3145728),(4194304),(5242880),(6291456),(7340032),(8388608),(9437184),(10485760),(11534336),(12582912),(13631488),(14680064),(15728640)) as x1048576(X)
on x1048576.X <= @[email protected]
join
(VALUES (0),(16777216),(33554432),(50331648),(67108864),(83886080),(100663296),(117440512),(134217728),(150994944),(167772160),(184549376),(201326592),(218103808),(234881024),(251658240)) as x16777216(X)
on x16777216.X <= @[email protected]
join
(VALUES (0),(268435456),(536870912),(805306368),(1073741824),(1342177280),(1610612736),(1879048192)) as x268435456(X)
on x268435456.X <= @[email protected]
WHERE @end >=
    x268435456.X
    | isnull(x16777216.X, 0)
    | isnull(x1048576.X, 0)
    | isnull(x65536.X, 0)
    | isnull(x4096.X, 0)
    | isnull(x256.X, 0)
    | isnull(x16.X, 0)
    | isnull(x1.X, 0)
    + @start

GO

SELECT X FROM fn_ConsecutiveNumbers(5, 500);

Он также подходит для диапазонов даты и времени:

SELECT DATEADD(day,X, 0) DayX 
FROM fn_ConsecutiveNumbers(datediff(day,0,'5/8/2015'), datediff(day,0,'5/31/2015'))

SELECT DATEADD(hour,X, 0) HourX 
FROM fn_ConsecutiveNumbers(datediff(hour,0,'5/8/2015'), datediff(hour,0,'5/8/2015 12:00 PM'));

Вы можете использовать крест, чтобы присоединиться к нему, чтобы разделить записи на основе значений в таблице. Например, чтобы создать запись за каждую минуту в диапазоне времени в таблице, вы можете сделать что-то вроде:

select TimeRanges.StartTime,
    TimeRanges.EndTime,
    DATEADD(minute,X, 0) MinuteX
FROM TimeRanges
cross apply fn_ConsecutiveNumbers(datediff(hour,0,TimeRanges.StartTime), 
        datediff(hour,0,TimeRanges.EndTime)) ConsecutiveNumbers

Ответ 5

Самый лучший вариант, который я использовал, выглядит следующим образом:

DECLARE @min bigint, @max bigint
SELECT @Min=919859000000 ,@Max=919859999999

SELECT TOP (@[email protected]+1) @Min-1+row_number() over(order by t1.number) as N
FROM master..spt_values t1 
    CROSS JOIN master..spt_values t2

Я создал миллионы записей, используя это, и он отлично работает.

Ответ 6

Это работает для меня!

select top 50 ROW_NUMBER() over(order by a.name) + 1000 as Rcount
from sys.all_objects a

Ответ 7

Если у вас нет проблемы с установкой сборки CLR на вашем сервере, хорошим вариантом является запись функции табличной оценки в .NET. Таким образом, вы можете использовать простой синтаксис, упрощая объединение с другими запросами, а в качестве бонуса не будет тратить память, потому что результат передается.

Создайте проект, содержащий следующий класс:

using System;
using System.Collections;
using System.Data;
using System.Data.Sql;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

namespace YourNamespace
{
   public sealed class SequenceGenerator
    {
        [SqlFunction(FillRowMethodName = "FillRow")]
        public static IEnumerable Generate(SqlInt32 start, SqlInt32 end)
        {
            int _start = start.Value;
            int _end = end.Value;
            for (int i = _start; i <= _end; i++)
                yield return i;
        }

        public static void FillRow(Object obj, out int i)
        {
            i = (int)obj;
        }

        private SequenceGenerator() { }
    }
}

Поместите узел где-нибудь на сервер и запустите:

USE db;
CREATE ASSEMBLY SqlUtil FROM 'c:\path\to\assembly.dll'
WITH permission_set=Safe;

CREATE FUNCTION [Seq](@start int, @end int) 
RETURNS TABLE(i int)
AS EXTERNAL NAME [SqlUtil].[YourNamespace.SequenceGenerator].[Generate];

Теперь вы можете запустить:

select * from dbo.seq(1, 1000000)

Ответ 8

2 года спустя, но я обнаружил, что у меня такая же проблема. Вот как я это решил. (отредактированный для включения параметров)

DECLARE @Start INT, @End INT
SET @Start = 1000
SET @End = 1050

SELECT  TOP (@End - @Start+1) ROW_NUMBER() OVER (ORDER BY S.[object_id])+(@Start - 1) [Numbers]
FROM    sys.all_objects S WITH (NOLOCK)

Ответ 9

Лучший способ - использовать рекурсивные ctes.

declare @initial as int = 1000;
declare @final as int =1050;

with cte_n as (
    select @initial as contador
    union all
    select contador+1 from cte_n 
    where contador <@final
) select * from cte_n option (maxrecursion 0)

Saludos.

Ответ 10

Ничего нового, но я переписал решение Брайана Пресслера, чтобы было проще для глаз, оно могло бы быть полезным для кого-то (даже если оно только меня будущее):

alter function [dbo].[fn_GenerateNumbers]
(   
    @start int,
    @end  int
) returns table
return

with 
b0 as (select n from (values (0),(0x00000001),(0x00000002),(0x00000003),(0x00000004),(0x00000005),(0x00000006),(0x00000007),(0x00000008),(0x00000009),(0x0000000A),(0x0000000B),(0x0000000C),(0x0000000D),(0x0000000E),(0x0000000F)) as b0(n)),
b1 as (select n from (values (0),(0x00000010),(0x00000020),(0x00000030),(0x00000040),(0x00000050),(0x00000060),(0x00000070),(0x00000080),(0x00000090),(0x000000A0),(0x000000B0),(0x000000C0),(0x000000D0),(0x000000E0),(0x000000F0)) as b1(n)),
b2 as (select n from (values (0),(0x00000100),(0x00000200),(0x00000300),(0x00000400),(0x00000500),(0x00000600),(0x00000700),(0x00000800),(0x00000900),(0x00000A00),(0x00000B00),(0x00000C00),(0x00000D00),(0x00000E00),(0x00000F00)) as b2(n)),
b3 as (select n from (values (0),(0x00001000),(0x00002000),(0x00003000),(0x00004000),(0x00005000),(0x00006000),(0x00007000),(0x00008000),(0x00009000),(0x0000A000),(0x0000B000),(0x0000C000),(0x0000D000),(0x0000E000),(0x0000F000)) as b3(n)),
b4 as (select n from (values (0),(0x00010000),(0x00020000),(0x00030000),(0x00040000),(0x00050000),(0x00060000),(0x00070000),(0x00080000),(0x00090000),(0x000A0000),(0x000B0000),(0x000C0000),(0x000D0000),(0x000E0000),(0x000F0000)) as b4(n)),
b5 as (select n from (values (0),(0x00100000),(0x00200000),(0x00300000),(0x00400000),(0x00500000),(0x00600000),(0x00700000),(0x00800000),(0x00900000),(0x00A00000),(0x00B00000),(0x00C00000),(0x00D00000),(0x00E00000),(0x00F00000)) as b5(n)),
b6 as (select n from (values (0),(0x01000000),(0x02000000),(0x03000000),(0x04000000),(0x05000000),(0x06000000),(0x07000000),(0x08000000),(0x09000000),(0x0A000000),(0x0B000000),(0x0C000000),(0x0D000000),(0x0E000000),(0x0F000000)) as b6(n)),
b7 as (select n from (values (0),(0x10000000),(0x20000000),(0x30000000),(0x40000000),(0x50000000),(0x60000000),(0x70000000)) as b7(n))

select s.n
from (
    select
          b7.n
        | b6.n
        | b5.n
        | b4.n
        | b3.n
        | b2.n
        | b1.n
        | b0.n
        + @start
         n
    from b0
    join b1 on b0.n <= @[email protected] and b1.n <= @[email protected]
    join b2 on b2.n <= @[email protected]
    join b3 on b3.n <= @[email protected]
    join b4 on b4.n <= @[email protected]
    join b5 on b5.n <= @[email protected]
    join b6 on b6.n <= @[email protected]
    join b7 on b7.n <= @[email protected]
) s
where @end >= s.n

GO

Ответ 11

Вот пара вполне оптимальных и совместимых решений:

USE master;

declare @min as int;    set @min = 1000;
declare @max as int;    set @max = 1050;    --null returns all

--  Up to 256 - 2 048 rows depending on SQL Server version
select  isnull(@min,0)+number.number  as  number
FROM    dbo.spt_values  AS  number
WHERE   number."type"                   =   'P'     --integers
    and (   @max                            is null     --return all
        or  isnull(@min,0)+number.number    <=  @max    --return up to max
    )
order by    number
;

--  Up to 65 536 - 4 194 303 rows depending on SQL Server version
select  isnull(@min,0)+value1.number+(value2.number*numberCount.numbers)  as  number
FROM  dbo.spt_values            AS  value1
  cross join  dbo.spt_values    AS  value2
  cross join (  --get the number of numbers (depends on version)
    select  sum(1)  as  numbers
    from    dbo.spt_values
    where   spt_values."type"   =   'P' --integers
  )                             as  numberCount
WHERE   value1."type" = 'P'   --integers
    and value2."type" = 'P'   --integers
    and (   @max    is null     --return all
        or  isnull(@min,0)+value1.number+(value2.number*numberCount.numbers)    
            <=  @max            --return up to max
    )
order by    number
;

Ответ 12

ответ slartidan можно улучшить, повысить производительность, исключив все ссылки на декартовой продукт и вместо этого используя ROW_NUMBER() (план выполнения сравнивается):

SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n FROM 
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x1(x),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x2(x),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x3(x),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x4(x),
(VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x5(x)
ORDER BY n

Обмотайте его внутри CTE и добавьте предложение where для выбора нужных номеров:

DECLARE @n1 AS INT = 100;
DECLARE @n2 AS INT = 40099;
WITH numbers AS (
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n FROM 
    (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x1(x),
    (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x2(x),
    (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x3(x),
    (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x4(x),
    (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x5(x)
)
SELECT numbers.n
FROM numbers
WHERE n BETWEEN @n1 and @n2
ORDER BY n

Ответ 13

Я знаю, что мне уже 4 года, но я наткнулся на еще один альтернативный ответ на эту проблему. Проблема скорости - это не только предварительная фильтрация, но и предотвращение сортировки. Это позволяет принудительно выполнить порядок соединения таким образом, чтобы декартово произведение действительно подсчитывалось в результате объединения. Использование slartidan-ответа в качестве точки перехода:

    WITH x AS (SELECT n FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) v(n))
SELECT ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n
FROM x ones,     x tens,      x hundreds,       x thousands
ORDER BY 1

Если мы знаем диапазон, который мы хотим, мы можем указать его через @Upper и @Lower. Объединив подсказку соединения REMOTE вместе с TOP, мы можем вычислить только подмножество значений, которые мы хотим, ничего не теряя.

WITH x AS (SELECT n FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) v(n))
SELECT TOP ([email protected]@Lower) @Lower + ones.n + 10*tens.n + 100*hundreds.n + 1000*thousands.n
FROM x thousands
INNER REMOTE JOIN x hundreds on 1=1
INNER REMOTE JOIN x tens on 1=1
INNER REMOTE JOIN x ones on 1=1

Подсказка соединения REMOTE заставляет оптимизатор сначала сравнивать на правой стороне соединения. Указав каждое соединение как REMOTE от большинства до наименее значимого значения, само соединение будет правильно подсчитывать вверх одним. Не нужно фильтровать с помощью WHERE или сортировать с помощью ORDER BY.

Если вы хотите увеличить диапазон, вы можете продолжать добавлять дополнительные соединения с прогрессивно более высокими порядками, если они упорядочены от большинства до наименее значимых в предложении FROM.

Обратите внимание, что это запрос, специфичный для SQL Server 2008 или выше.

Ответ 14

Это также сделает

DECLARE @startNum INT = 1000;
DECLARE @endNum INT = 1050;
INSERT  INTO dbo.Numbers
        ( Num
        )
        SELECT  CASE WHEN MAX(Num) IS NULL  THEN @startNum
                     ELSE MAX(Num) + 1
                END AS Num
        FROM    dbo.Numbers
GO 51

Ответ 15

Лучшая скорость при выполнении запроса

DECLARE @num INT = 1000
WHILE(@num<1050)
begin
 INSERT  INTO [dbo].[Codes]
    (   Code
    ) 
    VALUES (@num)
    SET @num = @num + 1
end

Ответ 16

рекурсивный CTE в экспоненциальном размере (даже для 100 рекурсии по умолчанию это может создать до 2 ^ 100 номеров):

DECLARE @startnum INT=1000
DECLARE @endnum INT=1050
DECLARE @size [email protected]@startnum+1
;
WITH numrange (num) AS (
    SELECT 1 AS num
    UNION ALL
    SELECT num*2 FROM numrange WHERE num*2<[email protected]
    UNION ALL
    SELECT num*2+1 FROM numrange WHERE num*2+1<[email protected]
)
SELECT [email protected] FROM numrange order by num

Ответ 17

Мне пришлось вставить путь к файлу изображения в базу данных с помощью аналогичного метода. Следующий запрос работал нормально:

DECLARE @num INT = 8270058
WHILE(@num<8270284)
begin
    INSERT  INTO [dbo].[Galleries]
    (ImagePath) 
    VALUES 
    ('~/Content/Galeria/P'+CONVERT(varchar(10), @num)+'.JPG')

    SET @num = @num + 1
end

Код для вас:

DECLARE @num INT = 1000
WHILE(@num<1051)
begin
    SELECT @num

    SET @num = @num + 1
end

Ответ 18

-- Generate Numeric Range
-- Source: http://www.sqlservercentral.com/scripts/Miscellaneous/30397/

CREATE TABLE #NumRange(
    n int
)

DECLARE @MinNum int
DECLARE @MaxNum int
DECLARE @I int

SET NOCOUNT ON

SET @I = 0
WHILE @I <= 9 BEGIN
    INSERT INTO #NumRange VALUES(@I)
    SET @I = @I + 1
END


SET @MinNum = 1
SET @MaxNum = 1000000

SELECT  num = a.n +
    (b.n * 10) +
    (c.n * 100) +
    (d.n * 1000) +
    (e.n * 10000)
FROM    #NumRange a
CROSS JOIN #NumRange b
CROSS JOIN #NumRange c
CROSS JOIN #NumRange d
CROSS JOIN #NumRange e
WHERE   a.n +
    (b.n * 10) +
    (c.n * 100) +
    (d.n * 1000) +
    (e.n * 10000) BETWEEN @MinNum AND @MaxNum
ORDER BY a.n +
    (b.n * 10) +
    (c.n * 100) +
    (d.n * 1000) +
    (e.n * 10000) 

DROP TABLE #NumRange

Ответ 19

Это работает только для последовательностей, если в какой-либо таблице приложений есть строки. Предположим, что я хочу последовательность из 1..100 и имею таблицу приложений dbo.foo со столбцом (числового или строкового типа) foo.bar:

select 
top 100
row_number() over (order by dbo.foo.bar) as seq
from dbo.foo

Несмотря на свое присутствие в предложении order by, dbo.foo.bar не должен иметь отдельных или даже ненулевых значений.

Конечно, SQL Server 2012 имеет объекты последовательности, поэтому в этом продукте есть естественное решение.

Ответ 20

Это завершено для меня за 36 секунд на нашем сервере DEV. Как и ответ Брайана, фокусировка на фильтрации в диапазоне важна из запроса; BETWEEN все еще пытается сгенерировать все начальные записи до нижней границы, даже если они им не нужны.

declare @s bigint = 10000000
    ,   @e bigint = 20000000

;WITH 
Z AS (SELECT 0 z FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15)) T(n)),
Y AS (SELECT 0 z FROM Z a, Z b, Z c, Z d, Z e, Z f, Z g, Z h, Z i, Z j, Z k, Z l, Z m, Z n, Z o, Z p),
N AS (SELECT ROW_NUMBER() OVER (PARTITION BY 0 ORDER BY z) n FROM Y)

SELECT TOP ([email protected]@s) @s + n - 1 FROM N

Обратите внимание, что ROW_NUMBER является bigint, поэтому мы не можем переходить на 2 ^^ 64 (== 16 ^^ 16) сгенерированные записи любым способом, который использует Это. Поэтому этот запрос учитывает тот же верхний предел для сгенерированных значений.

Ответ 21

Вот что я придумал:

create or alter function dbo.fn_range(@start int, @end int)  returns table
return
with u2(n) as (
    select n 
    from (VALUES (0),(1),(2),(3)) v(n)
), 
u8(n) as (
    select
        x0.n | x1.n * 4 | x2.n * 16 | x3.n * 64 as n
    from u2 x0, u2 x1, u2 x2, u2 x3
)
select 
    @start + s.n as n
from (
    select
        x0.n | isnull(x1.n, 0) * 256 | isnull(x2.n, 0) * 65536 as n
    from u8 x0 
    left join u8 x1 on @[email protected] > 256
    left join u8 x2 on @[email protected] > 65536
) s
where s.n < @end - @start

Генерирует до 2 ^ 24 значений. Условия соединения сохраняют это быстро при небольших значениях.

Ответ 22

В этом случае используется процедурный код и табличная функция. Медленно, но легко и предсказуемо.

CREATE FUNCTION [dbo].[Sequence] (@start int, @end int)
RETURNS
@Result TABLE(ID int)
AS
begin
declare @i int;
set @i = @start;
while @i <= @end 
    begin
        insert into @result values (@i);
        set @i = @i+1;
    end
return;
end

Использование:

SELECT * FROM dbo.Sequence (3,7);
ID
3
4
5
6
7

Это таблица, поэтому вы можете использовать ее в соединениях с другими данными. Я чаще всего использую эту функцию как левую сторону соединения против GROUP BY hour, day и т.д., Чтобы обеспечить непрерывную последовательность значений времени.

SELECT DateAdd(hh,ID,'2018-06-20 00:00:00') as HoursInTheDay FROM dbo.Sequence (0,23) ;

HoursInTheDay
2018-06-20 00:00:00.000
2018-06-20 01:00:00.000
2018-06-20 02:00:00.000
2018-06-20 03:00:00.000
2018-06-20 04:00:00.000
(...)

Производительность невыносима (16 секунд для миллиона строк), но достаточно для многих целей.

SELECT count(1) FROM [dbo].[Sequence] (
   1000001
  ,2000000)
GO

Ответ 23

Oracle 12c; Быстрый, но ограниченный:

select rownum+1000 from all_objects fetch first 50 rows only;

Примечание: ограничено количеством строк в представлении all_objects;

Ответ 24

declare @start int = 1000 declare @end int = 1050

с номером
КАК
(
SELECT @start [SEQUENCE]

UNION все

SELECT [SEQUENCE] + 1 FROM numcte WHERE [SEQUENCE] <@end)

SELECT * FROM numcte

Ответ 25

Это то, что я делаю, это довольно быстро и гибко, и не так много кода.

DECLARE @count  int =   65536;
DECLARE @start  int =   11;
DECLARE @xml    xml =   REPLICATE(CAST('<x/>' AS nvarchar(max)), @count);

; WITH GenerateNumbers(Num) AS
(
    SELECT  ROW_NUMBER() OVER (ORDER BY @count) + @start - 1
    FROM    @xml.nodes('/x') X(T)
)
SELECT  Num
FROM    GenerateNumbers;

Обратите внимание, что (ORDER BY @count) - пустышка. Он ничего не делает, но ROW_NUMBER() требует ORDER BY.

Изменить: я понял, что первоначальный вопрос должен был получить диапазон от х до у. Мой скрипт может быть изменен так, чтобы получить диапазон:

DECLARE @start  int =   5;
DECLARE @end    int =   21;
DECLARE @xml    xml =   REPLICATE(CAST('<x/>' AS nvarchar(max)), @end - @start + 1);

; WITH GenerateNumbers(Num) AS
(
    SELECT  ROW_NUMBER() OVER (ORDER BY @end) + @start - 1
    FROM    @xml.nodes('/x') X(T)
)
SELECT  Num
FROM    GenerateNumbers;