row_number registros numero numerar generar fila ejemplos contador consultas consecutivo complejas agrupadas sql odbc sqlncli

registros - numero de fila sql server



¿Necesita un recuento de filas después de la instrucción SELECT: cuál es el enfoque SQL óptimo? (10)

Intento seleccionar una columna de una sola tabla (sin uniones) y necesito contar el número de filas, idealmente antes de comenzar a recuperar las filas. He llegado a dos enfoques que proporcionan la información que necesito.

Enfoque 1:

SELECT COUNT( my_table.my_col ) AS row_count FROM my_table WHERE my_table.foo = ''bar''

Entonces

SELECT my_table.my_col FROM my_table WHERE my_table.foo = ''bar''

O enfoque 2

SELECT my_table.my_col, ( SELECT COUNT ( my_table.my_col ) FROM my_table WHERE my_table.foo = ''bar'' ) AS row_count FROM my_table WHERE my_table.foo = ''bar''

Estoy haciendo esto porque mi controlador SQL (SQL Native Client 9.0) no me permite usar SQLRowCount en una declaración SELECT, pero necesito saber el número de filas en mi resultado para asignar una matriz antes de asignarle información. El uso de un contenedor dinámicamente asignado, desafortunadamente, no es una opción en esta área de mi programa.

Me preocupa que pueda ocurrir la siguiente situación:

  • SELECCIONAR para el conteo ocurre
  • Se produce otra instrucción, agregar o eliminar una fila
  • Se produce SELECCIONAR para datos y de repente la matriz tiene un tamaño incorrecto.
    -En el peor de los casos, esto intentará escribir datos más allá de los límites de las matrices y bloquear mi programa.

¿El Enfoque 2 prohíbe este problema?

Además, ¿será uno de los dos enfoques más rápidos? Si es así, ¿cuál?

Finalmente, ¿hay un mejor enfoque que deba considerar (quizás una forma de indicarle al controlador que devuelva la cantidad de filas en un resultado SELECCIONADO usando SQLRowCount?)

Para aquellos que preguntaron, estoy usando Native C ++ con el controlador SQL antes mencionado (provisto por Microsoft).


¿Por qué no pones tus resultados en un vector? De esta forma no tienes que saber el tamaño de antemano.


Aquí hay algunas ideas:

  • Vaya con el Método n. ° 1 y cambie el tamaño de la matriz para guardar resultados adicionales o use un tipo que cambie de tamaño automáticamente si es necesario (no menciona qué idioma está usando, así que no puedo ser más específico).
  • Puede ejecutar ambas declaraciones en el Método n. ° 1 dentro de una transacción para garantizar que los recuentos sean los mismos las dos veces si su base de datos lo admite.
  • No estoy seguro de lo que está haciendo con los datos, pero si es posible procesar los resultados sin almacenarlos primero, este podría ser el mejor método.

El Método 2 siempre devolverá un recuento que coincida con su conjunto de resultados.

Sin embargo, le sugiero que vincule la subconsulta con su consulta externa, para garantizar que la condición en su recuento coincida con la condición en el conjunto de datos.

SELECT mt.my_row, (SELECT COUNT(mt2.my_row) FROM my_table mt2 WHERE mt2.foo = mt.foo) as cnt FROM my_table mt WHERE mt.foo = ''bar'';


Es posible que desee pensar en un mejor patrón para tratar con datos de este tipo.

Ningún controlador de SQL autoelegido le dirá cuántas filas devolverá su consulta antes de devolver las filas, porque la respuesta podría cambiar (a menos que use una transacción, que crea problemas propios).

El número de filas no cambiará: google para ACID y SQL.


Si está utilizando SQL Server, después de su consulta puede seleccionar la función @@ RowCount (o si su conjunto de resultados puede tener más de 2 mil millones de filas, use la función BIGROW_COUNT ()). Esto devolverá el número de filas seleccionadas por la declaración anterior o el número de filas afectadas por una instrucción de inserción / actualización / eliminación.

SELECT my_table.my_col FROM my_table WHERE my_table.foo = ''bar'' SELECT @@Rowcount

