Saya memiliki dua angka sebagai masukan dari pengguna, seperti misalnya 1000
dan 1050
.
Bagaimana cara menghasilkan angka di antara dua angka ini, menggunakan kueri sql, dalam baris terpisah? Saya ingin ini:
1000
1001
1002
1003
.
.
1050
sql
sql-server
tsql
sql-server-2008
pengguna3211705
sumber
sumber
solusi alternatifnya adalah CTE rekursif:
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)
sumber
SELECT DISTINCT n = number FROM master..[spt_values] WHERE number BETWEEN @start AND @end
Demo
Perhatikan bahwa tabel ini memiliki maksimum 2048 karena jumlahnya memiliki celah.
Berikut adalah pendekatan yang sedikit lebih baik menggunakan tampilan sistem (sejak dari 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;
Demo
atau gunakan tabel angka khusus. Penghargaan untuk Aaron Bertrand, saya sarankan untuk membaca seluruh artikel: Hasilkan satu set atau urutan tanpa loop
sumber
WHERE type = 'P'
dan menghindariSELECT DISTINCT
String index out of range: 33
Saya baru-baru ini menulis fungsi nilai tabel sebaris ini untuk memecahkan masalah ini. Itu tidak terbatas dalam jangkauan selain memori dan penyimpanan. Itu tidak mengakses tabel sehingga tidak perlu membaca atau menulis disk secara umum. Ini menambahkan nilai gabungan secara eksponensial pada setiap iterasi sehingga sangat cepat bahkan untuk rentang yang sangat besar. Ini membuat sepuluh juta catatan dalam lima detik di server saya. Ini juga bekerja dengan nilai negatif.
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);
Ini berguna untuk rentang tanggal dan waktu juga:
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'));
Anda bisa menggunakan gabungan penerapan silang di atasnya untuk memisahkan rekaman berdasarkan nilai dalam tabel. Jadi misalnya untuk membuat rekor untuk setiap menit pada rentang waktu dalam tabel, Anda dapat melakukan sesuatu seperti:
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
sumber
SELECT X FROM fn_ConsecutiveNumbers(5, 500) ORDER BY X;
Opsi terbaik yang saya gunakan adalah sebagai berikut:
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
Saya telah menghasilkan jutaan rekaman menggunakan ini dan bekerja dengan sempurna.
sumber
Ini berhasil untuk saya!
select top 50 ROW_NUMBER() over(order by a.name) + 1000 as Rcount from sys.all_objects a
sumber
sys.all_objects
- untuk rentang kecil <2000 item, ini bukan masalah. Tidak yakin apakah akan ada masalah perizinan? sempurna untuk menghasilkan sekumpulan data uji dengan cepat.select top 50 ROW_NUMBER() over(order by a.name) + 1000 as Rcount from sys.all_objects a, sys.all_objects b
. Jika sebelumnya saya hanya dapat menghasilkan 2.384 baris, sekarang saya dapat menghasilkan 5683456 baris.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
sumber
Cara terbaik adalah menggunakan ctes rekursif.
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.
sumber
Jika Anda tidak memiliki masalah menginstal perakitan CLR di server Anda, opsi yang baik adalah menulis fungsi nilai tabel di .NET. Dengan begitu Anda dapat menggunakan sintaks sederhana, membuatnya mudah untuk digabungkan dengan kueri lain dan sebagai bonus tidak akan membuang memori karena hasilnya dialirkan.
Buat proyek yang berisi kelas berikut:
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() { } } }
Letakkan perakitan di suatu tempat di server dan jalankan:
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];
Sekarang Anda dapat menjalankan:
select * from dbo.seq(1, 1000000)
sumber
Tidak ada yang baru selain saya menulis ulang solusi Brian Pressler agar lebih enak dipandang, mungkin berguna bagi seseorang (meskipun itu hanya saya di masa depan):
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
sumber
ROW_NUMBER()
tidak memiliki masalah itu.2 tahun kemudian, tetapi saya menemukan saya memiliki masalah yang sama. Inilah cara saya menyelesaikannya. (diedit untuk memasukkan parameter)
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)
sumber
Jawaban slartidan dapat ditingkatkan, performa bijaksana, dengan menghilangkan semua referensi ke produk cartesian dan menggunakan
ROW_NUMBER()
sebagai gantinya ( perbandingan rencana eksekusi ):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
Bungkus di dalam CTE dan tambahkan klausa where untuk memilih nomor yang diinginkan:
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
sumber
SELECT ROW_NUMBER() OVER (...) - 1 AS n
. Dalam beberapa kasus, ini mungkin mematikan kinerja.Berikut adalah beberapa solusi yang cukup optimal dan kompatibel:
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 ;
sumber
select
ingwhere spt_values.number between @min and @max
?Saya tahu saya terlambat 4 tahun, tetapi saya menemukan jawaban alternatif lain untuk masalah ini. Masalah kecepatan bukan hanya pra-pemfilteran, tetapi juga mencegah penyortiran. Dimungkinkan untuk memaksa perintah gabungan untuk dieksekusi dengan cara yang benar-benar dihitung oleh produk Cartesian sebagai hasil dari penggabungan. Menggunakan jawaban slartidan sebagai titik lompatan:
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
Jika kita mengetahui kisaran yang kita inginkan, kita dapat menentukannya melalui @Upper dan @Lower. Dengan menggabungkan REMOTE petunjuk gabungan bersama dengan TOP, kita hanya dapat menghitung subset dari nilai yang kita inginkan tanpa ada yang terbuang.
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
Petunjuk gabungan REMOTE memaksa pengoptimal membandingkan di sisi kanan gabungan terlebih dahulu. Dengan menentukan setiap gabungan sebagai REMOTE dari nilai paling signifikan hingga paling tidak signifikan, gabungan itu sendiri akan dihitung satu per satu dengan benar. Tidak perlu memfilter dengan WHERE, atau mengurutkan dengan ORDER BY.
Jika Anda ingin meningkatkan rentang, Anda dapat terus menambahkan gabungan tambahan dengan urutan besaran yang semakin tinggi, selama mereka diurutkan dari yang paling signifikan hingga yang paling tidak signifikan dalam klausa FROM.
Perhatikan bahwa ini adalah kueri khusus untuk SQL Server 2008 atau lebih tinggi.
sumber
Ini juga akan dilakukan
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
sumber
Kecepatan terbaik saat menjalankan kueri
DECLARE @num INT = 1000 WHILE(@num<1050) begin INSERT INTO [dbo].[Codes] ( Code ) VALUES (@num) SET @num = @num + 1 end
sumber
CTE rekursif dalam ukuran eksponensial (bahkan untuk default 100 rekursi, ini dapat membangun hingga 2 ^ 100 angka):
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
sumber
@startnum
danendnum
harus diinput oleh user?Saya harus memasukkan filepath gambar ke dalam database menggunakan metode serupa. Kueri di bawah berfungsi dengan baik:
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
Kode untuk Anda adalah:
DECLARE @num INT = 1000 WHILE(@num<1051) begin SELECT @num SET @num = @num + 1 end
sumber
Ini yang saya lakukan, cukup cepat dan fleksibel dan tidak banyak kode.
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;
Perhatikan bahwa (ORDER BY @count) adalah dummy. Itu tidak melakukan apa pun kecuali ROW_NUMBER () membutuhkan ORDER BY.
Sunting : Saya menyadari bahwa pertanyaan awal adalah mendapatkan rentang dari x ke y. Skrip saya dapat dimodifikasi seperti ini untuk mendapatkan kisaran:
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;
sumber
Pembaruan untuk SQL 2017 dan yang lebih baru: Jika urutan yang Anda inginkan <8k maka ini akan berfungsi:
Declare @start_num int = 1000 , @end_num int = 1050 Select [number] = @start_num + ROW_NUMBER() over (order by (Select null)) from string_split(replicate(' ',@end_num-@start_num-1),' ')
sumber
-- 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
sumber
Ini hanya berfungsi untuk urutan selama beberapa tabel aplikasi memiliki baris. Asumsikan saya ingin urutan dari 1..100, dan memiliki tabel aplikasi dbo.foo dengan kolom (tipe numerik atau string) foo.bar:
select top 100 row_number() over (order by dbo.foo.bar) as seq from dbo.foo
Meskipun ada dalam urutan menurut klausa, dbo.foo.bar tidak harus memiliki nilai yang berbeda atau bahkan bukan nol.
Tentu saja, SQL Server 2012 memiliki objek urutan, jadi ada solusi alami dalam produk tersebut.
sumber
Inilah yang saya dapatkan:
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
Menghasilkan hingga 2 ^ 24 nilai. Kondisi bergabung tetap cepat untuk nilai-nilai kecil.
sumber
Ini selesai untuk saya dalam 36 detik di server DEV kami. Seperti jawaban Brian, fokus pada pemfilteran ke kisaran penting dari dalam kueri; a BETWEEN masih mencoba untuk menghasilkan semua catatan awal sebelum batas bawah meskipun tidak membutuhkannya.
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
Perhatikan bahwa ROW_NUMBER adalah bigint , jadi kita tidak bisa melewati 2 ^^ 64 (== 16 ^^ 16) menghasilkan record dengan metode apa pun yang menggunakannya. Oleh karena itu, kueri ini menghormati batas atas yang sama pada nilai yang dihasilkan.
sumber
Ini menggunakan kode prosedural dan fungsi nilai tabel. Lambat, tetapi mudah dan dapat diprediksi.
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
Pemakaian:
SELECT * FROM dbo.Sequence (3,7); ID 3 4 5 6 7
Ini adalah tabel, jadi Anda bisa menggunakannya dalam gabungan dengan data lain. Saya paling sering menggunakan fungsi ini sebagai sisi kiri gabungan terhadap GROUP BY jam, hari, dll untuk memastikan urutan nilai waktu yang berdekatan.
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 (...)
Performanya tidak menarik (16 detik untuk sejuta baris) tetapi cukup baik untuk banyak tujuan.
SELECT count(1) FROM [dbo].[Sequence] ( 1000001 ,2000000) GO
sumber
Oracle 12c; Cepat tapi terbatas:
select rownum+1000 from all_objects fetch first 50 rows only;
Catatan : terbatas pada jumlah baris tampilan all_objects;
sumber
Solusi yang telah saya kembangkan dan gunakan untuk beberapa waktu sekarang (menunggangi beberapa karya bersama orang lain) sedikit mirip dengan setidaknya satu yang diposting. Itu tidak mereferensikan tabel apa pun dan mengembalikan rentang yang tidak diurutkan hingga 1048576 nilai (2 ^ 20) dan dapat menyertakan negatif jika diinginkan. Anda tentu saja dapat menyortir hasilnya jika perlu. Ini berjalan cukup cepat, terutama pada jarak yang lebih kecil.
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 )
sumber
;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
sumber
Saya membuat fungsi di bawah ini setelah membaca utas ini. Sederhana dan cepat:
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)
sumber
Berikut adalah solusi umum dan relatif cepat yang menghasilkan bilangan bulat dari 1 hingga
@n
. Ini berfungsi dengan bilangan bulat positif apa pun@n
(angka yang sangat besar akan menyebabkan luapan aritmatika) tanpa perlu menambah atau menghapus gabungan tabel. Itu tidak memerlukan penggunaan tabel sistem dan Anda juga tidak mengubah rekursi maksimal.declare @n int = 10000 ;with d as (select * from (values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) x (d)), n as ( select d x from d where d > 0 and d <= @n union all select x * 10 + d from n, d where x * 10 + d <= @n ) select x from n
Anda dapat menambahkan
order by
klausa untuk mengurutkan angka.sumber