Заява T-SQL CASE: Як вказати КОГО НУЛЬ


227

Я написав подібну заяву T-SQL (оригінал виглядає інакше, але тут я хочу навести простий приклад):

SELECT first_name + 
    CASE last_name WHEN null THEN 'Max' ELSE 'Peter' END AS Name
FROM dbo.person

У цій заяві немає синтаксичних помилок, але випадок "case" завжди вибирає частину ELSE - також якщо ім'я прізвища є недійсним. Але чому?

Що я хочу зробити, це об'єднати ім’я та прізвище, але якщо прізвище є недійсним, все ім'я стає нульовим:

SELECT first_name +
   CASE last_name WHEN null THEN '' ELSE ' ' + last_name END AS Name 
FROM dbo.person

Чи знаєте ви, де проблема?

Відповіді:


369
CASE WHEN last_name IS NULL THEN '' ELSE ' '+last_name END

4
@ Пропозиція Лютера щодо COALESCE краща за мою відповідь. Це незначно менш ефективно, але набагато елегантніше.
Марсело Кантос

Поводження з цим чимось подібним може бути корисним або чимось подібним: COALESCE (прізвище, прізвище, '') Опис справи, хоч і стислий, не є менш рентабельним, ніж COALESCE у великих запитах. Зрештою, у вас такий же результат. Якщо вам потрібно оптимізувати, перевірте плани виконання, але я не помітив великої різниці.
Ентоні Мейсон

1
COALESCEв основному внутрішньо перекладається на CASE. Проблема CASE полягає в тому, що last_nameвона оцінюється двічі, і це може призвести до інших побічних ефектів - дивіться цю чудову статтю . Щоб вирішити те, що було запропоновано, я б краще пішов із ISNULL(' '+ last_name, '')зазначеним у коментарі нижче.
miroxlav

41

КОЛИНА частина порівнюється з ==, але ви не можете порівнювати її з NULL. Спробуйте

CASE WHEN last_name is NULL  THEN ... ELSE .. END

замість цього або СОБАЧЕННЯ:

COALESCE(' '+last_name,'')

('' + прізвище - NULL, коли прізвище NULL, тому воно повинне повернутися '' у такому випадку)


Гаразд дякую за інформацію з == у КОЛІЙ частині. Я цього не знав. З COALESCE це також добре працює. Не думав, що існує стільки можливостей для цього.
мені

15

Рішень існує маса, але жодне не пояснює, чому оригінальна заява не працює.

CASE last_name WHEN null THEN '' ELSE ' '+last_name

Після того, коли відбувається перевірка рівності, яка повинна бути правдою чи помилкою.

Якщо одна або обидві частини порівняння є недійсними, результатом порівняння буде НЕЗНАЧЕНО, що трактується як помилкове в структурі випадків. Дивіться: https://www.xaprb.com/blog/2006/05/18/why-null-never-compares-false-to-anything-in-sql/

Щоб цього уникнути, Coalesce - найкращий спосіб.


11

З огляду на ваш запит, ви також можете зробити це:

SELECT first_name + ' ' + ISNULL(last_name, '') AS Name FROM dbo.person

2
Це додає зайвий простір, коли прізвище є недійсним, чого ОП намагалася уникнути.
Марсело Кантос

6
Краще використовувати ISNULL(' '+ last_name, '')для запобігання зайвого місця.
Prutswonder

Ага зрозумів це після того, як я розмістив повідомлення. Подумав, що я залишу це, оскільки це вирішило ту частину, з якою він мав проблеми.
Ян Джейкобс

7

Проблема полягає в тому, що null не вважається рівним собі, тому пункт ніколи не відповідає.

Потрібно чітко перевірити наявність нуля:

SELECT CASE WHEN last_name is NULL THEN first_name ELSE first_name + ' ' + last_name

5

спробуйте:

SELECT first_name + ISNULL(' '+last_name, '') AS Name FROM dbo.person

Це додає простір до прізвища, якщо воно недійсне, весь пробіл + прізвище переходить до NULL, і ви отримуєте лише ім’я, інакше ви отримуєте firts + пробіл + прізвище.

це буде працювати до тих пір, поки встановлено за замовчуванням параметр конкатенації з нульовими рядками:

SET CONCAT_NULL_YIELDS_NULL ON 

це не повинно викликати занепокоєння, оскільки OFFрежим відходить у майбутніх версіях сервера SQl


4

Проблема полягає в тому, що NULL не вважається рівним нічому, навіть не самому собі, але дивна частина полягає в тому, що вона також не дорівнює собі.

Розглянемо наступні твердження (що BTW є незаконним у S-сервері T-SQL, але є дійсним у My-SQL, однак це ANSI визначає як null, і його можна перевірити навіть у SQL Server, використовуючи заяви справ тощо).

SELECT NULL = NULL -- Results in NULL

SELECT NULL <> NULL -- Results in NULL

Отже, немає правдивої / неправдивої відповіді на питання, натомість відповідь також є недійсною.

