2014-02-07 33 views
0

以下查詢以零百分比形式返回每個字段的表的值。我想要的是獲得特定ProductID的百分比總和。此外,我想獲得一個百分比(在一個額外的列)的領域沒有價值即=「」。有任何想法嗎?爲特定記錄返回NULL值的百分比

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 
+0

當然你知道'[AdventureWorks]的模式。[Production]。[Product]',爲什麼要使用動態SQL?你是否試圖展示反規範化如何導致稀疏的人口? – Jodrell

+0

@Jodrell我的意思是動態sql爲了獲得表中的所有字段。我們有時會在表中添加來自查詢的字段,因此我們不希望修改每個字段更改/添加的特定(百分比)查詢。 – alwaysVBNET

+0

通過「特定產品ID的百分比之和」,是指表中所有列的百分比總和,但僅考慮具有特定產品ID的記錄(事實上應該只有一條記錄)? – FrankPl

回答

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並使用表達式而不是*時,它會計算此表達式非空的行。由於這與您需要的相反,我添加了100.00 -作爲SELECT的開頭。

對於「空檢查」,這會使邏輯更加複雜,因此我將原邏輯留在那裏並擴展它。在那裏,我實現了對數字和字符/文本數據類型的空白檢查。您可以使用您用來確定列是否爲空的邏輯輕鬆擴展日期,二進制數據等。

我還發現,在兩個變量@nullCheck@emptyCheck之間保留第一個+更簡單,因爲它是有效的SQL,可以通過這種方式啓動表達式。

我也擴展了這個陳述,所以如果可能有多個記錄與ProductId = 123,它會顯示所有記錄中的平均值,即i。即總和除以行數。如果count(*)將爲零,則最外面的case表達式僅避免零除誤差。即找不到記錄ProductId = 123。在這種情況下,返回值是null

+0

您的回答有效。你能否通過下面的第二部分來完成它:另外,我想獲得一個字段的百分比(在額外的列中)沒有值,即=「」。這意味着要獲得您返回的百分比與空或「」合併的字段。 – alwaysVBNET

+0

@nectarines你顯然只希望檢查文本列中的空文本。整數,浮點數,日期,二進制,...列應該如何檢查? – FrankPl

+0

整數 - 0,日期(我不知道 - 請指教),二進制文件 - 沒有。這應該是全部。 – alwaysVBNET

0

您可以使用AVG功能:

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

UPDATE:

這裏是你的腳本:

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 
+0

的空值的字段百分比。我希望查詢是動態的,幷包含所有字段而不指定列名。 – alwaysVBNET

+0

編輯我的答案,所以它是通用的,你可以通過模式,表名和ID –

+0

在你的答案中,所有的字段得到返回。我想要的只是打開一個數字,即[tableProduct] -97%nulls – alwaysVBNET