提问人:DBA_AV 提问时间:10/30/2023 更新时间:10/31/2023 访问量:52
非 null 列的 SQL 查询
Sql query for non-null columns
问:
我正在尝试编写一个查询来返回表的每一列和非空值的计数,结构为
| C1 | C2 | C*
Count()
对于我正在使用的单个列
SELECT COUNT(NULLIF(E.Id,''))
FROM Employee as E
我无法理解如何在每列上递归执行 Nullif,而不必对每个列名称进行硬编码。
答:
0赞
Yitzhak Khabinsky
10/31/2023
#1
请尝试以下解决方案。
无论所讨论的表有多少列,以及列具有哪些数据类型,它都是通用的。
并且没有动态 SQL。
SQL算法
USE tempdb;
GO
DROP TABLE IF EXISTS #tmpTable;
-- DDL and sample data population, start
CREATE TABLE #tmpTable (ID INT IDENTITY PRIMARY KEY, Col_1 VARCHAR(20), Col_2 VARCHAR(20), Col_3 VARCHAR(20), Col_4 VARCHAR(20));
INSERT INTO #tmpTable (Col_1, Col_2, Col_3, Col_4) VALUES
(NULL, 'Nike', 'Adidas', NULL),
(NULL, 'Nike', 'Adidas', 'Asics'),
(NULL, 'Asics', NULL, 'Asics'),
(NULL, 'Nike', NULL, 'Adidas');
-- DDL and sample data population, end
;WITH rs AS
(
SELECT c.value('local-name(.)', 'sysname') AS column_name
FROM #tmpTable AS t
CROSS APPLY (SELECT t.* FOR XML PATH(''), TYPE) AS t1(x)
CROSS APPLY x.nodes('/*') AS t2(c)
)
(
SELECT name AS column_name, NULL AS column_counter
FROM tempdb.sys.columns
WHERE object_id = object_id('tempdb..#tmpTable')
AND is_nullable = 1
EXCEPT
SELECT column_name, null
FROM rs
)
UNION ALL
SELECT column_name, COUNT(*) AS column_counter
FROM rs
GROUP BY column_name;
输出
column_name | column_counter |
---|---|
Col_1 | 零 |
Col_2 | 4 |
Col_3 | 2 |
Col_4 | 3 |
编号 | 4 |
1赞
Zorkolot
10/31/2023
#2
正如用户 @Thom A 在评论中指出的那样,您正在寻找动态 SQL 解决方案。 通常,您可以使用 sys.all_columns 查看数据库中的所有列详细信息。
同样,可以使用 sys.tables 查看所有表,并使用 sys.schemas 查看所有架构(其中默认架构为“dbo”)。
尝试:。SELECT * FROM sys.all_columns; SELECT * FROM sys.tables; SELECT * FROM sys.schemas
sys.tables 和 sys.columns 都联接在相同的列名 object_id 上。Sys.tables 联接到schema_id上的 sys.schemas。
动态 sql 通常是与变量的字符串连接。我创建了一个示例,该示例通过条件聚合执行您要求的操作:
DECLARE @tableName varchar(100) = 'Loan_dtl'
DECLARE @schemaName varchar(100) = 'dbo'
DECLARE @sql varchar(max) = 'SELECT '
SELECT @sql = CONCAT(@sql, 'COUNT(CASE WHEN ', C.name, ' IS NULL THEN 1 END) AS [', C.name, '], ')
FROM sys.tables T
INNER JOIN sys.all_columns C ON T.object_id = C.object_id
INNER JOIN sys.schemas S ON S.schema_id = T.schema_id
WHERE T.name = @tableName AND S.name = @schemaName
--remove last comma in STUFF and add the FROM clause
SET @sql = CONCAT(STUFF(@sql, len(@sql), 1, ''), ' FROM ', @schemaName, '.', @tableName)
EXEC (@sql)
评论