ทดสอบว่าคอลัมน์ใด ๆ เป็น NULL


16

ฉันพยายามที่จะคิดออกแบบสอบถามง่าย ๆ ที่ฉันสามารถทำได้เพื่อทดสอบว่าตารางขนาดใหญ่มีรายการของรายการที่มีค่าว่างอย่างน้อยหนึ่ง (NULL / เปล่า) ในคอลัมน์ใด ๆ

ฉันต้องการบางสิ่งบางอย่าง

SELECT * FROM table AS t WHERE ANY(t.* IS NULL)

ฉันไม่ต้องการที่จะทำ

SELECT * FROM table AS t WHERE t.c1 = NULL OR t.c2 = NULL OR t.c3 = NULL

นี่จะเป็นข้อความค้นหาขนาดใหญ่

คำตอบ:


16

ส่วนขยายของคำตอบของ @ db2 ที่มีการหักมือน้อยลง (อ่าน: ศูนย์):

DECLARE @tb nvarchar(512) = N'dbo.[table]';

DECLARE @sql nvarchar(max) = N'SELECT * FROM ' + @tb
    + ' WHERE 1 = 0';

SELECT @sql += N' OR ' + QUOTENAME(name) + ' IS NULL'
    FROM sys.columns 
    WHERE [object_id] = OBJECT_ID(@tb);

EXEC sys.sp_executesql @sql;

8

คุณควรแสดงรายการคอลัมน์ทั้งหมดตามความคิดเห็นของ JNK

WHERE c1 IS NULL OR c2 IS NULL OR c3 IS NULL

วิธีที่ค่อนข้างมีประสิทธิภาพน้อยกว่าที่หลีกเลี่ยงสิ่งนี้อยู่ด้านล่าง

;WITH xmlnamespaces('http://www.w3.org/2001/XMLSchema-instance' AS ns) 
SELECT * 
FROM   YourTable AS T1 
WHERE (
    SELECT T1.* 
    FOR XML PATH('row'), ELEMENTS XSINIL, TYPE
  ).exist('//*/@ns:nil') = 1 

(ขึ้นอยู่กับคำตอบ SO นี้)


5

ไม่มีไวยากรณ์ในตัวที่ดี แต่ Management Studio มีคุณสมบัติที่สะดวกสบายสองอย่างเพื่อสร้างแบบสอบถามอย่างรวดเร็ว

ใน Object Explorer เจาะลึกลงไปในตารางที่คุณต้องการขยายจากนั้นลากทั้งโฟลเดอร์ "คอลัมน์" ลงในตัวแก้ไขแบบสอบถามว่าง นี่จะเพิ่มรายการคอลัมน์ที่คั่นด้วยเครื่องหมายจุลภาคในแบบสอบถาม

ถัดไปเปิดค้นหาและแทนที่ ตั้งค่า "ค้นหาสิ่งที่" เป็น,และตั้งค่า "แทนที่ด้วย" เป็นIS NULL OR(ด้วยช่องว่างนำ) จากนั้นกดแทนที่ทั้งหมด คุณจะต้องทำความสะอาดสิ่งสุดท้ายในลำดับด้วยมือ

มันยังคงน่าเกลียด แต่ก็ใช้แรงงานน้อยน่าเกลียด


4

การแก้ปัญหาหลายอย่างสำหรับ: ค่า Null บางค่า, ค่า Null ทั้งหมด, คอลัมน์เดียวและหลายคอลัมน์พร้อมกันทำให้ QUICK ใช้ Top 1

หากคุณต้องการทดสอบหลายคอลัมน์คุณสามารถใช้สิ่งต่อไปนี้:

Column_1 Column_2 Column_3
-------- -------- --------
1        2        NULL
1        NULL     NULL
5        6        NULL

ก่อนอื่นให้ทดสอบค่า NULL แล้วนับเป็น:

select 
    sum(case when Column_1 is null then 1 else 0 end) as Column_1, 
    sum(case when Column_2 is null then 1 else 0 end) as Column_2, 
    sum(case when Column_3 is null then 1 else 0 end) as Column_3,
from TestTable 

ให้ผลเป็น NULL:

Column_1  Column_2  Column_3
0         1         3

เมื่อผลลัพธ์เป็น 0 จะไม่มีค่า NULL

ประการที่สองลองนับ non-NULLs:

select 
    sum(case when Column_1 is null then 0 else 1 end) as Column_1, 
    sum(case when Column_2 is null then 0 else 1 end) as Column_2, 
    sum(case when Column_3 is null then 0 else 1 end) as Column_3,
from TestTable

... แต่เนื่องจากเรานับ non-NULL ที่นี่เราสามารถทำสิ่งนี้ให้ง่ายขึ้น:

select 
    count(Column_1) as Column_1, 
    count(Column_2) as Column_2, 
    count(Column_3) as Column_3,
from TestTable

หนึ่งผลตอบแทน:

Column_1  Column_2  Column_3
3         2         0

เมื่อผลลัพธ์เป็น 0 คอลัมน์จะประกอบด้วย NULL ทั้งหมด

สุดท้ายหากคุณต้องการตรวจสอบคอลัมน์ที่เฉพาะเจาะจงท็อป 1 นั้นเร็วกว่าเพราะมันควรจะหยุดในการเข้าชมครั้งแรก จากนั้นคุณสามารถเลือกใช้ count (*) เพื่อให้ผลลัพธ์บูลีนได้:

select top 1 'There is at least one NULL' from TestTable where Column_3 is NULL

select count(*) from (select top 1 'There is at least one NULL' AS note from TestTable where Column_3 is NULL) a

0 = ไม่มี NULL อยู่ 1 = มีอย่างน้อยหนึ่ง NULL

หรือ

select top 1 'There is at least one non-NULL' AS note from TestTable where Column_3 is not NULL

select count(*) from (select top 1 'There is at least one non-NULL' AS note from TestTable where Column_3 is not NULL) a

0 = เป็น NULL ทั้งหมด 1 = มีอย่างน้อยหนึ่งค่าที่ไม่ใช่ NULL

ฉันหวังว่านี่จะช่วยได้.


ในขณะนี้ดูเหมือนว่ามีประโยชน์มากฉันรู้สึกผูกพันที่จะต้องทราบว่ามันไม่ใช่สิ่งที่ OP ขอมา - พวกเขาต้องการเนื้อหาของแต่ละแถวที่มีค่า NULL ไม่ใช่แค่การตรวจสอบเพื่อดูว่ามีอยู่จริงหรือไม่
RDFozz

ยุติธรรมพอสมควร ฉันคิดว่าฉันแค่อ่านมันแตกต่างกัน ฉันมุ่งเน้นไปที่ส่วน "... ทดสอบว่าตารางขนาดใหญ่มี ... " หรือไม่ดังนั้น ... Boolean (ในกรณีของฉัน Boolean-ish) แต่ถ้าโดย "รายการของรายการ" เขาหมายถึงแถวคุณก็พูดถูก
jwolf

เพิ่งเข้ามาอีกครั้ง ฉันตีความคำถามผิดไปอย่างแน่นอน - ควรสรุปว่าเขากำลังมองหาแถวที่เป็นผลลัพธ์ ฉันคิดว่าฉันเข้าใจผิดในความหมายของเขาเช่นกัน ฉันเดิมคิดว่าเขาหมายถึงคอมพิวเตอร์ที่มีราคาแพง แต่ตอนนี้ฉันแค่คิดว่าเขาหมายกว้างกับคอลัมน์เพื่อ Arron และ DB2 ได้มันขวาทั้งในการอ่านและการแก้ปัญหา (ขึ้นอยู่กับซึ่งเป็นเหนื่อยมากขึ้น: สมองหรือนิ้วมือของคุณของคุณ)
jwolf

2