Це має багато наслідків, наприклад, в

  1. ВИПАДОК заяву, в якому будь-який порожньому значення буде завжди використовувати ELSE положення , якщо не використовувати явний вид КОЛИ умова NULL ( НЕ умова )WHEN NULL
  2. З'єднання рядків, як
    SELECT a + NULL -- Results in NULL
  3. У пункті WHERE IN чи WHERE NOT IN, як якщо ви хочете правильних результатів, переконайтеся, що у відповідному підзапиті відфільтрувати будь-які нульові значення.

Можна змінити таку поведінку в SQL Server, вказавши SET ANSI_NULLS OFF, проте це НЕ рекомендується, і цього не слід робити, оскільки це може спричинити багато проблем, просто через відхилення від стандарту.

(Як бічна примітка, в My-SQL є можливість використовувати спеціальний оператор <=>для порівняння з нулем.)

Для порівняння, у загальних мовах програмування нульове значення обробляється регулярним значенням і дорівнює самому собі, однак це значення NAN, яке також не є собі рівним, але принаймні повертає "помилкове", порівнюючи його з собою, (і при перевірці на нерівність різні мови програмування мають різні реалізації).

Однак зауважте, що в базових мовах (наприклад, VB тощо) немає ключового слова "null", і замість цього використовується ключове слово "Nothing", яке не можна використовувати в прямому порівнянні, і замість цього потрібно використовувати "IS", як у SQL, однак він насправді дорівнює собі (при використанні непрямих порівнянь).


1
"Дивна частина полягає в тому, що теж не рівна собі". => це не дивно, враховуючи, що null в SQL має значення "невідомо". Щось невідоме, швидше за все, не те саме, що щось невідоме.
JDC


1

Коли ви засмучуєтесь, намагаєтесь це:

CASE WHEN last_name IS NULL THEN '' ELSE ' '+last_name END

Спробуйте це замість цього:

CASE LEN(ISNULL(last_Name,''))
WHEN 0 THEN '' 
ELSE ' ' + last_name
END AS newlastName

LEN(ISNULL(last_Name,'')) вимірює кількість символів у цьому стовпці, яке буде нульовим, незалежно від того, чи порожній він, або NULL WHEN 0 THEN оцінюватиметься як true та повертає "" як очікувалося.

Я сподіваюся, що це корисна альтернатива.

Я включив цей тестовий випадок для sql-сервера 2008 і вище:

DECLARE @last_Name varchar(50) = NULL

SELECT 
CASE LEN(ISNULL(@last_Name,''))
WHEN 0 THEN '' 
ELSE 'A ' + @last_name
END AS newlastName

SET @last_Name = 'LastName'

SELECT 
CASE LEN(ISNULL(@last_Name,''))
WHEN 0 THEN '' 
ELSE 'A ' + @last_name
END AS newlastName

2
Ви впевнені, що це працює? Більшість функцій повертають NULL при введенні NULL, і мої тести підтверджують, що це також стосується LEN (), тобто LEN (NULL) повертає NULL, а не 0.
Jason Musgrove

Pokechu22 є правильним, і це виправлений сценарій: СЛУЧАЙ ДЛЯ СЛУЧАЙ (ISNULL (last_Name, '')) КОЛИ 0 ТАМ '' ELSE '' + прізвище END як NEWlastName
Chef Slagle

0

Джейсон виявив помилку, тому це працює ...

Чи може хто-небудь підтвердити інші версії платформи?
SQL Server:

SELECT
CASE LEN(ISNULL(last_name,'')) 
WHEN 0 THEN '' 
ELSE ' ' + last_name
END AS newlastName

MySQL:

SELECT
CASE LENGTH(IFNULL(last_name,'')) 
WHEN 0 THEN '' 
ELSE ' ' + last_name
END AS newlastName

Oracle:

SELECT
CASE LENGTH(NVL(last_name,'')) 
WHEN 0 THEN '' 
ELSE ' ' + last_name
END AS newlastName

0

Ви можете використовувати функцію IsNull

select 
    isnull(rtrim(ltrim([FirstName]))+' ','') +
    isnull(rtrim(ltrim([SecondName]))+' ','') +
    isnull(rtrim(ltrim([Surname]))+' ','') +
    isnull(rtrim(ltrim([SecondSurname])),'')
from TableDat

якщо один стовпець недійсний, ви отримаєте порожній знак

Сумісний з Microsoft SQL Server 2008+


0

Використовуйте функцію CONCAT, доступну в SQL Server 2012 і далі.

SELECT CONCAT([FirstName], ' , ' , [LastName]) FROM YOURTABLE

0

Я спробував передати рядок і протестувати рядок нульової довжини, і це спрацювало.

CASE 
   WHEN LEN(CAST(field_value AS VARCHAR(MAX))) = 0 THEN 
       DO THIS
END AS field 

0

NULL нічого не дорівнює. Оператор справи в основному говорить, коли значення = NULL .. він ніколи не потрапить.
Існує також декілька системних процедур, які записані неправильно із вашим синтаксисом. Див. Sp_addpullsubscription_agent та sp_who2.
Хочеться, щоб я знав, як повідомити Microsoft про ці помилки, оскільки я не в змозі змінити системні програми, що зберігаються.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.