2011-11-17 30 views
0

我是SQL和SQL Server 2008 R2的新手。我發現了一種基於遊標的方法來查找包含空值的特定表中的所有列,但我希望找到更簡單的基於集合的解決方案。基於集的查詢來查找包含至少一個空值的表中的所有列

USE QC_TEST 

DECLARE @colName nvarchar(100) 
DECLARE @nullCols nvarchar(max) 

SELECT @colName = c.name, @nullCols = COALESCE(@nullCols+', ','')[email protected] 
FROM sys.tables AS t 
    JOIN sys.columns AS c 
     ON t.object_id = c.object_id 
WHERE t.name = 'myTable' 
AND 
EXISTS(SELECT * FROM myTable WHERE c.name IS NULL) 

SELECT @colName, @nullCols 

上述代碼目前返回myTable所有列。如果我將EXISTS子句更改爲NOT EXISTS,則它不返回任何列。結果應該是逗號分隔的至少包含1個空值的列名稱字符串。

感謝您的幫助

+2

爲什麼?什麼類型的應用程序需要這個?你也可以在你的查詢中加入'AND c.is_nullable = 1'來只循環可能有空的列。 –

+1

在將數據移到生產數據庫之前,這是從供應商處提供給我們的數據時檢查數據所必需的。這是一個標準的質量控制檢查。 – Brian

回答

0

您的代碼不工作,因爲EXISTS子查詢只是檢查你的列名不爲空,它是不可能的。子查詢不會將「WHERE c.name IS NULL」展開爲「WHERE MyColumnName IS NULL」,它只會看到c.name ='MyColumnName',它不爲null並始終返回false。

基於遊標的方法可能通過爲每列創建一個單獨的字符串查詢然後刪除該字符串。

你可以unpivot的表,並期待在該結果集空值,即

WITH myTable_unpvt AS (
    SELECT ContactID, FieldName, FieldValue 
    FROM 
     (SELECT ContactID 
      , cast(Forename as sql_variant) Forename 
      , cast(Surname as sql_variant) Surname 
      , cast(Extn as sql_variant) Extn 
      , cast(Email as sql_variant) Email 
      , cast(Age as sql_variant) Age 
     FROM myTable) p 
    UNPIVOT 
     (FieldValue FOR FieldName IN 
      (Forename, Surname, Extn, Email, Age) 
    ) AS myTable_unpvt 
) 

SELECT DISTINCT FieldName FROM myTable_unpvt WHERE FieldValue IS NULL 
+0

感謝您的回覆。是否有可能動態地做到這一點?換句話說,我需要在具有不同列的多個表上運行此查詢。我希望避免將列名硬編碼到SQL代碼中。 – Brian

+0

使用遊標構建查詢將是可以接受的。你只需要在表更改時重新運行它,並且任務的大小足夠小,不用擔心速度。 –

+0

@Brian:對於動態,請參閱我的答案。結果在行(不是CSV)中,但可以通過一個額外的間接級別來解決。這也是一種噁心(連接字符串...)。 – Sorpigal

0

這是一個有點標新立異,但試試這個:

--set up test table 
--the BEGIN TRY and ALTERs allow you to rerun entire script over and over again 
BEGIN TRY 
    CREATE TABLE YourTable (PK int not null primary key, RowValue1 int null, RowValue2 varchar(5) null, RowValue3 datetime) 
END TRY 
BEGIN CATCH END CATCH 
delete YourTable 
ALTER TABLE YourTable ALTER COLUMN RowValue1 int NULL 
ALTER TABLE YourTable ALTER COLUMN RowValue2 varchar(5) NULL 
ALTER TABLE YourTable ALTER COLUMN RowValue3 datetime NULL 

--setup test data 
INSERT INTO YourTable VALUES (1,1111,'AAAA',GETDATE()) 
INSERT INTO YourTable VALUES (2,2222,'BBBB',GETDATE()) 
INSERT INTO YourTable VALUES (3,3333,'CCCC',GETDATE()) 
INSERT INTO YourTable VALUES (4,NULL,'DDDD',GETDATE()) 
INSERT INTO YourTable VALUES (5,5555,'EEEE',NULL) 

--determine null columns 
DECLARE @BadColumns varchar(50) 

BEGIN TRY 
    ALTER TABLE YourTable ALTER COLUMN RowValue1 int NOT NULL 
END TRY 
BEGIN CATCH 
    SET @BadColumns=ISNULL(@BadColumns+', ','')+'RowValue1' 
END CATCH  
---------------------------------- 
BEGIN TRY 
    ALTER TABLE YourTable ALTER COLUMN RowValue2 varchar(5) NOT NULL 
END TRY 
BEGIN CATCH 
    SET @BadColumns=ISNULL(@BadColumns+', ','')+'RowValue2' 
END CATCH 
---------------------------------- 
BEGIN TRY 
    ALTER TABLE YourTable ALTER COLUMN RowValue3 datetime NOT NULL 
END TRY 
BEGIN CATCH 
    SET @BadColumns=ISNULL(@BadColumns+', ','')+'RowValue3' 
END CATCH 

--report null columns 
SELECT @BadColumns AS [Columns having NULLs] 

OUTPUT:

Columns having NULLs 
-------------------------------------------------- 
RowValue1, RowValue3 

(1 row(s) affected) 

如果你需要動態,因爲你不知道列名,你可以建立一個類似的命令到一個字符串然後執行。

2

你可以得到一個結果,這樣

declare @sql varchar(max), @t varchar(max); 
set @t = 'your_table'; 
select @sql = (select stuff(
    (select 
      '] is null union select ''' + c.name + 
      ''' from ' + @t + ' where [' + c.name 
     from 
      (select 
        c.name 
       from sys.tables AS t 
       inner join sys.columns AS c 
        ON t.object_id = c.object_id 
       where 
        t.name = @t 
      ) as c 
     for xml path('') 
    ), 1, 16, '') + '] is null') 
; 
exec(@sql); 

但我不知道,你真的考慮好。

+0

感謝您的解決方案。我現在正在SSMS中嘗試它,但查詢結果爲,錯誤消息如下:「名稱...不是有效的標識符。」其中...是創建並存儲在@ sql變量中的長SQL查詢,但是它是截斷的和不完整的。當我計算字符數時,它遠小於varchar(max)變量應該允許的8,000個字符。你對這個錯誤有任何想法嗎? – Brian

+0

@Brian:如果表中有很多列,則這個查詢可能會導致比'varchar(max)'更長的字符串。不確定最好的解決方法。你可以讓它工作在一大堆柱子中,但要多一點工作,但是, – Sorpigal

+0

當我在'EXEC @ sql'調用之前'PRINT @ sql'時,我得到整個字符串。 「EXEC」語句可以接受的變量大小是否有限制? – Brian

相關問題