O bien, si desea incluir el recuento de filas en el resultado enviado similar al Método n.º 2, puede utilizar la cláusula OVER (consulte http://msdn.microsoft.com/en-us/library/ms189461.aspx 1 ).

SELECT my_table.my_col, count(*) OVER(PARTITION BY my_table.foo) AS ''Count'' FROM my_table WHERE my_table.foo = ''bar''

El uso de la cláusula OVER tendrá un rendimiento mucho mejor que el uso de una subconsulta para obtener el recuento de filas. Usar @@ RowCount tendrá el mejor rendimiento porque no habrá ningún costo de consulta para la instrucción select @@ RowCount

Actualización en respuesta al comentario: el ejemplo que proporcioné daría el número de filas en la partición, definido en este caso por "PARTITION BY my_table.foo". El valor de la columna en cada fila es el número de filas con el mismo valor de my_table.foo. Como su consulta de ejemplo tenía la cláusula "WHERE my_table.foo = ''bar''", todas las filas del conjunto de resultados tendrán el mismo valor de my_table.foo y, por lo tanto, el valor en la columna será el mismo para todas las filas e igual (en este caso) este el # de filas en la consulta.

Aquí hay un ejemplo mejor / más simple de cómo incluir una columna en cada fila que es el número total de filas en el conjunto de resultados. Simplemente elimine la cláusula Partition By opcional.

SELECT my_table.my_col, count(*) OVER() AS ''Count'' FROM my_table WHERE my_table.foo = ''bar''


Si le preocupa que el número de filas que cumplen la condición pueda cambiar en los pocos milisegundos desde la ejecución de la consulta y la recuperación de resultados, puede / debería ejecutar las consultas dentro de una transacción:

BEGIN TRAN bogus SELECT COUNT( my_table.my_col ) AS row_count FROM my_table WHERE my_table.foo = ''bar'' SELECT my_table.my_col FROM my_table WHERE my_table.foo = ''bar'' ROLLBACK TRAN bogus

Esto devolvería los valores correctos, siempre.

Además, si está utilizando SQL Server, puede usar @@ ROWCOUNT para obtener el número de filas afectadas por la última instrucción, y redirigir el resultado de la consulta real a una tabla temporal o variable de tabla, para que pueda devolver todo por completo, y sin necesidad de una transacción:

DECLARE @dummy INT SELECT my_table.my_col INTO #temp_table FROM my_table WHERE my_table.foo = ''bar'' SET @dummy=@@ROWCOUNT SELECT @dummy, * FROM #temp_table


Si realmente está preocupado de que su recuento de filas cambie entre el recuento de selección y la declaración de selección, ¿por qué no seleccionar primero las filas en una tabla temporal? De esa forma, sabes que estarás sincronizado.


Solo hay dos maneras de estar 100% seguros de que el COUNT(*) y la consulta real darán resultados consistentes:

  • Combina el COUNT(*) con la consulta, como en su Método 2. Recomiendo el formulario que muestra en su ejemplo, no la forma de subconsulta correlacionada que se muestra en el comentario de kogus.
  • Utilice dos consultas, como en su Método 1, después de iniciar una transacción en SNAPSHOT o nivel de aislamiento SERIALIZABLE .

Usar uno de esos niveles de aislamiento es importante porque cualquier otro nivel de aislamiento permite que nuevas filas creadas por otros clientes sean visibles en su transacción actual. Lea la documentación de MSDN en SET TRANSACTION ISOLATION para obtener más detalles.


Solo para agregar esto porque este es el resultado principal en google para esta pregunta. En sqlite lo usé para obtener el recuento de filas.

WITH temptable AS (SELECT one,two FROM (SELECT one, two FROM table3 WHERE dimension=0 UNION ALL SELECT one, two FROM table2 WHERE dimension=0 UNION ALL SELECT one, two FROM table1 WHERE dimension=0) ORDER BY date DESC) SELECT * FROM temptable LEFT JOIN (SELECT count(*)/7 AS cnt, 0 AS bonus FROM temptable) counter WHERE 0 = counter.bonus


IF (@@ROWCOUNT > 0) BEGIN SELECT my_table.my_col FROM my_table WHERE my_table.foo = ''bar'' END