【问题标题】:Find % missing in every column in a table T-SQL查找表 T-SQL 中每一列中缺失的百分比
【发布时间】:2020-08-07 03:20:05
【问题描述】:

我试图弄清楚如何编写查询以查找 SQL Server 表中每一列的缺失百分比(NULL 值),因此我的想法是让查询返回两列:

  1. 第一列是表中每一列的名称
  2. 第二列应该是该列中缺失的百分比。

我一直在尝试将 case 语句应用于每一列,但它不起作用,非常感谢任何帮助!

【问题讨论】:

  • 什么是缺失?你的意思是空值吗?发布样本数据和预期结果以澄清。
  • 是的,我已经编辑了问题以反映我的意思是 NULL VALUES,只是表中没有数据的记录
  • 什么是“细胞”? SQL Server 中不存在单元格。这些是您在 Excel 电子表格中找到的内容。
  • 当我说“单元格”时,我只是指列中的一条记录
  • 旁注:一个包含 400 多列的表听起来您可能应该解决一些非规范化问题。

标签: sql sql-server


【解决方案1】:

好的,使用我链接的第一个answer,您可以进行如下查询:

USE Sandbox;
GO

DECLARE @Schema sysname, @Table sysname, @IncDistinct bit = 0;
SET @Schema = 'dbo';
SET @Table = 'rCTEvsTally';

DECLARE @SQL nvarchar(MAX)

