Recientemente, me dieron la tarea de imprimir todos los números primos (1-100). Fallé drásticamente allí. Mi código:
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
Aunque terminé sin completarlo, me pregunto si es factible hacer dichos programas en la base de datos (SQL Server 2008 R2).
En caso afirmativo, cómo puede terminar.
sql-server
sql-server-2008-r2
t-sql
ispostback
fuente
fuente
Respuestas:
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?
Por supuesto, si necesita calcular los números primos entre 1 y 100, lo siguiente es bastante eficiente:
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):
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
ALCANCE: 1 - 10,000
ALCANCE: 1 - 100,000
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ó en1
. Reemplacé laDividend.num <= @endnum
línea conDividend.num BETWEEN @startnum AND @endnum
.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).
fuente
ROW_NUMBER() OVER (ORDER BY (SELECT 1))
? ¿NoROW_NUMBER() OVER ()
sería equivalente?OVER ()
, obtendrá el siguiente error:The function 'ROW_NUMBER' must have an OVER clause with ORDER BY.
. Y, conORDER BY
, no puede ser una constante, de ahí la subconsulta para devolver una constante.DECLARE @RangeStart INT = 999900, @RangeEnd INT = 1000000;
funciona pero tan pronto como lo configuroDECLARE @RangeStart INT = 9999999900, @RangeEnd INT = 10000000000;
diceMsg 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
. El valor máximo queINT
puede contener es 2,147,483,647, que es menor que su valor inicial de 9,999,999,900. Obtiene ese error incluso si ejecuta solo elDECLARE
. Puede intentar cambiar los tipos de datos variables para que seanBIGINT
y ver cómo funciona. Es posible que se necesiten otros cambios menores para respaldar eso. Para los rangos de tipo de datos, consulte: int, bigint, smallint y tinyint .Sería una forma simple pero no muy eficiente de devolver los números primos en el rango 2-100 (1 no es primo)
También podría materializar los números del 2 al 100 en una tabla e implementar el Tamiz de Eratóstenes mediante actualizaciones o eliminaciones repetidas.
fuente
Sí, es factible, pero no creo que T-SQL sea la herramienta adecuada para el trabajo. A continuación se muestra un ejemplo de un enfoque basado en conjuntos en T-SQL para este problema.
fuente
Podemos escribir el siguiente código y funciona:
Arriba he creado un Procedimiento almacenado para obtener números primos.
Para conocer los resultados, ejecute el procedimiento almacenado:
fuente
fuente