返回特定记录的NULL值的百分比

时间:2014-02-07 09:16:14

标签: sql sql-server-2008

以下查询以null百分比的形式返回每个字段的表值。我想要的是得到特定ProductID的百分比之和。另外,我想得到一个字段的百分比(在额外的列中)没有值,即=“”。有什么想法吗?

use AdventureWorks 
DECLARE @TotalCount decimal(10,2), @SQL NVARCHAR(MAX)
SELECT @TotalCount = COUNT(*) FROM [AdventureWorks].[Production].[Product] 

SELECT @SQL = 

COALESCE(@SQL + ', ','SELECT ') +
'cast(sum (case when ' + QUOTENAME(column_Name) + 
' IS NULL then 1 else 0 end)/@TotalCount*100.00 as decimal(10,2)) as [' +
column_Name + ' NULL %]
'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Product' and TABLE_SCHEMA = 'Production'
SET @SQL = 'set @TotalCount = NULLIF(@TotalCount,0) 
' + @SQL + '
FROM [AdventureWorks].Production.Product'
print @SQL
EXECUTE SP_EXECUTESQL @SQL, N'@TotalCount decimal(10,2)', @TotalCount

2 个答案:

答案 0 :(得分:1)

您可以使用以下内容:

use AdventureWorks

DECLARE @colCount int;
DECLARE @nullCheck nvarchar(max) = N'';
DECLARE @emptyCheck nvarchar(max) = N'';
DECLARE @SQL NVARCHAR(MAX);
DECLARE @KeyToCheck int = 123; -- adapt as necessary

SELECT 
    @nullCheck += '
         + ' + 'count(' + QUOTENAME(column_Name) + ')'
   ,@emptyCheck += '
         + ' +
         CASE
             WHEN DATA_TYPE IN('bigint', 'int', 'smallint', 'tinyint', 'bit', 'money', 'smallmoney', 'numeric', 'decimal', 'float', 'real') THEN
                 -- check numeric data for zero
                 'sum(case when coalesce(' + QUOTENAME(column_Name) + ', 0) = 0 then 1 else 0 end)' 
             WHEN DATA_TYPE like '%char' or DATA_TYPE like '%text' THEN 
                 --check character data types for empty string
                 'sum(case when coalesce(' + QUOTENAME(column_Name) + ', '''') = '''' then 1 else 0 end)'
             ELSE -- otherwise, only check for null
                 'sum(case when ' + QUOTENAME(column_Name) + ' IS NULL then 1 else 0 end)'
         END
   ,@colCount = 
        count(*) over()

FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Product' and TABLE_SCHEMA = 'Production'
;

SET @SQL = 'SELECT case when count(*) > 0 then 100.00 - (' + @nullCheck + '
      ) * 100.00 / ' + cast(@colCount as nvarchar(max)) + '.00 / count(*) end as null_percent
      , case when count(*) > 0 then (' + @emptyCheck + '
      ) * 100.00 / ' + cast(@colCount as nvarchar(max)) + '.00 / count(*) end as empty_percent
FROM Production.Product
WHERE ProductID = ' + cast(@KeyToCheck as nvarchar(max))
;

print @SQL;

EXECUTE (@SQL)

我简化了您的一个表达式:您可以使用sum (case when <column> IS NULL then 1 else 0 end)而不是count(<column>)。将count与表达式而不是*一起使用时,它会计算此表达式为非null的行。由于这与您的需求相反,我添加了100.00 -作为SELECT的开头。

对于“空检查”,这会使逻辑变得更加复杂,因此我将原始逻辑留在那里并对其进行扩展。在那里,我实现了对数字和字符/文本数据类型空虚的检查。您可以使用您用来确定列是否为空的逻辑,轻松地扩展日期,二进制数据等。

我还发现将+放在两个变量@nullCheck@emptyCheck中会更简单,因为这是一个有效的SQL来启动表达式。

我还扩展了声明,以便如果有ProductId = 123个可能有多条记录,它会显示所有记录的平均值,即。即总和除以行数。如果case为零,则最外面的count(*)表达式可以避免除零错误,即i。即找不到ProductId = 123的记录。在这种情况下,返回值为null

答案 1 :(得分:0)

您可以使用AVG功能:

SELECT AVG(CASE WHEN value IS NULL THEN 100 ELSE 0 END) AS Percents
FROM Table

<强>更新

这是你的脚本:

DECLARE @SQL NVARCHAR(MAX), @TABLE_NAME NVARCHAR(MAX), @TABLE_SCHEMA NVARCHAR(MAX), @PK NVARCHAR(MAX)

SET @TABLE_NAME = 'tblBigTable'
SET @TABLE_SCHEMA = 'dbo'
SET @PK = '8'

SELECT
    @SQL = COALESCE(@SQL + ', ', 'SELECT ') +'AVG(CASE WHEN ' + COLUMN_NAME + ' IS NULL THEN 100 ELSE 0 END) AS [' + COLUMN_NAME +' NULL %]'
FROM 
    INFORMATION_SCHEMA.COLUMNS
WHERE 
    TABLE_SCHEMA = @TABLE_SCHEMA AND 
    TABLE_NAME = @TABLE_NAME

SET @SQL = @SQL + ' FROM ' + @TABLE_NAME + ' WHERE pkId = ''' + @PK + ''''

print @SQL

EXECUTE SP_EXECUTESQL @SQL