SQL Server If оператор горе - PullRequest
1 голос
/ 08 января 2010

У меня возникли проблемы со следующим sproc

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

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

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

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

Ответы [ 4 ]

3 голосов
/ 09 января 2010
declare @id int 
set @id = 0     
if isnull(@id, '') = ''  
  print 'true'

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

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

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

2 голосов
/ 08 января 2010

Это довольно странно - возможно, это как-то связано с тем, что вы смешиваете 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 голосов
/ 08 января 2010

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

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

IF ISNULL(@id, 0)  <> 0                                 
    SELECT @q = @q + ' AND Id = ' + Cast(@id as varchar)
0 голосов
/ 08 января 2010

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 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...