查找SQL中非空行的百分比

查找SQL中非空行的百分比,sql,sql-server,Sql,Sql Server,哦,SQL,你为什么让我失望 大家下午好,我又卡住了 我有一个数据库,它保存表单的信息(duh),这个表单可以被“保存”,以便用户以后可以回来处理它。我需要的是找到非空字段的百分比。比如, COL_A |COL_B |COL_C |ETC.. z % -------------------------- z------ X | X | NULL | z 66 X | X | X | z 100 NULL | NULL | X

哦,SQL,你为什么让我失望

大家下午好,我又卡住了

我有一个数据库,它保存表单的信息(duh),这个表单可以被“保存”,以便用户以后可以回来处理它。我需要的是找到非空字段的百分比。比如,

COL_A |COL_B |COL_C |ETC.. z  %  
-------------------------- z------
  X   |   X  | NULL |      z  66 
  X   |   X  |   X  |      z  100
 NULL | NULL |   X  |      z  33
 NULL | NULL | NULL |      z  0

蛋糕上的糖霜?每行有47列需要检查。我可能走错了方向。任何帮助/提示都将不胜感激。

您可以将
交叉应用
值结合使用

SELECT t.*, FLOOR(100 * (1.0 * sub.col)/sub.counter) AS [percentage]
FROM #tab t
CROSS APPLY (
   SELECT COUNT(c), COUNT(*) 
   FROM (VALUES(t.col1), (t.col2), (t.col3), (t.col4), (t.col5),
               (t.col6), (t.col7), (t.col8), (t.col9), (t.col10)) AS s(c)
 ) AS sub(col, counter)
您需要在
value
子句中添加多达47个列

编辑:

当列具有相似的数据类型或存在隐式转换时,上述解决方案有效。如果存在没有隐式转换的数据类型,它将失败(如
UNIQUEIDENTIFIER
DATETIME
。一个快速解决方法是使用
CAST(t.colx作为NVARCHAR(100))将每列包装起来。

或者可以使用
IIF/CASE
(不再关注数据类型):


您可以让收集数据的应用程序对未完成的行进行计数,并将其与记录一起保存。您还可以创建一个计算字段,在保存记录时自动存储保存的百分比值

具有3列的示例:

CREATE TABLE [dbo].[Table](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [COL_A] [varchar](10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [COL_B] [nchar](10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [COL_C] [nchar](10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [PctSaved]  AS 
            ((case when [COL_A] IS NULL then (1) else (0) end
            +case when [COL_B] IS NULL then (1) else (0) end)
            +case when [COL_C] IS NULL then (1) else (0) end/(3.0)
            ) PERSISTED
) ON [PRIMARY]

您可能想尝试
unpivot
将这47列转换为行。列的数量可能会经常更改吗?不,列的数量将始终相同。@lad2025..这是否适用于一行中的所有
null
值?并且没有
id
列?@vkp是的,它将适用于所有null,我将id添加为PK列,OP可以重新设置移动它非常好..像往常一样完美的解决方案:)我刚才检查了它。@Kramb当您有各种数据类型并且没有隐式转换时,这就是问题所在。一个快速的解决方法是
强制转换(t.col1为NVARCHAR(MAX))
每列。我会考虑为我做这件事的更干净的解决方案。非常感谢你的帮助!
SELECT t.*, FLOOR(100 * (1.0 * sub.col)/sub.counter) AS [percentage]
FROM #tab t
CROSS APPLY (SELECT COUNT(c), COUNT(*) 
             FROM (VALUES 
             (IIF(t.col1 IS NULL, NULL, 1)), 
             (IIF(t.col2 IS NULL, NULL, 1)),
             (IIF(t.col3 IS NULL, NULL, 1)), 
             (IIF(t.col4 IS NULL, NULL, 1)),
             (IIF(t.col5 IS NULL, NULL, 1)), 
             (IIF(t.col6 IS NULL, NULL, 1)),
             (IIF(t.col7 IS NULL, NULL, 1)), 
             (IIF(t.col8 IS NULL, NULL, 1)),
             (IIF(t.col9 IS NULL, NULL, 1)), 
             (IIF(t.col10 IS NULL, NULL, 1))
             ) AS s(c)) AS sub(col, counter);
CREATE TABLE [dbo].[Table](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [COL_A] [varchar](10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [COL_B] [nchar](10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [COL_C] [nchar](10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
    [PctSaved]  AS 
            ((case when [COL_A] IS NULL then (1) else (0) end
            +case when [COL_B] IS NULL then (1) else (0) end)
            +case when [COL_C] IS NULL then (1) else (0) end/(3.0)
            ) PERSISTED
) ON [PRIMARY]