UNPIVOT แปลคอลัมน์เป็นแถว ในกระบวนการมันกำจัดค่า NULL ( อ้างอิง )

รับอินพุต

create table #t
(
    ID  int primary key,
    c1  int null,
    c2  int null
);

insert #t(id, c1, c2)
values
    (1, 12, 13),
    (2, null, 14),
    (3, 15, null),
    (4, null, null);

แบบสอบถาม UNPIVOT

select
    ID, ColName, ColValue
from
(
    select *
    from #t
) as p
unpivot
(
    ColValue for ColName in
    (c1, c2)                  -- explicit source column names required
) as unpvt;

จะผลิตผลลัพธ์

| ID | ColName | ColValue |
|----|---------|----------|
| 1  | c1      | 12       |
| 1  | c2      | 13       |
| 2  | c2      | 14       |
| 3  | c1      | 15       |

Sadly row 4 ถูกกำจัดออกไปอย่างสิ้นเชิงเนื่องจากมันมีค่า NULL เท่านั้น! สามารถนำมาใช้ใหม่ได้โดยสะดวกโดยการฉีดค่าดัมมี่ลงในคิวรีแหล่งข้อมูล:

select
    ID, ColName, ColValue
from
(
    select
        -5 as dummy,               -- injected here, -5 is arbitrary
        *
    from #t
) as p
unpivot
(
    ColValue for ColName in
    (dummy, c1, c2)                -- referenced here
) as unpvt;

ด้วยการรวมแถวใน ID เราสามารถนับค่าที่ไม่เป็นนัล การเปรียบเทียบกับจำนวนคอลัมน์ทั้งหมดในตารางต้นฉบับจะระบุแถวที่มีค่า NULL ตั้งแต่หนึ่งรายการขึ้นไป

select
    ID
from
(
    select -5 as dummy, *
    from #t
) as p
unpivot
(
    ColValue for ColName in
    (dummy, c1, c2)
) as unpvt
group by ID
having COUNT(*) <> 3;

ฉันคำนวณ 3 เป็น
จำนวนคอลัมน์ในตารางต้นฉบับ #t
+ 1 สำหรับคอลัมน์ดัมมีการฉีด
- 1 สำหรับ ID ซึ่งไม่ใช่ UNPIVOTED

สามารถรับค่านี้ได้ในขณะทำงานโดยตรวจสอบตารางแคตตาล็อก

แถวเดิมสามารถดึงได้โดยเข้าร่วมกับผลลัพธ์

หากค่าอื่นที่ไม่ใช่ NULL จะถูกตรวจสอบพวกเขาสามารถรวมอยู่ในส่วนคำสั่ง:

...
) as unpvt
where ColValue <> ''      -- will eliminate empty strings

อภิปรายผล

สิ่งนี้ต้องการตัวระบุที่ดำเนินการผ่าน UNPIVOT กุญแจจะดีที่สุด หากไม่มีใครสามารถใช้ฟังก์ชันหน้าต่างROW_NUMBER ()ได้ แต่อาจมีค่าใช้จ่ายสูงในการดำเนินการ

คอลัมน์ทั้งหมดจะต้องอยู่ในรายการอย่างชัดเจนในข้อ UNPIVOT พวกเขาสามารถลากโดยใช้ SSMS ตามที่แนะนำ @ db2 มันจะไม่เป็นแบบไดนามิกเมื่อความหมายของตาราง chagnes ตามคำแนะนำของแอรอนเบอร์ทรานด์จะเป็น อย่างไรก็ตามนี่เป็นกรณีของ SQL เกือบทั้งหมด

สำหรับชุดข้อมูลที่ค่อนข้าง จำกัด ของฉันแผนการดำเนินการคือการสแกนดัชนีแบบคลัสเตอร์และกระแสรวม สิ่งนี้จะมีราคาแพงกว่าหน่วยความจำมากกว่าการสแกนตารางและคำสั่ง OR จำนวนมาก

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