Ostatnio otrzymałem zadanie wydrukowania wszystkich liczb pierwszych (1-100). Tam drastycznie mi się nie udało. Mój kod:
Create Procedure PrintPrimeNumbers
@startnum int,
@endnum int
AS
BEGIN
Declare @a INT;
Declare @i INT = 1
(
Select a = @startnum / 2;
WHILE @i<@a
BEGIN
@startnum%(@a-@i)
i=i+1;
)
END
Chociaż nie udało mi się go ukończyć, zastanawiam się, czy jest możliwe wykonywanie takich programów w bazie danych (SQL Server 2008 R2).
Jeśli tak, jak to się skończy.
sql-server
sql-server-2008-r2
t-sql
ispostback
źródło
źródło
Odpowiedzi:
Zdecydowanie najszybszym i najłatwiejszym sposobem na wydrukowanie „wszystkich liczb pierwszych (1-100)” jest pełne uwzględnienie faktu, że liczby pierwsze są znanym, skończonym i niezmiennym zestawem wartości („znanym” i „skończonym” w obrębie oczywiście określony zakres). Na tak małą skalę, po co marnować procesor za każdym razem, aby obliczyć wiązkę wartości, które są znane od bardzo dawna i nie zajmują prawie żadnej pamięci do przechowywania?
Oczywiście, jeśli musisz obliczyć liczby pierwsze od 1 do 100, następujące działania są dość skuteczne:
To zapytanie sprawdza tylko liczby nieparzyste, ponieważ liczby parzyste i tak nie będą pierwsze. Jest również specyficzny dla zakresu od 1 do 100.
Teraz, jeśli potrzebujesz zakresu dynamicznego (podobnego do tego, który pokazano w przykładowym kodzie w pytaniu), to poniżej znajduje się dostosowanie powyższego zapytania, które jest nadal dość wydajne (obliczyło zakres 1 - 100 000 - 9592 wpisy - w niecałe 1 sekundę):
Moje testowanie (używanie
SET STATISTICS TIME, IO ON;
) pokazuje, że to zapytanie działa lepiej niż pozostałe dwie odpowiedzi (jak dotąd):ZAKRES: 1 - 100
ZAKRES: 1 - 10 000
ZAKRES: 1 - 100 000
ZAKRES: 99 900 - 100 000
UWAGA : Aby uruchomić ten test, musiałem naprawić błąd w kodzie Dana -
@startnum
nie został uwzględniony w zapytaniu, więc zawsze zaczynał się od1
. ZamieniłemDividend.num <= @endnum
linię naDividend.num BETWEEN @startnum AND @endnum
.ZAKRES: 1 - 100 000 (częściowy ponowny test)
Po naprawieniu zapytania Dana dla testu 99,900 - 100 000 zauważyłem, że nie ma już żadnych logicznych odczytów. Ponownie przetestowałem ten zakres z wciąż stosowaną poprawką i stwierdziłem, że logiczne odczyty znowu zniknęły, a czasy były nieco lepsze (i tak, zwrócono tę samą liczbę wierszy).
źródło
ROW_NUMBER() OVER (ORDER BY (SELECT 1))
? NieROW_NUMBER() OVER ()
byłby równoważny?OVER ()
, otrzymasz następujący błąd:The function 'ROW_NUMBER' must have an OVER clause with ORDER BY.
. I, zORDER BY
, nie może być stałą, stąd podkwerenda, aby zwrócić stałą.DECLARE @RangeStart INT = 999900, @RangeEnd INT = 1000000;
go używam , działa, ale gdy tylkoDECLARE @RangeStart INT = 9999999900, @RangeEnd INT = 10000000000;
go ustawię, mówiMsg 8115, Level 16, State 2, Line 1 Arithmetic overflow error converting expression to data type int. Msg 1014, Level 15, State 1, Line 5 A TOP or FETCH clause contains an invalid value.
?INT
. Maksymalna wartość, którąINT
można przechowywać, wynosi 2 147 483 647, czyli mniej niż początkowa wartość 9 999 999 900. Ten błąd występuje, nawet jeśli wykonasz tylkoDECLARE
. Możesz spróbować zmienić zmienne typy danychBIGINT
i sprawdzić, jak to działa . Możliwe jest, że w celu wsparcia tego będą potrzebne inne niewielkie zmiany. Aby uzyskać zakresy typów danych, zobacz: int, bigint, smallint i tinyint .Byłby to prosty, ale niezbyt skuteczny sposób zwracania liczb pierwszych w zakresie 2-100 (1 nie jest liczbą pierwszą)
Możesz także potencjalnie zmaterializować liczby 2-100 w tabeli i zaimplementować sito Eratostenesa poprzez powtarzające się aktualizacje lub usuwanie.
źródło
Tak, jest to wykonalne, ale nie sądzę, aby T-SQL był odpowiednim narzędziem do tego zadania. Poniżej znajduje się przykład podejścia opartego na zestawie w języku T-SQL dla tego problemu.
źródło
Możemy napisać poniższy kod i to działa:
Powyżej utworzyłem Procedurę składowaną w celu uzyskania liczb pierwszych.
Aby poznać wyniki, wykonaj procedurę przechowywaną:
źródło
źródło