Con mucho, la forma más rápida y fácil de imprimir "todos los números primos (1-100)" es aceptar plenamente el hecho de que los números primos son un conjunto de valores conocido, finito e inmutable ("conocido" y "finito" dentro de un rango particular, por supuesto). A esta pequeña escala, ¿por qué desperdiciar CPU cada vez para calcular un montón de valores que se conocen desde hace mucho tiempo, y apenas ocupa memoria para almacenar?
SELECT tmp.[Prime]
FROM (VALUES (2), (3), (5), (7), (11), (13),
(17), (19), (23), (29), (31), (37), (41),
(43), (47), (53), (59), (61), (67), (71),
(73), (79), (83), (89), (97)) tmp(Prime)
Por supuesto, si necesita calcular los números primos entre 1 y 100, lo siguiente es bastante eficiente:
;WITH base AS
(
SELECT tmp.dummy, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [num]
FROM (VALUES (0), (0), (0), (0), (0), (0), (0)) tmp(dummy)
), nums AS
(
SELECT (ROW_NUMBER() OVER (ORDER BY (SELECT 1)) * 2) + 1 AS [num]
FROM base b1
CROSS JOIN base b2
), divs AS
(
SELECT [num]
FROM base b3
WHERE b3.[num] > 4
AND b3.[num] % 2 <> 0
AND b3.[num] % 3 <> 0
)
SELECT given.[num] AS [Prime]
FROM (VALUES (2), (3)) given(num)
UNION ALL
SELECT n.[num] AS [Prime]
FROM nums n
WHERE n.[num] % 3 <> 0
AND NOT EXISTS (SELECT *
FROM divs d
WHERE d.[num] <> n.[num]
AND n.[num] % d.[num] = 0
);
Esta consulta solo prueba números impares ya que los números pares no serán primos de todos modos. También es específico para el rango de 1 a 100.
Ahora, si necesita un rango dinámico (similar a lo que se muestra en el código de ejemplo en la pregunta), la siguiente es una adaptación de la consulta anterior que aún es bastante eficiente (calculó el rango de 1 - 100,000 - 9592 entradas - en menos de 1 segundo):
DECLARE @RangeStart INT = 1,
@RangeEnd INT = 100000;
DECLARE @HowMany INT = CEILING((@RangeEnd - @RangeStart + 1) / 2.0);
;WITH frst AS
(
SELECT tmp.thing1
FROM (VALUES (0), (0), (0), (0), (0), (0), (0), (0), (0), (0)) tmp(thing1)
), scnd AS
(
SELECT 0 AS [thing2]
FROM frst t1
CROSS JOIN frst t2
CROSS JOIN frst t3
), base AS
(
SELECT TOP( CONVERT( INT, CEILING(SQRT(@RangeEnd)) ) )
ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS [num]
FROM scnd s1
CROSS JOIN scnd s2
), nums AS
(
SELECT TOP (@HowMany)
(ROW_NUMBER() OVER (ORDER BY (SELECT 1)) * 2) +
(@RangeStart - 1 - (@RangeStart%2)) AS [num]
FROM base b1
CROSS JOIN base b2
), divs AS
(
SELECT [num]
FROM base b3
WHERE b3.[num] > 4
AND b3.[num] % 2 <> 0
AND b3.[num] % 3 <> 0
)
SELECT given.[num] AS [Prime]
FROM (VALUES (2), (3)) given(num)
WHERE given.[num] >= @RangeStart
UNION ALL
SELECT n.[num] AS [Prime]
FROM nums n
WHERE n.[num] BETWEEN 5 AND @RangeEnd
AND n.[num] % 3 <> 0
AND NOT EXISTS (SELECT *
FROM divs d
WHERE d.[num] <> n.[num]
AND n.[num] % d.[num] = 0
);
Mi prueba (usando SET STATISTICS TIME, IO ON;
) muestra que esta consulta funciona mejor que las otras dos respuestas dadas (hasta ahora):
ALCANCE: 1-100
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Solomon 0 0 0
Dan 396 0 0
Martin 394 0 1
ALCANCE: 1 - 10,000
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Solomon 0 47 170
Dan 77015 2547 2559
Martin n/a
ALCANCE: 1 - 100,000
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Solomon 0 984 996
Dan 3,365,469 195,766 196,650
Martin n/a
ALCANCE: 99,900 - 100,000
NOTA : Para ejecutar esta prueba, tuve que corregir un error en el código de Dan; @startnum
no se incluyó en la consulta, por lo que siempre comenzó en 1
. Reemplacé la Dividend.num <= @endnum
línea con Dividend.num BETWEEN @startnum AND @endnum
.
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Solomon 0 0 1
Dan 0 157 158
Martin n/a
ALCANCE: 1 - 100,000 (nueva prueba parcial)
Después de arreglar la consulta de Dan para la prueba 99,900 - 100,000, noté que no había más lecturas lógicas en la lista. Así que volví a probar este rango con esa corrección aún aplicada y descubrí que las lecturas lógicas habían desaparecido nuevamente y los tiempos eran ligeramente mejores (y sí, se devolvió el mismo número de filas).
Query Logical Reads CPU Milliseconds Elapsed Milliseconds
------- ---------------- ---------------- -----------------
Dan 0 179,594 180,096