查找所有行中的所有列都为空的表

Nem*_*ath -2 sql-server

我需要找到所有表的名称,其中表的所有列都NULL在每一行中。

我可以NULL使用以下查询获取允许值的表:

SELECT * FROM sys.objects A
WHERE TYPE = 'U'
AND NOT EXISTS
(   
    SELECT 1 FROM sys.all_columns B
    WHERE B.is_nullable = 0
    AND A.object_id = B.object_id
)
Run Code Online (Sandbox Code Playgroud)

但是我需要找到所有行和列所在的表NULL,图中显示了一个示例:

示例表

Dav*_*ett 5

不是在单个语句中,您必须在表中游标并生成动态 SQL 以依次检查每个表,如下所示:

CREATE TABLE #AllColumnsNullable (Name NVARCHAR(256) NOT NULL PRIMARY KEY, NumRows INT, NumRowsAllNull INT);

DECLARE CT CURSOR FOR 
            SELECT name FROM sys.objects so WHERE so.type = 'U'
            AND NOT EXISTS (SELECT * FROM sys.all_columns sc WHERE so.object_id=sc.object_id AND sc.is_nullable=0)
            ;
DECLARE @name NVARCHAR(MAX), @SQL NVARCHAR(MAX);
OPEN CT; FETCH NEXT FROM CT INTO @name;
WHILE @@FETCH_STATUS=0 BEGIN
    -- count rows
    SET @SQL = 'INSERT #AllColumnsNullable (Name, NumRows) SELECT '''+@name+''', COUNT(*) FROM ['+@name+'];';
    EXEC (@SQL);
    -- count rows all null
    SET @SQL = 'UPDATE #AllColumnsNullable SET NumRowsAllNull = (SELECT COUNT(*) FROM ['+@name+'] WHERE 1=1) WHERE name='''+@name+''';';
    DECLARE CC CURSOR FOR SELECT name FROM sys.columns WHERE object_id = (SELECT object_id FROM sys.objects WHERE name=@name);
    DECLARE @col NVARCHAR(MAX);
    OPEN CC; FETCH NEXT FROM CC INTO @col;
    WHILE @@FETCH_STATUS=0 BEGIN
        SET @SQL = REPLACE(@SQL, '1=1', '['+@col+'] IS NULL AND 1=1');
        FETCH NEXT FROM CC INTO @col;
    END;
    CLOSE CC;
    DEALLOCATE CC;
    EXEC (@SQL);
    -- done for this table
    FETCH NEXT FROM CT INTO @name;
END;
CLOSE CT;
DEALLOCATE CT;

SELECT * FROM #AllColumnsNullable;
DROP TABLE #AllColumnsNullable;
Run Code Online (Sandbox Code Playgroud)

第一个游标与您的查询类似,唯一重要的区别是它检查“没有不可为空的列”而不是“有一些可以为空”,因为如果至少有一个不可为空的列,您可以'没有任何没有非空值的行(如果您需要列出具有不可为空列但零行的表,因为它们具有非空值的零行,您需要对上述内容进行一些更改)。

在通过游标的循环中,我们使用动态 SQL 将表中的行数添加到我们的临时存储中,然后内部游标将更多动态 SQL 放在一起,从而增加了没有非 NULL 值的行数。添加PRINT @SQL;beforeEXEC (@SQL);以查看这为每个表生成什么(或者EXEC如果您只想查看代码而不运行它,则代替调用)。

这将需要一些时间在具有大量行的表上运行,因为它几乎肯定会对每个候选表进行表扫描。

注意:包含所有 NULL 的表意味着它没有主键(因为这些必须在不可为空的列上定义),这表明您在某处存在数据库设计问题。

注意:如果使用 SQL Server 2017 或更高版本,您可以使用STRING_AGG(). 事实上,对于之前的版本,您可以使用“普通” FOR XMLhack 来执行类似的连接并避免内部光标,尽管这不会像简单的GROUPing 和 usingSTRING_AGG()那样提高清晰度。