2010-11-24 29 views

Respuesta

25

El ExecuteNonQuery Method devuelve el número de filas afectadas por INSERT, UPDATE o DELETE. Este método se debe utilizar para realizar declaraciones DML (lenguaje de manipulación de datos) como se indicó anteriormente.

El ExecuteReader Method devolverá el conjunto de resultados de SELECT. Este método se debe usar cuando consulta un montón de resultados, como filas de una tabla, vista, lo que sea.

El ExecuteScalar Method devolverá un valor único en la primera fila, primera columna de una declaración SELECT. Este método se utilizará cuando espere que se devuelva solo un valor de la consulta.

En resumen, es normal que no tenga resultados de una declaración SELECT al utilizar el método ExecuteNonQuery. Use ExecuteReader en su lugar. Usando el método ExecuteReader, sabrá cuántas filas se devolvieron a través de la instancia del objeto SqlDataReader devuelto.

int rows = 0; 

if (reader.HasRows) 
    while (reader.Read()) 
     rows++; 

return rows; // Returns the number of rows read from the reader. 
6

No veo ninguna manera de hacer esto. Use ExecuteScalar con select count(*) where ... para contar las filas que coincidan con los criterios de su consulta SELECT original. Ejemplo a continuación, parafraseó a partir here:

using (SqlCommand thisCommand = 
    new SqlCommand("SELECT COUNT(*) FROM Employee", thisConnection)) 
{ 
    Console.WriteLine("Number of Employees is: {0}", 
     thisCommand.ExecuteScalar()); 
} 

Si necesita las filas, así, ya estaría utilizando ExecuteReader, imagino.

+0

No puedo cambiar la consulta sql su construido dinámicamente – Lyle

3

En su lugar, utilice el método ExecuteReader. Esto devuelve un SqlDataReader, que tiene una propiedad HasRows.

ExecuteNonQuery no debe utilizarse para las declaraciones SELECT.

1

Esto es tarde, pero me encontré con este problema recientemente y pensé que sería útil para otros que vendrían más tarde (como yo) en busca de ayuda con el mismo problema. De todos modos, creo que en realidad podrías usar ExecuteNonQuery de la forma en que lo intentas. PERO ... tiene que ajustar su consulta SELECT subyacente a un procedimiento almacenado que tiene una consulta SELECT y un parámetro de salida que se establece para que sea igual al recuento de filas.

Como se indica en la documentación de MSDN:

Aunque el ExecuteNonQuery no devuelve ninguna fila, los parámetros de salida o retorno valores asignados a los parámetros se rellenan con los datos.

Dado que así es como lo hice. Por cierto, me encantaría recibir retroalimentación por parte de los expertos si hay algún defecto en esto, pero parece funcionar para mí.

En primer lugar, el procedimiento almacenado debe tener dos sentencias SELECT: uno para devolver el conjunto de datos y otro atado a un parámetro de salida para devolver el número de registros:

CREATE PROCEDURE spMyStoredProcedure 
(
    @TotalRows int output 
) 
AS 
BEGIN 
    SELECT * FROM MyTable; //see extra note about this line below. 
    SELECT @TotalRows COUNT(*) FROM MyTable; 
END 

En segundo lugar, añadir el código (en VB.net, usando SqlCommand, etc.).

Dim cn As SqlConnection, cm As SqlCommand, dr As SqlDataReader 
Dim myCount As Int32 

cn = New SqlConnection("MyConnectionString") 
cn.Open() //I open my connection beforehand, but a lot of people open it right before executing the queries. Not sure if it matters. 

cm = New SqlCommand("spMyStoredProcedure", cn) 
cm.CommandType = CommandType.StoredProcedure 
cm.Parameters.Add("@TotalRows", SqlDbType.Int).Direction = ParameterDirection.Output 
cm.ExecuteNonQuery() 

myCount = CType(cm.Parameters("@TotalRows").Value, Integer) 
If myCount > 0 Then 
    //Do something. 
End If 

dr = cm.ExecuteReader() 
If dr.HasRows Then 
    //Return the actual query results using the stored procedure's 1st SELECT statement 
End If 
dr.Close() 
cn.Close() 
dr = Nothing 
cm = Nothing 
cn = Nothing 

Eso es todo.

Nota adicional. Supuse que es posible que haya deseado que el monto de "MyCount" haga algo diferente a determinar si continuará volviendo a ser consulta. La razón es porque con este método, realmente no necesitas hacer eso. Dado que estoy utilizando el método "ExecuteReader" después de obtener el conteo, puedo determinar si continuaré devolviendo el conjunto de datos deseado utilizando la propiedad "HasRows" del lector de datos. Sin embargo, para devolver un conjunto de datos, necesita una instrucción SELECT que devuelva un conjunto de datos, de ahí el motivo de mi primera instrucción SELECT en mi procedimiento almacenado.

Por cierto, lo bueno de este método de utilizar el método "ExecuteNonQuery" es que se puede utilizar para obtener la fila recuento total de antes cerrar el DataReader (no puede leer los parámetros de salida antes de cerrar el DataReader, que es lo que estaba tratando de hacer, este método lo soluciona). No estoy seguro de si hay un golpe de rendimiento o un error al hacer esto para evitar ese problema, pero como dije ... me funciona. = D

+0

Sí, hay un golpe de rendimiento debido a la ejecución del SQL en 'SqlCommand' dos veces. Y si hay declaraciones DML, se ejecutarán dos veces. Además, realmente no hay razón para abrir la conexión antes de ejecutar el SqlCommand; solo significa que estás manteniendo la conexión abierta por más tiempo. Podrías moverlo a después de la declaración del parámetro. Y Connection.Open() hacia abajo a través del último "End If" debe estar en un Try/Catch para que el Reader y la Conexión se puedan cerrar correctamente en un bloque Finally si ocurre una excepción. –

+0

Gracias por la entrada sobre dónde colocar Connection.Open. Tiene sentido. En cuanto al rendimiento alcanzado, entiendo que habrá un "golpe" hasta cierto punto para ejecutar SqlCommand 2x. Sin embargo, ¿la primera ejecución no sería mínima ya que ExecuteNonQuery no devuelve filas? Supuse que el primero sería rápido, ya que no está extrayendo todo el conjunto de datos. Por lo tanto, el golpe de rendimiento es mínimo para los primeros SqlCommands (incluso si había 1M registros subyacentes). Por favor corrija mi entendimiento si estoy equivocado. No lo he probado; simplemente asumí que así era como funcionaban las definiciones. – ptownbro

+0

No retirar los resultados no significa que SQL Server no necesitó encontrarlos. Si envía una consulta, SQL Server tiene que 1) analizarla, 2) compilar el plan de ejecución, 3) ejecutarlo y, opcionalmente, 4) devolver los resultados. Los primeros 3 pasos suceden incluso si descarta el puntero al conjunto de resultados. Sí, ahorra la cantidad de tiempo que lleva transferir los datos, que es algo, pero no mucho. Dado el almacenamiento en caché realizado en los planes de ejecución y las páginas de datos, la primera ejecución suele ser la más larga. Las consultas simples (sin ordenar/agrupar) podrían estar bien, pero en su mayor parte, este es un enfoque costoso. –

Cuestiones relacionadas