กรณี T-SQL ข้อ: วิธีการระบุเมื่อเป็นโมฆะ


227

ฉันเขียนคำแถลง T-SQL ที่คล้ายกันนี้ (คำเดิมมีลักษณะแตกต่างกัน แต่ฉันต้องการยกตัวอย่างง่ายๆที่นี่):

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

คำชี้แจงนี้ไม่มีข้อผิดพลาดทางไวยากรณ์ใด ๆ แต่ตัวพิมพ์เล็ก - ใหญ่จะเลือกส่วนของ ELSE เสมอ - และถ้า last_name เป็นโมฆะ แต่ทำไม

สิ่งที่ฉันต้องการทำคือการรวม first_name และ last_name แต่ถ้า last_name เป็นโมฆะชื่อทั้งหมดจะกลายเป็นโมฆะ:

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
ข้อเสนอแนะของ @ Luther COALESCE ดีกว่าคำตอบของฉัน มันมีประสิทธิภาพน้อยกว่าเล็กน้อย แต่สวยงามกว่ามาก
Marcelo Cantos

การจัดการกับบางสิ่งเช่นนี้อาจเป็นการใช้งานหรือสิ่งที่ชอบ: COALESCE (last_name, '') คำสั่ง case ในขณะที่รัดกุมคือ imho สามารถบำรุงรักษาได้น้อยกว่า COALESCE ในข้อความค้นหาขนาดใหญ่ ในท้ายที่สุดคุณมีผลลัพธ์ที่เหมือนกัน หากคุณต้องการเพิ่มประสิทธิภาพตรวจสอบแผนการดำเนินการ แต่ฉันไม่ได้สังเกตเห็นความแตกต่างมาก
Anthony Mason

1
COALESCECASEพื้นภายในแปลเป็น ปัญหาเกี่ยวกับกรณีที่เป็นที่last_nameได้รับการประเมินครั้งที่สองและมันจะนำไปสู่ผลกระทบด้านอื่น ๆ - ดูที่ยอดเยี่ยมนี้บทความ เพื่อแก้ไขสิ่งที่ถามฉันอยากจะISNULL(' '+ last_name, '')พูดถึงในความคิดเห็นด้านล่าง
miroxlav

41

เมื่อเปรียบเทียบกับส่วน == แต่คุณไม่สามารถเปรียบเทียบกับ NULL ได้ ลอง

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

แทนหรือเชื่อมต่อ:

COALESCE(' '+last_name,'')

('' + last_name เป็น NULL เมื่อ last_name เป็น NULL ดังนั้นจึงควรส่งคืน '' ในกรณีนั้น)


โอเคขอบคุณสำหรับข้อมูลด้วย == ในส่วนเมื่อ ฉันไม่รู้ ด้วย COALESCE มันทำงานได้ดี ยังไม่ได้คิดว่ามีความเป็นไปได้มากมายที่จะทำเช่นนั้น
Meni

15

มีวิธีแก้ปัญหามากมาย แต่ไม่มีใครครอบคลุมว่าทำไมข้อความดั้งเดิมไม่ทำงาน

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

หลังจากเวลาที่มีการตรวจสอบความเท่าเทียมกันซึ่งควรจะเป็นจริงหรือเท็จ

หากหนึ่งหรือทั้งสองส่วนของการเปรียบเทียบเป็นโมฆะผลลัพธ์ของการเปรียบเทียบจะเป็น UNKNOWN ซึ่งถือว่าเป็นเท็จในโครงสร้างเคส ดู: 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
สิ่งนี้จะเพิ่มช่องว่างที่ซ้ำซ้อนเมื่อ last_name เป็นโมฆะซึ่งเป็นสิ่งที่ OP พยายามหลีกเลี่ยง
Marcelo Cantos

6
ใช้ดีกว่าISNULL(' '+ last_name, '')เพื่อป้องกันพื้นที่ซ้ำซ้อน
Prutswonder

ใช่ฉันรู้ว่ามันหลังจากที่ฉันโพสต์ คิดว่าฉันจะทิ้งมันไว้เพราะมันแก้ไขส่วนที่เขามีปัญหา
Ian Jacobs

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 + space + นามสกุล

สิ่งนี้จะทำงานได้ตราบใดที่การตั้งค่าเริ่มต้นสำหรับการต่อข้อมูลด้วยสตริง null ได้รับการตั้งค่า:

SET CONCAT_NULL_YIELDS_NULL ON 

สิ่งนี้ไม่น่าเป็นห่วงเพราะOFFโหมดกำลังจะออกไปใน SQl Server เวอร์ชันอนาคต


4

