2009-09-25 32 views
12

Necesito obtener un conjunto de resultados que contenga los primeros N enteros positivos. ¿Es posible utilizar solo la instrucción SQL SELECT estándar para obtenerlos (sin contar con ninguna tabla de recuento)?SQL SELECT para obtener los primeros N enteros positivos

Si no es posible, ¿hay alguna forma específica de MySQL para lograr esto?

+0

Primero en qué definición? –

Respuesta

15

Parece que lo que quiere es un dummy rowset.

En MySQL, es imposible sin tener una mesa.

La mayoría de los principales sistemas proporcionan una manera de hacerlo:

  • En Oracle:

    SELECT level 
    FROM dual 
    CONNECT BY 
         level <= 10 
    
  • En SQL Server:

    WITH q AS 
         (
         SELECT 1 AS num 
         UNION ALL 
         SELECT num + 1 
         FROM q 
         WHERE num < 10 
         ) 
    SELECT * 
    FROM q 
    
  • En PostgreSQL:

    SELECT num 
    FROM generate_series(1, 10) num 
    

MySQL le falta algo como esto y esto es un serio inconveniente.

me escribió un script sencillo para generar datos de prueba para las tablas de ejemplo en mi blog, tal vez va a ser de utilidad:

CREATE TABLE filler (
     id INT NOT NULL PRIMARY KEY AUTO_INCREMENT 
) ENGINE=Memory; 

CREATE PROCEDURE prc_filler(cnt INT) 
BEGIN 
     DECLARE _cnt INT; 
     SET _cnt = 1; 
     WHILE _cnt <= cnt DO 
       INSERT 
       INTO filler 
       SELECT _cnt; 
       SET _cnt = _cnt + 1; 
     END WHILE; 
END 
$$ 

se llama al procedimiento y la mesa se llena con los números.

Puede reutilizarlo durante la sesión.

+0

Gran respuesta. Esto seguro es útil. – monn

2

Suponiendo que se refiere a recuperarlos de una tabla, aquí N es 10, suponiendo que intcolumn es la columna con números en ella.

SELECT intcolumn FROM numbers WHERE intcolumn > 0 LIMIT 10 

Editar: En caso de que se busca en realidad para obtener el conjunto matemático de los números positivos y sin una mesa, me volvería a considerar, puede ser intensivos (dependiendo de la aplicación). La práctica comúnmente aceptada parece ser crear una tabla de búsqueda llena de números y luego usar la consulta anterior.

+0

simplemente cambie> = a> para obtener solo resultados positivos. – dusoft

+0

¿0 se considera positivo o negativo? – rahul

+0

Acabo de verificar, aparentemente la definición de números positivos es mayor que 0. Aparentemente cero no es ninguno (según wikipedia). – Kazar

0

Tome un vistazo a los del followhing SO preguntas:

Editar:

Otro abordaje es crear un procedimiento almacenado que hace eso para ti. PostgreSQL contiene una función generate_series (start, stop) que hace lo que quiere.

select * from generate_series(2,4); 
generate_series 
----------------- 
       2 
       3 
       4 
(3 rows) 

No estoy familiarizado con MySQL, pero algo como eso debería ser fácil de implementar, si están de acuerdo con los SP. This sitio muestra una implementación.

+0

Parecería que ambos métodos requieren una tabla de búsqueda de alguna forma (usando AUTO_INCREMENT) – Kazar

0

Estoy bastante seguro de que no puede hacerlo, si entiendo su pregunta correctamente.

Como entiendo su pregunta, ¿desea la lista, a partir de una sola declaración de SQL, sin tener que hacer referencia a una tabla específica?

Estoy bastante seguro de que no es posible en ningún dialecto SQL. Si tuvieras que obtener un número de incremento secuencial junto con los resultados de otra consulta, entonces eso sería posible (dependiendo del dialecto de SQL, en mssql sería rownumber(), pero no sé cómo en MySql, pero es probable que allí)

¿Pero no es eso lo que oigo preguntar?

+0

En PostgreSQL hay una función llamada generate_series (start, stop) que hace exactamente lo que el OP quiere. –

1

Esto puede ayudar

Para obtener una R número entero aleatorio en el rango i < = R < j, utilice el FLOOR expresión (i + RAND() * (j - i)). Por ejemplo, para obtener un número entero aleatorio en el rango entre el 7 y R = < < 12, se podría utilizar la siguiente instrucción:

SELECT FLOOR(7 + (RAND() * 5));

+0

Pregunta sobre enteros positivos consecutivos. No sobre aleatorio. –

4

solución extraño, pero ...

SELECT 1 UNION SELECT 2 UNION SELECT 3.... 
2

La secuencia propongo permite al programador ejecutar la siguiente consulta:

select value from sequence where value>=15 and value<100; 

Y para obtener los resultados esperados: la secuencia de números enteros entre 15 (inclusive) y 100 (exclusivo).

Si eso es lo que quiere, tendrá que crear los siguientes dos vistas, vistas que declararemos una sola vez:

create view digits as select 0 n union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9; 

create view sequence as select u.n+t.n*10+h.n*100 as value from digits as u cross join digits as t cross join digits as h; 

De esta manera tiene la secuencia con un SELECT intuitiva ...

Espero que ayude.

+0

¡Loco! ...y funciona. Necesitaba algo que funcionara en una vista: el uso de la asignación en una variable está bloqueado para las vistas. Bonito. –

9

Una posible solución (no muy elegante) es utilizar cualquier tabla con un número suficientemente grande de registros.

Durante los primeros 10 números enteros (utilizando el mysql.help_relation, pero cualquier tabla haría), se puede utilizar la siguiente consulta:

SELECT @N := @N +1 AS integers 
FROM mysql.help_relation , (SELECT @N:=0) dum LIMIT 10; 

Esto también pueden clasificarse en función de tomar mínimo y máximo.

+1

Gracias por la sugerencia. utilizó con éxito lo siguiente para obtener un rango de fechas: 'SELECT @i: = DATE_SUB (@i, INTERVAL 1 DAY) date FROM mysql.help_relation, (SELECT @i: = CURRENT_DATE) v WHERE @i> DATE_SUB (CURRENT_DATE, INTERVAL) 3 MES); '. –

+0

Esto no es una solución genérica. Funciona, siempre que la tabla utilizada tenga al menos la cantidad de filas que desea obtener. Cree una tabla ficticia sin filas, y SELECCIONE @N: = @ N + 1 AS enteros FROM dummy, (SELECT @N: = 0) dum LIMIT 10 no produce filas. – user1645975

+0

Puede ser viejo, pero esto es increíble. Sabía que algo así debía existir. – slicedtoad

1

Si sabe que N es limitado (y generalmente lo es), se puede utilizar una construcción, tales como:

select (a.digit + (10 * b.digit) + (100 * c.digit) + (1000 * d.digit) + (10000 * e.digit) + (100000 * f.digit)) as n 
    from (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as d 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as e 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as f; 

que generará el primer millón de números. Si solo necesita los números positivos, simplemente agregue + 1 a la expresión.

Tenga en cuenta que en MySQL en particular, los resultados pueden no estar ordenados.Debe agregar order by n al final si necesita números solicitados. Esto aumentará el tiempo de ejecución dramáticamente, sin embargo (en mi máquina, saltó de 5 ms a 500 ms).

Para consultas simples, aquí es una consulta para sólo los primeros 10000 números:

select (a.digit + (10 * b.digit) + (100 * c.digit) + (1000 * d.digit)) as n 
    from (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c 
    cross join (select 0 as digit union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as d; 

Esta respuesta es una adaptación de la siguiente consulta que devuelve un rango de fechas: https://stackoverflow.com/a/2157776/2948

0

Si su base de datos soporta ventanas analítica funciones la siguiente es obras sencillas muy bien:

SELECT row_number() over (partition by 1 order by 1) numbers 
FROM SOME_TABLE 
LIMIT 2700; 

Esta instrucción devuelve un conjunto de números del 1 al 2700.

Cuestiones relacionadas