1
malheurs

je vais avoir des problèmes avec la sproc suivanteSQL Server Si la déclaration

Create PROCEDURE GetMatchingUsers 
@id int = NULL, 
@lastName varchar(50) = NULL, 
@firstName varchar(50) = NULL 
AS 
BEGIN 

SET NOCOUNT ON 

DECLARE @q nvarchar(4000), 
@paramlist nvarchar(4000) 

    SELECT @q = 'SELECT Id 
    , LastName 
    , FirstName ' 
SELECT @q = @q + 'FROM Users WHERE 1 = 1' 

IF ISNULL(@id, '') <> ''         
    SELECT @q = @q + ' AND Id = ' + Cast(@id as varchar) 
IF ISNULL(@lastName, '') <> ''           
    SELECT @q = @q + ' AND LastName like ''' + @lastName + '%''' 
IF ISNULL(@firstName, '') <> ''           
    SELECT @q = @q + ' AND FirstName like ''' + @firstName + '%''' 

SELECT @q = @q + ' ORDER BY LastName, FirstName ' 

--PRINT @q 

SELECT @paramlist = ' 
    @id int = NULL, 
    @lastName varchar(50) = NULL, 
    @firstName varchar(50) = NULL' 

EXEC sp_executesql @q, @paramlist,        
    @id, 
    @lastName, 
    @firstName 

J'étais étonnant que ce qui suit si la déclaration n'est pas considéré comme vrai si je passe 0 comme id

IF ISNULL(@id, '') <> ''         
    SELECT @q = @q + ' AND Id = ' + Cast(@id as varchar) 

Merci pour toute aide

Répondre

2

C'est assez bizarre - cela a probablement quelque chose à voir avec le fait que vous mélangez un int et un littéral de chaîne. Il semble plus facile de faire if @id is null ou if @id is not null en fonction de vos besoins

Je reproduis cela avec un exemple simple (j'ai changé <>-= pour rendre la logique un peu plus évident):

declare @id int 
set @id = 0 

if isnull(@id, '') = '' 
    print 'true' 
else 
    print 'false' 

que vous attendez ceci pour imprimer 'faux', mais il imprime 'vrai'. Si vous définissez la valeur de @id sur 1, il se comporte comme prévu.

2

Zéro n'est pas la même chose que NULL. Null est plus ou moins l'absence de toute valeur. Zéro est une valeur.

Si vous voulez 0 être une valeur que vous pouvez passer à travailler le même que si vous aviez passé dans NULL (si vous donnez 0, ne pas faire la sélection) puis faire:

IF ISNULL(@id, 0) <> 0         
    SELECT @q = @q + ' AND Id = ' + Cast(@id as varchar) 
+0

Je veux réellement qu'il concatène la chaîne si l'id passé est 0. La seule fois où je ne veux pas qu'il entre dans le bloc est si l'ID n'est pas du tout passé. – AlteredConcept

+0

puis changez le 0 ci-dessus à -1 (c'est-à-dire: ISNULL (@ Id, -1) <> -1 –

0

NULL signifie inconnu, pas zéro. Donc

IF @id> 0

Devrait fonctionner. Mais je resterais loin de la construction d'une chaîne et réécrire comme:

SELECT Id 
    , LastName 
    , FirstName 
FROM Users 
WHERE id = @id or 
(@lastName is null or LastName like @lastName+'%') or 
(@firstName is null or FirstName like @firstName+'%') 
ORDER BY LastName, FirstName 

est inférieure à la même chose, mais moins autodocumenté.

SELECT Id 
    , LastName 
    , FirstName 
FROM Users 
WHERE id = @id or 
LastName like @lastName+'%' or 
FirstName like @firstName+'%' 
ORDER BY LastName, FirstName 
3
declare @id int 
set @id = 0  
if isnull(@id, '') = '' 
    print 'true' 

Cela ne devrait pas surprendre personne, tout cela est documenté dans les spécifications du produit:

  • ISNULL est documenté pour renvoyer le type de l'expression vérifiée, pas le remplacement d'un. Donc, isnull(@id, '') renverra 0 en tant que type int.
  • La comparaison if 0='' suivra les règles de Data Type Precedence et de convertir au type de précendence supérieur, dans ce cas int.
  • La chaîne « » convertie en une valeur int, ce qui équivaut à cast('' as int), est 0.

Donc la comparaison est vraiment la même chose que l'écriture if 0=0, qui est, bien sûr, vrai. q.e.d.