SET @SQL = N'WITH Counts AS (' + NCHAR(13) + NCHAR(10) + 
           N'    SELECT @Schema AS SchemaName,' + NCHAR(13) + NCHAR(10) +
           N'           @Table AS TableName,' +
           STUFF((SELECT N',' + NCHAR(13) + NCHAR(10) + 
                           N'           COUNT(' + CASE WHEN C.DATA_TYPE IN ('text','image') THEN 'NULL' ELSE N'CASE WHEN ' + QUOTENAME(C.COLUMN_NAME) + N' IS NULL THEN 1 END' END + N') AS ' + QUOTENAME(COLUMN_NAME + N'_NULLs') + N',' + NCHAR(13) + NCHAR(10) +
                           N'           COUNT(' + CASE WHEN C.DATA_TYPE IN ('text','image') THEN '1' ELSE QUOTENAME(C.COLUMN_NAME) END + N') AS ' + QUOTENAME(COLUMN_NAME) + N',' + NCHAR(13) + NCHAR(10) +
                           N'           COUNT(DISTINCT ' + CASE WHEN C.DATA_TYPE IN ('text','image') THEN '1' ELSE QUOTENAME(C.COLUMN_NAME) END + N') AS ' + QUOTENAME(COLUMN_NAME + N'_Distinct')
                   FROM INFORMATION_SCHEMA.COLUMNS C
                   WHERE C.TABLE_SCHEMA = @Schema
                       AND C.TABLE_NAME = @Table
                       --AND C.DATA_TYPE NOT IN ('text','image')
                   ORDER BY C.ORDINAL_POSITION
                   FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,14,N'') + NCHAR(13) + NCHAR(10) + 
           N'    FROM ' + QUOTENAME(@Schema) + N'.' + QUOTENAME(@Table) + N')' + NCHAR(13) + NCHAR(10) + 
           N'SELECT V.OrdinalPosition,' + NCHAR(13) + NCHAR(10) + 
           N'       V.ColumnName,' + NCHAR(13) + NCHAR(10) + 
           N'       V.NonNullCount,' + NCHAR(13) + NCHAR(10) + 
           CASE WHEN @IncDistinct = 1 THEN N'       V.DistinctCount,' + NCHAR(13) + NCHAR(10) ELSE N'' END +
           N'       V.NullCount,' + NCHAR(13) + NCHAR(10) + 
           N'       ISC.DATA_TYPE + ISNULL(NULLIF(DT.S,''(*)''),'''') AS Datatype,' + NCHAR(13) + NCHAR(10) +
           N'       K.KeyType' + NCHAR(13) + NCHAR(10) +
           N'FROM Counts C' + NCHAR(13) + NCHAR(10) + 
           N'     CROSS APPLY(VALUES' + STUFF((SELECT N',' + NCHAR(13) + NCHAR(10) + 
                                                       N'                       (' + CONVERT(varchar(4),C.ORDINAL_POSITION) +N',N' + QUOTENAME(C.COLUMN_NAME,'''') + N',C.' + QUOTENAME(C.COLUMN_NAME) + N',C.' + QUOTENAME(C.COLUMN_NAME + N'_Distinct') + N',C.' + QUOTENAME(C.COLUMN_NAME + N'_NULLs') + N')'
                                               FROM INFORMATION_SCHEMA.COLUMNS C
                                               WHERE C.TABLE_NAME = @Table
                                                 --AND C.DATA_TYPE NOT IN ('text','image')
                                               ORDER BY C.ORDINAL_POSITION
                                               FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,26,N'') + N')V(OrdinalPosition,ColumnName,NonNullCount,DistinctCount,NullCount)' + NCHAR(13) + NCHAR(10) +
           N'     JOIN INFORMATION_SCHEMA.COLUMNS ISC ON C.SchemaName = ISC.TABLE_SCHEMA' + NCHAR(13) + NCHAR(10) +
           N'                                        AND C.TableName = ISC.TABLE_NAME' + NCHAR(13) + NCHAR(10) +
           N'                                        AND V.ColumnName = ISC.COLUMN_NAME' + NCHAR(13) + NCHAR(10) + 
           N'     CROSS APPLY (VALUES(''('' + STUFF(CONCAT('','' + CASE ISC.CHARACTER_MAXIMUM_LENGTH WHEN -1 THEN ''MAX'' ELSE CONVERT(varchar(4),ISC.CHARACTER_MAXIMUM_LENGTH) END,' + NCHAR(13) + NCHAR(10)+
           N'                                            '','' + CASE WHEN ISC.DATA_TYPE NOT LIKE ''%int'' THEN CONVERT(varchar(4),ISC.NUMERIC_PRECISION) END,' + NCHAR(13) + NCHAR(10) +
           N'                                            '','' + CASE WHEN ISC.DATA_TYPE NOT LIKE ''%int'' THEN CONVERT(varchar(4),ISC.NUMERIC_SCALE) END,' + NCHAR(13) + NCHAR(10) +
           N'                                            '','' + CASE WHEN ISC.DATA_TYPE NOT IN (''datetime'',''smalldatetime'') THEN CONVERT(varchar(4),ISC.DATETIME_PRECISION) END),1,1,'''') + '')'')) DT(S)' + NCHAR(13) + NCHAR(10) +
           N'     OUTER APPLY(SELECT TC.CONSTRAINT_TYPE AS KeyType ' + NCHAR(13) + NCHAR(10) + 
           N'                 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC' + NCHAR(13) + NCHAR(10) + 
           N'                      JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU ON TC.TABLE_SCHEMA = KCU.TABLE_SCHEMA' + NCHAR(13) + NCHAR(10) + 
           N'                                                                  AND TC.TABLE_NAME = KCU.TABLE_NAME' + NCHAR(13) + NCHAR(10) + 
           N'                                                                  AND TC.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME' + NCHAR(13) + NCHAR(10) + 
           N'                 WHERE KCU.COLUMN_NAME = V.ColumnName' + NCHAR(13) + NCHAR(10) + 
           N'                   AND TC.TABLE_SCHEMA = ISC.TABLE_SCHEMA' + NCHAR(13) + NCHAR(10) + 
           N'                   AND TC.TABLE_NAME = ISC.TABLE_NAME) K' + NCHAR(13) + NCHAR(10) +
           N'ORDER BY V.OrdinalPosition';

PRINT @SQL; --you will need to use the SELECT here if @SQL is over 4,000 characters
--SELECT @SQL;
EXEC sp_executesql @SQL, N'@Schema sysname,@Table sysname',@Schema = @Schema, @Table = @Table;

这会公开参数化表的各种计数。

您可以将这个数据集INSERT 放入一个(临时)表中,然后再进行工作,而不是扼杀那个解决方案。

--All prior code goes above apart from the call to sp_executesql
CREATE TABLE #ColumnCounts (OrdinalPosition int,
                            ColumnName sysname,
                            NonNullCount decimal(15,0), --Decimal as we want a percentage later
                            NullCount decimal(15,0), --Decimal as we want a percentage later
                            Datatype sysname,
                            KeyType nvarchar(50));
INSERT INTO #ColumnCounts
EXEC sys.sp_executesql @SQL, N'@Schema sysname,@Table sysname',@Schema = @Schema, @Table = @Table;

SELECT CC.ColumnName,
       NullCount / (NonNullCount + NullCount) AS ["Missingness"]
FROM #ColumnCounts CC;

DROP TABLE #ColumnCounts;

就像我在许多复杂的动态 SQL 解决方案中所说的那样,这不是入门级的。如果您不理解它,您可能不应该使用它,或者您应该花时间去理解它。如果你想开始理解它,我建议先查看生成的 SQL,然后再往回看。

【讨论】:

  • 不客气,@SamCannon,但就像我说的,在实施之前,您需要花时间了解这里的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-15
  • 1970-01-01
  • 2022-08-23
  • 2018-12-06
  • 2021-10-26
  • 2019-12-05
  • 2013-02-17
相关资源
最近更新 更多