我需要找到所有表的名称,其中表的所有列都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,图中显示了一个示例:
不是在单个语句中,您必须在表中游标并生成动态 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()那样提高清晰度。