简体   繁体   English

基于集合的查询,以查找表中包含至少一个空值的所有列

[英]Set-based query to find all columns in table that contain at least one null value

I am new to SQL and SQL Server 2008 R2. 我是SQL和SQL Server 2008 R2的新手。 I have found a cursor based approach to find all columns in a particular table that contain null values, but I am hoping to find a simpler set-based solution. 我找到了一种基于游标的方法来查找特定表中包含空值的所有列,但我希望找到一个更简单的基于集合的解决方案。

USE QC_TEST

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

SELECT @colName = c.name, @nullCols = COALESCE(@nullCols+', ','')+@colName
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

The above code currently returns all columns in myTable . 上面的代码当前返回myTable所有列。 If I change the EXISTS clause to NOT EXISTS , it returns no columns. 如果我将EXISTS子句更改为NOT EXISTS ,则不返回任何列。 The result should be a comma-separated string of column names that contain at least 1 null value. 结果应该是以逗号分隔的列名字符串,其中包含至少1个空值。

Thanks for your help 谢谢你的帮助

You could get a result this way 你可以用这种方式得到一个结果

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);

But I don't know that you'd really consider that better. 但我不知道你真的认为那更好。

Your code isn't working because the EXISTS subquery is just checking the name of your column isn't null, which it can't be. 您的代码无法正常工作,因为EXISTS子查询只是检查列的名称是否为空,这是不可能的。 The subquery doesn't expand out the "WHERE c.name IS NULL" into "WHERE MyColumnName IS NULL", it just sees that c.name = 'MyColumnName' which is not null and always returns false. 子查询不会将“WHERE c.name IS NULL”扩展为“WHERE MyColumnName IS NULL”,它只会看到c.name ='MyColumnName',它不是null并且始终返回false。

The cursor based approach probably works by building a seperate string query for each column and then excuting the string. 基于游标的方法可能通过为每列构建单独的字符串查询然后激活字符串来工作。

You could unpivot the table and look for nulls in that result set, ie 您可以将表格取消,并在该结果集中查找空值,即

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

this is a little unconventional, but try this: 这有点不同寻常,但试试这个:

--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: OUTPUT:

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

(1 row(s) affected)

if you need to to be dynamic because you don't know the column names, you can build a similar command into a string and then execute that. 如果您因为不知道列名而需要变为动态,则可以在字符串中构建类似的命令,然后执行该命令。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM