2009-01-29 28 views
18

Tengo una consulta SQL, que devuelve un conjunto de filas:SQLServer consulta SQL con un contador de fila

SELECT id, name FROM users where group = 2 

necesito incluir también una columna que tiene un valor entero de incremento, por lo que la primera fila necesita tiene un 1 en la columna del contador, el segundo un 2, el tercero un 3 etc.

La consulta que se muestra aquí es solo un ejemplo simplificado, en realidad la consulta podría ser arbitrariamente compleja, con varias uniones y consultas anidadas.

Sé que esto se puede lograr utilizando una tabla temporal con un campo de autonumeración, pero ¿hay alguna forma de hacerlo dentro de la consulta misma?

Respuesta

24

Para empezar, algo a lo largo de las líneas de:

SELECT my_first_column, my_second_column, 
    ROW_NUMBER() OVER (ORDER BY my_order_column) AS Row_Counter 
FROM my_table 

Sin embargo, es importante tener en cuenta que la construcción ROW_NUMBER() OVER (ORDER BY ...) sólo determina los valores de Row_Counter, que no garantiza el orden de los resultados.

A menos que el SELECT tenga una cláusula explícita ORDER BY, los resultados podrían devolverse en cualquier orden, dependiendo de cómo SQL Server decida optimizar la consulta. (. See this article for more info)

La única manera de garantizar que los resultados serán siempre ser devueltos en Row_Counter fin es aplicar exactamente el mismo orden tanto a la SELECT y la ROW_NUMBER():

SELECT my_first_column, my_second_column, 
    ROW_NUMBER() OVER (ORDER BY my_order_column) AS Row_Counter 
FROM my_table 
ORDER BY my_order_column -- exact copy of the ordering used for Row_Counter 

El patrón anterior siempre devolverá resultados en el orden correcto y funciona bien para consultas simples, pero ¿qué tal una consulta "arbitrariamente compleja" con quizás docenas de expresiones en la cláusula ORDER BY? En esas situaciones prefiero algo como esto en su lugar:

SELECT t.* 
FROM 
(
    SELECT my_first_column, my_second_column, 
     ROW_NUMBER() OVER (ORDER BY ...) AS Row_Counter -- complex ordering 
    FROM my_table 
) AS t 
ORDER BY t.Row_Counter 

Usando una consulta anidada significa que no hay necesidad de duplicar la complicada ORDER BY cláusula, lo que significa menos desorden y un mantenimiento más fácil. El exterior ORDER BY t.Row_Counter también hace que la intención de la consulta sea mucho más clara para sus compañeros desarrolladores.

+0

¿Por qué la consulta anidada? Con mi prueba rápida de ROW_NUMBER(), la consulta resultante terminó ordenada por el valor del contador de filas de todos modos. – andynormancx

+1

La consulta anidada anterior no es necesaria, pero ocasionalmente puede ser útil escribir "SELECT t. * FROM (...) as t WHERE t.Row_Counter BEWEEN 20 and 30" como una forma eficiente de enviar datos a la página. – Juliet

+0

La consulta anidada * es * obligatoria si desea garantizar que el conjunto de resultados siempre se devolverá en el orden de Fila_Counter para consultas "arbitrariamente complejas". (Consulte http://blogs.msdn.com/queryoptteam/archive/2006/05/02/588731.aspx para obtener más información.) – LukeH

10

En SQL Server 2005 en adelante, puede usar la función ROW_NUMBER(), que tiene opciones para el orden de clasificación y los grupos sobre los que se realizan los recuentos (y restablecer).

-2

Aquí hay un enfoque diferente. Si tiene varias tablas de datos que no se pueden unir, o si por algún motivo no desea contar todas las filas al mismo tiempo pero aún desea que formen parte del mismo recuento de filas, puede crear una tabla que haga trabajo para ti

Ejemplo:

create table #test (
     rowcounter int identity, 
     invoicenumber varchar(30) 
     ) 

insert into #test(invoicenumber) select [column] from [Table1] 

insert into #test(invoicenumber) select [column] from [Table2] 

insert into #test(invoicenumber) select [column] from [Table3] 

select * from #test 

drop table #test 
+0

Especifiqué específicamente en la pregunta original que sabía que se podía hacer con una tabla temporal, pero estaba buscando una solución que evitara eso. – andynormancx

2

La forma más sencilla es utilizar un contador de filas variable. Sin embargo, serían dos comandos SQL reales. Uno para establecer la variable, y luego la consulta de la siguiente manera:

SET @n=0; 
SELECT @n:[email protected]+1, a.* FROM tablename a 

Su consulta puede ser tan complejo como desee con une etc. Normalmente suelo hacer esto un procedimiento almacenado. Puede tener todo tipo de diversión con la variable, incluso usarla para calcular contra valores de campo.La clave es :=

+0

Esto funciona para MySQL, no estoy seguro acerca de SQL Server –

Cuestiones relacionadas