ปัญหาคือ NULL ไม่ถือว่าเท่ากับอะไรแม้แต่กับตัวมันเอง แต่ส่วนที่แปลกคือมันไม่เท่ากับตัวเอง

พิจารณาข้อความต่อไปนี้ (ซึ่งเป็น BTW ที่ผิดกฎหมายใน SQL Server T-SQL แต่ใช้ได้ใน My-SQL อย่างไรก็ตามนี่คือสิ่งที่ ANSI กำหนดให้เป็นโมฆะและสามารถตรวจสอบได้แม้ใน SQL Server โดยใช้คำสั่ง case เป็นต้น)

SELECT NULL = NULL -- Results in NULL

SELECT NULL <> NULL -- Results in NULL

ดังนั้นจึงไม่มีคำตอบจริง / เท็จสำหรับคำถาม แต่คำตอบนั้นเป็นโมฆะเช่นกัน

สิ่งนี้มีความหมายหลายอย่างเช่น

  1. งบกรณีซึ่งในค่า null ใด ๆ มักจะใช้ข้ออื่นเว้นแต่คุณจะใช้อย่างชัดเจนเมื่อไหร่จะมีสภาพเป็นโมฆะ ( ไม่เงื่อนไข )WHEN NULL
  2. การต่อข้อมูลสตริงเป็น
    SELECT a + NULL -- Results in NULL
  3. ในส่วนคำสั่ง WHERE IN หรือ WHERE NOT IN ราวกับว่าคุณต้องการผลลัพธ์ที่ถูกต้องตรวจสอบให้แน่ใจในแบบสอบถามย่อยที่สัมพันธ์กันเพื่อกรองค่า Null ใด ๆ

หนึ่งสามารถแทนที่พฤติกรรมนี้ใน SQL Server โดยการระบุSET ANSI_NULLS OFFแต่ไม่แนะนำและไม่ควรทำเพราะอาจทำให้เกิดปัญหามากมายเพียงเพราะเบี่ยงเบนมาตรฐาน

(ตามหมายเหตุด้านข้างใน My-SQL มีตัวเลือกให้ใช้ตัวดำเนินการพิเศษ<=>สำหรับการเปรียบเทียบค่าว่าง)

ในการเปรียบเทียบภาษาการเขียนโปรแกรมทั่วไป null ถือว่าเป็นค่าปกติและมีค่าเท่ากับตัวเองอย่างไรก็ตามค่า NAN ซึ่งไม่เท่ากับตัวมันเอง แต่อย่างน้อยก็คืนค่า 'false' เมื่อเปรียบเทียบกับตัวมันเอง (และ เมื่อตรวจสอบไม่เท่ากับภาษาการเขียนโปรแกรมที่แตกต่างกันมีการใช้งานที่แตกต่างกัน)

โปรดทราบว่าในภาษาพื้นฐาน (เช่น VB เป็นต้น) ไม่มีคำหลัก 'ว่าง' และแทนที่จะใช้คำหลัก 'ไม่มีอะไร' ซึ่งไม่สามารถใช้ในการเปรียบเทียบโดยตรงและแทนที่จะต้องการใช้ '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จะประเมินเป็นจริงและส่งคืน '' ตามที่คาดไว้

ฉันหวังว่านี่เป็นทางเลือกที่มีประโยชน์

ฉันได้รวมกรณีทดสอบนี้สำหรับ sql server 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 ถูกต้องและนี่คือสคริปต์ที่ได้รับการแก้ไข: CASE LEN (ISNULL (last_Name, '')) เมื่อ 0 จากนั้น 'ELSE' '+ last_name END AS newlastName
Chef Slagle

0

เจสันพบข้อผิดพลาดดังนั้นสิ่งนี้จึงใช้ได้

ทุกคนสามารถยืนยันเวอร์ชันแพลตฟอร์มอื่น ๆ ได้หรือไม่
เซิร์ฟเวอร์ SQL:

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

ออราเคิล:

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 ไม่เท่ากัน คำสั่ง case ถูกพูดโดยทั่วไปว่าเมื่อ value = NULL .. มันจะไม่มีวันได้รับผลกระทบ
นอกจากนี้ยังมีขั้นตอนการจัดเก็บระบบหลายอย่างที่เขียนไม่ถูกต้องกับไวยากรณ์ของคุณ ดู sp_addpullsubscription_agent และ sp_who2
หวังว่าฉันจะรู้วิธีแจ้งให้ Microsoft ทราบถึงข้อผิดพลาดเหล่านั้นเนื่องจากฉันไม่สามารถเปลี่ยนระบบที่จัดเก็บไว้ได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.