Mam dwie liczby jako dane wejściowe od użytkownika, jak na przykład 1000
i1050
.
Jak wygenerować liczby między tymi dwiema liczbami, używając zapytania sql, w oddzielnych wierszach? Chcę to:
1000
1001
1002
1003
.
.
1050
sql
sql-server
tsql
sql-server-2008
user3211705
źródło
źródło
alternatywnym rozwiązaniem jest rekurencyjne CTE:
źródło
Demo
Zauważ, że ta tabela ma maksymalnie 2048, ponieważ wtedy liczby mają luki.
Oto nieco lepsze podejście przy użyciu widoku systemu (od wersji SQL-Server 2005):
Demo
lub użyj niestandardowej tabeli liczbowej. Podziękowania dla Aarona Bertranda, proponuję przeczytać cały artykuł: Wygeneruj zestaw lub sekwencję bez pętli
źródło
WHERE type = 'P'
i uniknąćSELECT DISTINCT
String index out of range: 33
Niedawno napisałem tę funkcję wartościowaną w tabeli inline, aby rozwiązać ten właśnie problem. Nie jest ograniczony zasięgiem innym niż pamięć i przechowywanie. Nie uzyskuje dostępu do tabel, więc nie ma potrzeby wykonywania odczytów ani zapisów na dysku. Dodaje wartości złączeń wykładniczo przy każdej iteracji, dzięki czemu jest bardzo szybki nawet dla bardzo dużych zakresów. Tworzy dziesięć milionów rekordów w pięć sekund na moim serwerze. Działa również z wartościami ujemnymi.
Jest to przydatne również w przypadku zakresów dat i godzin:
Możesz użyć na nim sprzężenia krzyżowego, aby podzielić rekordy na podstawie wartości w tabeli. Na przykład, aby utworzyć rekord dla każdej minuty w zakresie czasu w tabeli, możesz zrobić coś takiego:
źródło
SELECT X FROM fn_ConsecutiveNumbers(5, 500) ORDER BY X;
Najlepsza opcja, z której korzystałem, jest następująca:
Wygenerowałem miliony rekordów za pomocą tego i działa idealnie.
źródło
To działa dla mnie!
źródło
sys.all_objects
- w przypadku małych zakresów <2000 elementów nie stanowi to problemu. Nie jesteś pewien, czy będzie miał problemy z uprawnieniami? idealne do szybkiego generowania partii danych testowych.select top 50 ROW_NUMBER() over(order by a.name) + 1000 as Rcount from sys.all_objects a, sys.all_objects b
. Tam, gdzie wcześniej mogłem wygenerować tylko 2384 wiersze, teraz mogę wygenerować wiersze 5683456.Najlepszym sposobem jest użycie rekurencyjnych ctes.
saludos.
źródło
źródło
Jeśli nie masz problemu z instalacją zestawu CLR na serwerze, dobrym rozwiązaniem jest napisanie funkcji wartościowanej tabelowo w .NET. W ten sposób możesz użyć prostej składni, dzięki czemu łatwo będzie łączyć się z innymi zapytaniami, a jako bonus nie marnujesz pamięci, ponieważ wynik jest przesyłany strumieniowo.
Utwórz projekt zawierający następującą klasę:
Umieść zestaw gdzieś na serwerze i uruchom:
Teraz możesz biegać:
źródło
Nic nowego, ale przepisałem rozwiązanie Briana Presslera, aby było przyjemniejsze dla oka, może się komuś przydać (nawet jeśli to tylko przyszły mnie):
źródło
ROW_NUMBER()
nie mają tego problemu.2 lata później, ale okazało się, że mam ten sam problem. Oto jak to rozwiązałem. (edytowane w celu uwzględnienia parametrów)
źródło
Odpowiedź slartidana można poprawić, pod względem wydajności, poprzez wyeliminowanie wszelkich odniesień do produktu kartezjańskiego i użycie
ROW_NUMBER()
zamiast tego ( porównanie planu wykonania ):Zawiń go wewnątrz CTE i dodaj klauzulę where, aby wybrać żądane liczby:
źródło
SELECT ROW_NUMBER() OVER (...) - 1 AS n
. W niektórych przypadkach może to obniżyć wydajność.Oto kilka całkiem optymalnych i kompatybilnych rozwiązań:
źródło
select
ingwhere spt_values.number between @min and @max
?Wiem, że spóźniłem się o 4 lata, ale natknąłem się na inną alternatywną odpowiedź na ten problem. Problem z szybkością to nie tylko wstępne filtrowanie, ale także zapobieganie sortowaniu. Możliwe jest wymuszenie wykonania kolejności łączenia w taki sposób, że iloczyn kartezjański faktycznie liczy się w wyniku łączenia. Wykorzystując odpowiedź Slartidana jako punkt wyjścia:
Jeśli znamy żądany zakres, możemy go określić za pomocą @Upper i @Lower. Łącząc wskazówkę o sprzężeniu REMOTE wraz z TOP, możemy obliczyć tylko podzbiór wartości, które chcemy, i nic nie zostanie zmarnowane.
Wskazówka dotycząca łączenia REMOTE wymusza na optymalizatorze porównanie najpierw po prawej stronie sprzężenia. Określając każde sprzężenie jako ZDALNE od najbardziej do najmniej znaczącej wartości, samo sprzężenie będzie poprawnie liczyć w górę o jeden. Nie ma potrzeby filtrowania za pomocą GDZIE lub sortowania według ZAMÓWIENIA.
Jeśli chcesz zwiększyć zakres, możesz kontynuować dodawanie dodatkowych sprzężeń o stopniowo wyższych rzędach wielkości, o ile są uporządkowane od najbardziej do najmniej znaczących w klauzuli FROM.
Zauważ, że jest to zapytanie specyficzne dla SQL Server 2008 lub nowszego.
źródło
To też wystarczy
źródło
Najlepsza prędkość podczas wykonywania zapytania
źródło
rekurencyjne CTE o rozmiarze wykładniczym (nawet przy domyślnej rekursji 100, może to zbudować do 2 ^ 100 liczb):
źródło
@startnum
iendnum
powinienem być wprowadzany przez użytkownika?Musiałem wstawić ścieżkę pliku obrazu do bazy danych przy użyciu podobnej metody. Poniższe zapytanie zadziałało dobrze:
Kod dla ciebie byłby:
źródło
To właśnie robię, jest to dość szybkie i elastyczne i nie zawiera dużo kodu.
Zauważ, że (ORDER BY @count) jest atrapą. To nic nie robi, ale ROW_NUMBER () wymaga ORDER BY.
Edycja : zdałem sobie sprawę, że pierwotnym pytaniem było uzyskanie zakresu od x do y. Mój skrypt można zmodyfikować w ten sposób, aby uzyskać zakres:
źródło
źródło
Działa to tylko w przypadku sekwencji, o ile tabela aplikacji zawiera wiersze. Załóżmy, że chcę sekwencję od 1..100 i mam tabelę aplikacji dbo.foo z kolumną (typu numerycznego lub łańcuchowego) foo.bar:
Pomimo swojej obecności w klauzuli order by, dbo.foo.bar nie musi mieć odrębnych ani nawet niezerowych wartości.
Oczywiście SQL Server 2012 ma obiekty sekwencyjne, więc ten produkt jest naturalnym rozwiązaniem.
źródło
Oto, co wymyśliłem:
Generuje maksymalnie 2 ^ 24 wartości. Warunki łączenia utrzymują go szybko dla małych wartości.
źródło
Ukończyło się to dla mnie w 36 sekund na naszym serwerze DEV. Podobnie jak odpowiedź Briana, skupienie się na filtrowaniu do zakresu jest ważne od samego początku zapytania; a BETWEEN nadal próbuje wygenerować wszystkie początkowe rekordy przed dolną granicą, nawet jeśli ich nie potrzebuje.
Zauważ, że ROW_NUMBER to bigint , więc nie możemy przejść przez 2 ^^ 64 (== 16 ^^ 16) wygenerowanych rekordów żadną metodą, która go używa. Dlatego to zapytanie przestrzega tego samego górnego limitu generowanych wartości.
źródło
Używa kodu proceduralnego i funkcji wycenianej w tabeli. Powolny, ale łatwy i przewidywalny.
Stosowanie:
Jest to tabela, więc możesz jej używać w połączeniach z innymi danymi. Najczęściej używam tej funkcji jako lewej strony sprzężenia z GRUPĄ według godziny, dnia itp., Aby zapewnić ciągłą sekwencję wartości czasu.
Wydajność jest mało inspirująca (16 sekund na milion wierszy), ale wystarczająca do wielu celów.
źródło
Oracle 12c; Szybki, ale ograniczony:
Uwaga : ograniczona do liczby wierszy widoku all_objects;
źródło
Rozwiązanie, które opracowałem i używam już od jakiegoś czasu (jeżdżę na udostępnionych pracach innych) jest nieco podobne do przynajmniej jednego opublikowanego. Nie odwołuje się do żadnych tabel i zwraca nieposortowany zakres do 1048576 wartości (2 ^ 20) i w razie potrzeby może zawierać negatywy. W razie potrzeby możesz oczywiście posortować wynik. Działa dość szybko, zwłaszcza na mniejszych dystansach.
źródło
źródło
Poniższą funkcję wykonałem po przeczytaniu tego wątku. Prosto i szybko:
źródło