2010-11-24 4 views

Répondre

25

Le ExecuteNonQuery Method renvoie le nombre de lignes affectées par un INSERT, un UPDATE ou un DELETE. Cette méthode doit être utilisée pour exécuter des instructions DML (langage de manipulation de données) comme indiqué précédemment. Le ExecuteReader Method renverra l'ensemble de résultats d'un SELECT Cette méthode doit être utilisée lorsque vous demandez un ensemble de résultats, tels que des lignes d'une table, d'une vue, etc.

Le ExecuteScalar Method retournera une seule valeur dans la première ligne, première colonne d'une instruction SELECT. Cette méthode doit être utilisée lorsque vous attendez qu'une seule valeur de la requête soit renvoyée. En résumé, il est normal que vous n'ayez aucun résultat d'une instruction SELECT lorsque vous utilisez la méthode ExecuteNonQuery. Utilisez plutôt ExecuteReader. En utilisant la méthode ExecuteReader, vous saurez combien de lignes ont été renvoyées via l'instance de l'objet SqlDataReader retourné.

int rows = 0; 

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

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

Je ne vois aucun moyen de le faire. Utilisez ExecuteScalar avec select count(*) where ... pour compter les lignes correspondant aux critères de votre requête SELECT d'origine. Exemple ci-dessous, paraphrasé de here:

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

Si vous avez besoin des lignes aussi bien, vous seriez déjà en utilisant ExecuteReader, j'imagine.

+0

Je ne peux pas modifier la requête sql de façon dynamique – Lyle

3

Utilisez plutôt la méthode ExecuteReader. Cela renvoie un SqlDataReader, qui a une propriété HasRows.

ExecuteNonQuery ne doit pas être utilisé pour les instructions SELECT.

1

Il est tard, mais j'ai récemment rencontré ce problème et je pensais qu'il serait utile pour les autres qui viendront plus tard (comme moi) demander de l'aide pour le même problème. Quoi qu'il en soit, je crois que vous pourriez réellement utiliser ExecuteNonQuery comme vous le souhaitez. MAIS ... vous devez ajuster votre requête SELECT sous-jacente à une procédure stockée à la place qui a une requête SELECT et un paramètre de sortie qui est défini pour égaler le nombre de lignes.

Comme il est indiqué dans la documentation MSDN:

Bien que le ExecuteNonQuery retourne aucune ligne, aucun paramètre de sortie ou de retour des valeurs mises en correspondance avec les paramètres sont remplis avec des données.

Étant donné que, voici comment je l'ai fait. Au fait, j'adorerais recevoir des commentaires de la part des experts s'il y a des failles, mais cela semble fonctionner pour moi.

D'abord, votre procédure stockée doit avoir deux instructions SELECT: l'un pour retourner votre ensemble de données et un autre lié à un paramètre de sortie pour retourner le nombre d'enregistrements:

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 second lieu, ajouter ce code (en vb.net, en utilisant 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 

C'est tout.

Note supplémentaire. J'ai supposé que vous vouliez peut-être obtenir le montant "MyCount" pour faire autre chose que de déterminer si vous souhaitez continuer à renvoyer votre requête. La raison en est que, avec cette méthode, vous n'avez pas vraiment besoin de faire cela. Comme j'utilise la méthode "ExecuteReader" après avoir obtenu le nombre, je peux déterminer si continuer à renvoyer le jeu de données prévu en utilisant la propriété "HasRows" du lecteur de données. Pour retourner un ensemble de données, cependant, vous avez besoin d'une instruction SELECT qui renvoie un ensemble de données, d'où la raison de ma première instruction SELECT dans ma procédure stockée.

Par ailleurs, la chose cool sur cette méthode d'utiliser la méthode « ExecuteNonQuery » est que vous pouvez l'utiliser pour obtenir la ligne compte total avant fermeture DataReader (vous ne pouvez pas lire les paramètres de sortie avant de fermer le DataReader, qui est ce que j'essayais de faire, cette méthode contourne ça). Je ne sais pas s'il y a un problème de performance ou un défaut de faire cela pour contourner ce problème, mais comme je l'ai dit ... ça marche pour moi. = D

+0

Oui, il y a un problème de performance dû à l'exécution du SQL dans 'SqlCommand' deux fois. Et s'il y a des instructions DML, elles auront été exécutées deux fois. En outre, il n'y a vraiment aucune raison d'ouvrir la connexion avant d'exécuter le SqlCommand; cela signifie simplement que vous gardez la connexion ouverte plus longtemps. Vous pouvez simplement le déplacer après la déclaration des paramètres. Et le Connection.Open() jusqu'à la dernière "End If" devrait être dans un Try/Catch afin que le Lecteur et la Connexion puissent être correctement fermés dans un bloc Finally si une exception se produit. –

+0

Merci pour l'entrée sur où placer le Connection.Open. Logique. En ce qui concerne la performance hit, je comprends qu'il y aura un "hit" dans une certaine mesure pour l'exécution de SqlCommand 2x. Cependant, la première exécution ne serait-elle pas minimale puisque ExecuteNonQuery ne retourne pas de lignes? J'ai supposé que le premier serait rapide car il ne tire pas l'ensemble des données. Par conséquent, le hit de performance est minimal pour les premiers SqlCommands (même s'il y a des enregistrements sous-jacents 1M). S'il vous plaît corriger ma compréhension si je me trompe. N'a pas testé - juste supposé que c'est comment cela a fonctionné compte tenu des définitions. – ptownbro

+0

Ne pas retirer les résultats ne signifie pas que SQL Server n'a pas besoin de les trouver. Si vous soumettez une requête, SQL Server doit 1) l'analyser, 2) compiler le plan d'exécution, 3) l'exécuter, et éventuellement 4) renvoyer les résultats. Les 3 premières étapes se produisent même si vous supprimez le pointeur sur le jeu de résultats. Oui, vous économisez le temps nécessaire pour transférer les données, ce qui est quelque chose, mais pas beaucoup. Compte tenu de la mise en cache effectuée sur les plans d'exécution et les pages de données, la première exécution est généralement la plus longue. Des requêtes simples (pas de tri/groupement) peuvent être correctes, mais pour la plupart, c'est une approche coûteuse. –

Questions connexes