У меня есть два числа в качестве ввода от пользователя, например, 1000
и 1050
.
Как мне сгенерировать числа между этими двумя числами, используя SQL-запрос, в отдельных строках? Я хочу этот:
1000
1001
1002
1003
.
.
1050
У меня есть два числа в качестве ввода от пользователя, например, 1000
и 1050
.
Как мне сгенерировать числа между этими двумя числами, используя SQL-запрос, в отдельных строках? Я хочу этот:
1000
1001
1002
1003
.
.
1050
Ответы:
Выберите непостоянные значения с VALUES
ключевым словом. Затем используйте JOIN
s для генерации множества комбинаций (можно расширить для создания сотен тысяч строк и более).
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
Более короткая альтернатива, которую не так легко понять:
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
альтернативным решением является рекурсивный 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<=@endnum
)
SELECT * FROM gen
option (maxrecursion 10000)
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;
или используйте пользовательскую таблицу номеров. Благодарности Аарону Бертрану, я предлагаю прочитать всю статью: создать набор или последовательность без циклов
WHERE type = 'P'
и избежатьSELECT DISTINCT
String index out of range: 33
Я недавно написал эту встроенную табличную функцию, чтобы решить эту проблему. Он не ограничен в диапазоне, кроме памяти и памяти. Он не обращается к таблицам, поэтому нет необходимости в чтении или записи на диск в целом. Он добавляет значения соединений экспоненциально на каждой итерации, поэтому он очень быстр даже для очень больших диапазонов. Он создает десять миллионов записей за пять секунд на моем сервере. Это также работает с отрицательными значениями.
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 <= @end-@start and x16.X <= @end-@start
join
(VALUES (0),(256),(512),(768),(1024),(1280),(1536),(1792),(2048),(2304),(2560),(2816),(3072),(3328),(3584),(3840)) as x256(X)
on x256.X <= @end-@start
join
(VALUES (0),(4096),(8192),(12288),(16384),(20480),(24576),(28672),(32768),(36864),(40960),(45056),(49152),(53248),(57344),(61440)) as x4096(X)
on x4096.X <= @end-@start
join
(VALUES (0),(65536),(131072),(196608),(262144),(327680),(393216),(458752),(524288),(589824),(655360),(720896),(786432),(851968),(917504),(983040)) as x65536(X)
on x65536.X <= @end-@start
join
(VALUES (0),(1048576),(2097152),(3145728),(4194304),(5242880),(6291456),(7340032),(8388608),(9437184),(10485760),(11534336),(12582912),(13631488),(14680064),(15728640)) as x1048576(X)
on x1048576.X <= @end-@start
join
(VALUES (0),(16777216),(33554432),(50331648),(67108864),(83886080),(100663296),(117440512),(134217728),(150994944),(167772160),(184549376),(201326592),(218103808),(234881024),(251658240)) as x16777216(X)
on x16777216.X <= @end-@start
join
(VALUES (0),(268435456),(536870912),(805306368),(1073741824),(1342177280),(1610612736),(1879048192)) as x268435456(X)
on x268435456.X <= @end-@start
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
SELECT X FROM fn_ConsecutiveNumbers(5, 500) ORDER BY X;
Лучший вариант, который я использовал, выглядит следующим образом:
DECLARE @min bigint, @max bigint
SELECT @Min=919859000000 ,@Max=919859999999
SELECT TOP (@Max-@Min+1) @Min-1+row_number() over(order by t1.number) as N
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
Я создал миллионы записей, используя это, и это прекрасно работает.
Это работает для меня!
select top 50 ROW_NUMBER() over(order by a.name) + 1000 as Rcount
from sys.all_objects a
sys.all_objects
- для небольших диапазонов <2000 пунктов, это не проблема. Не уверен, что у него будут проблемы с разрешениями? идеально подходит для быстрой генерации пакета тестовых данных.
select top 50 ROW_NUMBER() over(order by a.name) + 1000 as Rcount from sys.all_objects a, sys.all_objects b
, Там, где раньше я мог генерировать только 2384 строки, теперь я могу создать 5683456 строк.
Лучший способ - использовать рекурсивные 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.
declare @start int = 1000
declare @end int =1050
;with numcte
AS
(
SELECT @start [SEQUENCE]
UNION all
SELECT [SEQUENCE] + 1 FROM numcte WHERE [SEQUENCE] < @end
)
SELECT * FROM numcte
Если у вас нет проблем с установкой сборки 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)
Ничего нового, но я переписал решение Брайана Пресслера так, чтобы оно было проще для глаз, оно может быть полезно кому-то (даже если это только будущее для меня):
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 <= @end-@start and b1.n <= @end-@start
join b2 on b2.n <= @end-@start
join b3 on b3.n <= @end-@start
join b4 on b4.n <= @end-@start
join b5 on b5.n <= @end-@start
join b6 on b6.n <= @end-@start
join b7 on b7.n <= @end-@start
) s
where @end >= s.n
GO
ROW_NUMBER()
не имеют этой проблемы.
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)
Ответ 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
SELECT ROW_NUMBER() OVER (...) - 1 AS n
. В некоторых случаях это может снизить производительность.
Вот пара вполне оптимальных и совместимых решений:
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
;
select
ING where spt_values.number between @min and @max
?
Я знаю, что я опоздал на 4 года, но я наткнулся на еще один альтернативный ответ на эту проблему. Проблема скорости заключается не только в предварительной фильтрации, но и в предотвращении сортировки. Можно заставить ордер на объединение выполнить таким образом, чтобы декартово произведение фактически считало результат объединения. Используя ответ Слартидана в качестве отправной точки:
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 (1+@Upper-@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 заставляет оптимизатор сравнивать сначала с правой стороны соединения. Указав каждое соединение как УДАЛЕННОЕ от самого значительного до наименее значимого значения, само соединение будет считаться вверх на единицу правильно. Нет необходимости фильтровать с помощью WHERE или сортировать с помощью ORDER BY.
Если вы хотите увеличить диапазон, вы можете продолжать добавлять дополнительные объединения с прогрессивно более высокими порядками величины, если они упорядочены от наиболее значимых до наименее значимых в предложении FROM.
Обратите внимание, что это запрос, специфичный для SQL Server 2008 или выше.
Лучшая скорость при выполнении запроса
DECLARE @num INT = 1000
WHILE(@num<1050)
begin
INSERT INTO [dbo].[Codes]
( Code
)
VALUES (@num)
SET @num = @num + 1
end
рекурсивный CTE в экспоненциальном размере (даже для 100 рекурсий по умолчанию это может составить до 2 ^ 100 чисел):
DECLARE @startnum INT=1000
DECLARE @endnum INT=1050
DECLARE @size INT=@endnum-@startnum+1
;
WITH numrange (num) AS (
SELECT 1 AS num
UNION ALL
SELECT num*2 FROM numrange WHERE num*2<=@size
UNION ALL
SELECT num*2+1 FROM numrange WHERE num*2+1<=@size
)
SELECT num+@startnum-1 FROM numrange order by num
@startnum
и endnum
должен быть введен пользователем?
Мне пришлось вставить файл filepath в базу данных, используя аналогичный метод. Запрос ниже работал нормально:
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
Это то, что я делаю, это довольно быстро и гибко, и не много кода.
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;
-- 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
Это работает только для последовательностей, если в некоторых таблицах приложений есть строки. Предположим, мне нужна последовательность из 1..100, и у меня есть таблица приложения dbo.foo со столбцом (числового или строкового типа) foo.bar:
select
top 100
row_number() over (order by dbo.foo.bar) as seq
from dbo.foo
Несмотря на то, что dbo.foo.bar присутствует в предложении order by, он не должен иметь отдельных или даже ненулевых значений.
Конечно, SQL Server 2012 имеет объекты последовательности, поэтому в этом продукте есть естественное решение.
Вот что я придумал:
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 @end-@start > 256
left join u8 x2 on @end-@start > 65536
) s
where s.n < @end - @start
Генерирует до 2 ^ 24 значений. Условия соединения сохраняют скорость для небольших значений.
Для меня это завершилось за 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 (1+@e-@s) @s + n - 1 FROM N
Обратите внимание, что ROW_NUMBER - это bigint , поэтому мы не можем просмотреть 2 ^ ^ 64 (== 16 ^^ 16) сгенерированных записей любым методом, который его использует. Поэтому этот запрос учитывает тот же верхний предел для сгенерированных значений.
Это использует процедурный код и табличную функцию. Медленно, но легко и предсказуемо.
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, чтобы обеспечить непрерывную последовательность значений времени.
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
Oracle 12c; Быстро, но ограничено:
select rownum+1000 from all_objects fetch first 50 rows only;
Примечание : ограничено количеством строк представления all_objects;
Решение, которое я разработал и использовал в течение довольно долгого времени (некоторые используют общие работы других), немного похоже на хотя бы одно опубликованное. Он не ссылается ни на какие таблицы и возвращает несортированный диапазон до 1048576 значений (2 ^ 20) и может включать отрицательные значения при желании. Вы можете, конечно, отсортировать результат, если это необходимо. Он работает довольно быстро, особенно на небольших диапазонах.
Select value from dbo.intRange(-500, 1500) order by value -- returns 2001 values
create function dbo.intRange
(
@Starting as int,
@Ending as int
)
returns table
as
return (
select value
from (
select @Starting +
( bit00.v | bit01.v | bit02.v | bit03.v
| bit04.v | bit05.v | bit06.v | bit07.v
| bit08.v | bit09.v | bit10.v | bit11.v
| bit12.v | bit13.v | bit14.v | bit15.v
| bit16.v | bit17.v | bit18.v | bit19.v
) as value
from (select 0 as v union ALL select 0x00001 as v) as bit00
cross join (select 0 as v union ALL select 0x00002 as v) as bit01
cross join (select 0 as v union ALL select 0x00004 as v) as bit02
cross join (select 0 as v union ALL select 0x00008 as v) as bit03
cross join (select 0 as v union ALL select 0x00010 as v) as bit04
cross join (select 0 as v union ALL select 0x00020 as v) as bit05
cross join (select 0 as v union ALL select 0x00040 as v) as bit06
cross join (select 0 as v union ALL select 0x00080 as v) as bit07
cross join (select 0 as v union ALL select 0x00100 as v) as bit08
cross join (select 0 as v union ALL select 0x00200 as v) as bit09
cross join (select 0 as v union ALL select 0x00400 as v) as bit10
cross join (select 0 as v union ALL select 0x00800 as v) as bit11
cross join (select 0 as v union ALL select 0x01000 as v) as bit12
cross join (select 0 as v union ALL select 0x02000 as v) as bit13
cross join (select 0 as v union ALL select 0x04000 as v) as bit14
cross join (select 0 as v union ALL select 0x08000 as v) as bit15
cross join (select 0 as v union ALL select 0x10000 as v) as bit16
cross join (select 0 as v union ALL select 0x20000 as v) as bit17
cross join (select 0 as v union ALL select 0x40000 as v) as bit18
cross join (select 0 as v union ALL select 0x80000 as v) as bit19
) intList
where @Ending - @Starting < 0x100000
and intList.value between @Starting and @Ending
)
;WITH u AS (
SELECT Unit FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) v(Unit)
),
d AS (
SELECT
(Thousands+Hundreds+Tens+Units) V
FROM
(SELECT Thousands = Unit * 1000 FROM u) Thousands
,(SELECT Hundreds = Unit * 100 FROM u) Hundreds
,(SELECT Tens = Unit * 10 FROM u) Tens
,(SELECT Units = Unit FROM u) Units
WHERE
(Thousands+Hundreds+Tens+Units) <= 10000
)
SELECT * FROM d ORDER BY v
Я сделал ниже функцию после прочтения этой темы. Просто и быстро:
go
create function numbers(@begin int, @len int)
returns table as return
with d as (
select 1 v from (values(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d(v)
)
select top (@len) @begin -1 + row_number() over(order by (select null)) v
from d d0
cross join d d1
cross join d d2
cross join d d3
cross join d d4
cross join d d5
cross join d d6
cross join d d7
go
select * from numbers(987654321,500000)