.NET: Comment gérer les valeurs nulles possibles dans une requête SQL?

Code:

private void DoSomethingWithDatabase(ssortingng f1, int f2) { SqlCommand myCommand = new SqlCommand("SELECT Field1,Field2,Field3 FROM MyTable WHERE Field1 = @F1 AND Field2 = @F2", this.myConn); myCommand.Parameters.Add("@F1", System.Data.SqlDbType.VarChar); myCommand.Parameters.Add("@F2", System.Data.SqlDbType.Int); if (f1 == "") myCommand.Parameters["@F1"].Value = DBNull.Value; else myCommand.Parameters["@F1"].Value = f1; if (f2 < 0) myCommand.Parameters["@F2"].Value = DBNull.Value; else myCommand.Parameters["@F2"].Value = f2; // code to do stuff with the results here } 

Le server est une instance de Microsoft SQL Server.

La table de database MyTable contient des champs nullables. Par conséquent, null est une valeur valide à searchr lors de l'exécution de la requête.

De ma lecture, et aussi du code de test comme ceci, faire quelque chose comme ce que j'ai fait ici ne fonctionne pas correctement parce que apparemment vous ne pouvez pas faire une comparaison "égale nulle" de cette façon – vous êtes supposé faire "IS NULL" .

Il semble que vous pouvez corriger cela et le faire fonctionner en définissant ANSI_NULL sur OFF (selon https://msdn.microsoft.com/en-us/library/ms188048.aspx ) mais cela indique également que cette méthode est obsolète et ne devrait pas être utilisé.

Cet article suggère que vous pouvez utiliser un opérateur OR pour faire quelque chose comme WHERE Field1 = 25 OR Field1 IS NULL . Le problème est, avec un seul appel à cette fonction, je veux vérifier soit null et seulement null, ou pour la valeur constante donnée et rien d'autre.

Jusqu'à présent, il semble que je doive fondamentalement build la requête morceau par morceau, string par string, pour tenir count de la possibilité de valeurs NULL. Donc j'ai besoin de faire quelque chose comme:

 ssortingng theQuery = "SELECT Field1,Field2,Field3 FROM MyTable WHERE "; if (f1 == "") theQuery += "Field1 IS NULL "; else theQuery += "Field1 = @F1 "; // ... SqlCommand myCommand = new SqlCommand(theQuery, this.myConn); if (f1 == "") { myCommand.Parameters.Add("@F1", System.Data.SqlDbType.VarChar); myCommand.Parameters["@F1"].Value = f1; } // ... 

Est-ce vraiment la façon dont cela doit être fait? Existe-t-il un moyen plus efficace de le faire sans répéter cela if bloquer et en utilisant des parameters plutôt que de concaténer une string de requête set?

(Notes: Une string vide est convertie en NULL ici pour l'exemple Dans le scénario avec lequel je travaille actuellement, les strings vides ne sont jamais utilisées, mais à la place NULL est stocké La database est hors de mon contrôle, donc je peux ' Il suffit de dire "changez toutes vos valeurs NULL en strings vides" .De même pour les ints – si nous passons, disons, -1 dans la fonction, il devrait tester une valeur nulle. Mauvaise pratique? Peut-être, mais la database elle-même n'est pas dans mon contrôle, seul le code pour y accéder est.)

Pourquoi ne pas utiliser:

 ssortingng theQuery = "SELECT Field1, Field2, Field3 FROM MyTable WHERE ISNULL(Field1,'') = @F1"; 

?

De cette façon, vous vous débarrassez de votre bloc if et vos valeurs nulles sont interprétées comme une string vide, comme votre variable f1 .

SQL Server possède une fonction appelée ISNULL(Column,Value) laquelle vous pouvez spécifier une colonne à vérifier et définir une valeur par défaut dans le cas où cette colonne est NULL. Vous pouvez vérifier ici

La fonction ISNULL vous permet de gérer ce que vous voulez get lorsque vous obtenez une valeur NULL.

Voici quelques exemples

Si vous voulez éviter les blocs, vous pouvez probablement changer la requête en quelque chose comme ceci:

 SELECT Field1,Field2,Field3 FROM MyTable WHERE COALESCE(Field1,'') = @F1 AND COALESCE(Field2,-1) = @F2 

Vous pourriez faire quelque chose comme

 WHERE ISNULL(Field, '') = @F1 

Dans ce cas, les champs NULL sont traités comme des strings vides. Une autre façon serait:

 WHERE Field IS NULL OR Field = @1 

La façon dont vous traitez les valeurs NULL est la bonne. Peut-être que vous pourriez utiliser une méthode d'assistance comme celle-ci:

 private ssortingng AppendParameter(ssortingng query, ssortingng parameterName, ssortingng parameterValue, SqlParameterCollection parameters) { if (ssortingng.IsNullOrEmpty(parameterValue)) query += "Field1 IS NULL "; else { query += "Field1 = " + parameterName + " "; parameters.AddWithValue(parameterName, parameterValue); } return query; } 
 SqlCommand myCommand = new SqlCommand(@"SELECT Field1,Field2,Field3 FROM MyTable WHERE ( (@F1 IS NULL AND [field1] IS NULL) OR [field1] = @F1 ) AND ( (@F2 IS NULL AND [field2] IS NULL) OR [field2] = @F2 );", this.myconn); myCommand.Parameters.Add("@F1", System.Data.SqlDbType.VarChar).Value = DBNull.Value; myCommand.Parameters.Add("@F2", System.Data.SqlDbType.Int).Value = DBNull.Value; if (!ssortingng.IsNullOrEmpty(f1)) myCommand.Parameters["@F1"].Value = f1; if (f2 != -1) myCommand.Parameters["@F2"].Value = f2; 

Cela utiliserait des index sur les champs.