1

У меня возникли некоторые проблемы со следующим sprocSQL Server Если заявление беды

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 

Я был удивительно, почему следующее, если заявление не считается истинным, если я передать 0 в качестве идентификатора

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

Спасибо за любую помощь.

ответ

2

Это довольно странно - возможно, это связано с тем, что вы смешиваете int и строковый литерал. Это кажется более простым, чтобы сделать if @id is null или if @id is not null в зависимости от ваших требований

я воспроизвел это на простом примере (я изменил <> к =, чтобы логика немного более очевидной):

declare @id int 
set @id = 0 

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

Вы ожидали бы это для печати «false», но оно печатает «true». Если вы установите значение @id равным 1, оно будет вести себя так, как ожидалось.

2

Zero - это не то же самое, что и NULL. Нуль - это более или менее отсутствие какой-либо ценности. Ноль - это значение.

Если вы хотите 0, чтобы быть значение, которое вы можете передать его работать так же, как если бы вы прошли в NULL (то есть, если вы даете ему 0, не делать выбор), то сделать это:

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

Я на самом деле хочу, чтобы он конкатенировал строку, если идентификатор прошел в 0. Единственный раз, когда я не хочу, чтобы он входил в блок, это если идентификатор вообще не передается. – AlteredConcept

+0

затем измените значение 0 выше на -1 (то есть: ISNULL (@ Id, -1) <> -1 –

0

NULL означает неизвестный, а не ноль. Таким образом,

IF @id> 0

Должно работать. Но я хотел бы держаться подальше от здания строки и записать его в виде:

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 

Ниже то же самое, но менее самодокументирован.

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' 

Это не должно никого удивлять, все это описано в спецификации продукта:

  • ISNULL документирована вернуть тип проверяемого выражения, а не замена одного. Таким образом, isnull(@id, '') вернет 0 как тип int.
  • Сравнение if 0='' будет следовать правилам Data Type Precedence и конвертировать в более высокий класс пресечений, в данном случае int.
  • Строка «» преобразуется в целочисленное значение, эквивалентное cast('' as int), является 0.

Так что сравнение действительно так же, как написание if 0=0, что, конечно, верно. что и требовалось доказать

Смежные вопросы