1
votes

Récupérer des données de SQL Server avec AND / OR lorsque certains paramètres peuvent être laissés vides

J'utilise une procédure stockée pour récupérer des données à partir de SQL Server. L'application permet à l'utilisateur de rechercher par plusieurs paramètres. Il peut arriver que l'utilisateur doive laisser un ou plusieurs champs vides.

Par exemple, ils peuvent rechercher par nom de famille, code postal, race; ou ils peuvent rechercher par nom et code postal mais pas par race; ou ils peuvent rechercher par code postal et par race uniquement. Vous avez eu l'idée.

C'est facile à faire avec seulement quelques paramètres. Cependant, j'ai maintenant une douzaine de paramètres et il faudrait beaucoup de temps pour coder chaque option possible séparément.

Voici ce que j'ai essayé qui ne fonctionne pas:

    @LastName VARCHAR(50)
    @Zip NUMERIC(5)
    @Race VARCHAR(10)
AS
BEGIN
    SELECT *
    FROM myTable
    WHERE LastName = @LastName AND LastName != ''
       OR ZIP = @Zip AND ZIP != ''
       OR Race = @Race AND Race != ''

Comment pourrais-je utiliser AND / OR en même temps? Cela me donnerait les résultats que je recherche.


5 commentaires

Lisez les Requêtes attrape-tout et Réviser les requêtes attrape-tout .


Utilisez des parenthèses et même des instructions CASE. Mettez des parenthèses autour de vos clauses "ET", en laissant les OR à l'extérieur, et vous aurez peut-être plus de chance.


Faites attention si votre variable est nulle


Remarque: le type de données est NUMERIC - pas "numérique" ...


Erland en parle de manière exhaustive ici . Et faites attention aux détails. Pourquoi pensez-vous pouvoir passer une chaîne vide comme valeur de votre paramètre Race? Et comprenez-vous ce qui se passe lorsque vous comparez une valeur numérique à une chaîne vide? Les conversions implicites ne sont généralement pas votre alliée.


3 Réponses :


3
votes

Vous devez utiliser les parenthèses

SELECT *
FROM myTable
WHERE (LastName = @LastName OR @LastName = '')
AND (ZIP =@Zip OR @Zip = '')
AND(Race = @Race OR @Race = '')

De cette façon, les conditions entre parenthèses sont d'abord exécutées et après que toute cette condition soit testée.

Mais cette requête a aussi un bogue. Si les paramètres @Lastname = 'Smith', @ ZIP = 12345, @Race = '' alors un enregistrement avec LastName = 'Doe', ZIP = 12345 correspondra également.

Je pense

SELECT *
FROM myTable
WHERE (LastName = @LastName AND LastName != '')
OR (ZIP =@Zip AND ZIP != '')
OR (Race = @Race AND Race != '')

répond mieux à vos besoins


4 commentaires

AND a déjà la priorité sur OR afin que les parenthèses ne changent rien.


Non. La parenthèse a la priorité la plus élevée.


Vous avez raison, ils ont la priorité la plus élevée mais dans la première expression (qui était la seule avant votre modification et à laquelle mon commentaire précédent adressait) ils ne changent rien car le AND a déjà la priorité sur OU . Il n'est pas nécessaire d'appliquer une priorité déjà donnée entre parenthèses.


Le problème sans la version entre parenthèses est qu'une seule incompatibilité wolud cause un résultat sans résultat. Le problème avec les parenthèses, mais les OR sont sortis, c'était que la correspondance d'un seul des trois paramètres devrait entraîner de mauvaises correspondances.



0
votes

Essayez d'utiliser des parenthèses

@LastName varchar (50)
@Zip numberic (5)
@Race varchar (10)

AS
BEGIN
SELECT *
FROM myTable
WHERE (LastName = @LastName AND LastName != '')
OR (ZIP =@Zip AND ZIP != '')
OR (Race = @Race AND Race != '')

Lors de l'exécution de votre requête, le code entre parenthèses est lu avec priorité


6 commentaires

AND a déjà la priorité sur OR afin que les parenthèses ne changent rien.


si vous avez des doutes, vérifiez ce lien docs.microsoft.com/en-us/sql/integration-services/expression‌ s /… où l'utilisation des parenthèses est expliquée.


Vous pouvez vérifier: docs.microsoft.com/en-us/sql/t-sql/language-elements/... (Niveau 6: AND , Niveau 7 OU )


Utilisez des parenthèses pour remplacer la priorité définie des opérateurs dans une expression. Tout ce qui se trouve entre parenthèses est évalué en premier pour donner une valeur unique avant que cette valeur ne puisse être utilisée par tout opérateur en dehors des parenthèses. cela vient de votre lien @stickybit


Encore une fois: il n'est pas nécessaire de remplacer la priorité car AND a déjà la priorité sur OR .


Mais lorsque vous avez un mélange entre "et" & "ou" vous avez besoin de parenthèses, cela ne nuit pas aux performances et rend la requête plus lisible



1
votes

Le code suivant est plus difficile à écrire mais beaucoup plus efficace car la condition OR dans le WHERE pose plusieurs problèmes de performances, ce qui n'est pas SARGable:

DECLARE @LastName varchar (50) = 'LAST'
DECLARE @Zip NUMERIC (5) = 1
DECLARE @Race varchar (10)  = '1'

DECLARE @SQL AS NVARCHAR(MAX),
        @WHERE AS NVARCHAR(MAX) = '';
SELECT @SQL = 'SELECT *
FROM myTable';
IF LEN(@LastName) > 0 
   SELECT @WHERE = @WHERE + 'LastName = ''' + @LastName + '''';

IF LEN(@Zip) > 0
   IF LEN(@WHERE) > 0
   SELECT @WHERE = @WHERE + ' AND ZIP = ''' + CONVERT(NVARCHAR(18), @Zip) + '''';;
   ELSE
   SELECT @WHERE = 'ZIP = ' + CONVERT(NVARCHAR(18), @Zip) ;

IF LEN(@Race) > 0
   IF LEN(@WHERE) > 0
       SELECT @WHERE = @WHERE + ' AND Race = ''' + @Race + '''';
   ELSE
       SELECT @WHERE = 'Race = ''' + @Race + '''';
IF LEN(@WHERE) > 0 
    SELECT @SQL = @SQL + ' WHERE ' + @WHERE 
-- PRINT @SQL
EXEC sp_ExecuteSQL @SQL


0 commentaires