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 aislamientoSERIALIZABLE
.
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