按行计算填充列数

时间:2019-02-26 09:58:30

标签: sql-server

我想知道是否有一种方法可以计算表中每行的填充列数。

例如,如果我有一个名为“客户”的简单表格:

 **Name**      **Customer**   **DOB**       **Order number**  **Populated Columns**
 ABC Ltd         Jo Blogg      2/1/78          123                3
 Umbrella Co     A Sherman                     232                2
 Nike                          14/5/98                            1

我想要的是一个查询,它将为我提供一个额外的列,并带有一个数字,表示其中有多少列具有值。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

可以通过对NULL(以及此类列的空字符串)进行简单检查来完成:

SELECT 
    [Name]
,   [Customer]
,   [DOB]
,   [Order number]

,   CASE WHEN ISNULL([Name], '') != ''  THEN 1 ELSE 0 END 
+   CASE WHEN ISNULL([Customer], '') != ''  THEN 1 ELSE 0 END 
+   CASE WHEN [DOB] IS NOT NULL  THEN 1 ELSE 0 END 
+   CASE WHEN [Order number] IS NOT NULL  THEN 1 ELSE 0 END  AS [Populated Columns]

这对于固定和已知数量的列将很好地工作。 如果从元数据中获取列列表,则这种方法可能更通用。缺点-这需要动态SQL。 以下是 SQL Server 2017 及更高版本的示例:

DECLARE @_SQL NVARCHAR(max)
DECLARE @_TableName sysname = 'Table1'

SELECT @_SQL = 
'SELECT ' 
+ STRING_AGG(QUOTENAME(COLUMN_NAME), ', 
')
+ ', '
+ STRING_AGG('
CASE WHEN ['+COLUMN_NAME+'] IS NOT NULL THEN 1 ELSE 0 END', ' +')
+ ' AS [Populated Columns]
FROM ' + QUOTENAME(MIN(TABLE_SCHEMA)) + '.' + QUOTENAME(MIN(TABLE_NAME))
FROM INFORMATION_SCHEMA.COLUMNs 
WHERE TABLE_NAME = @_TableName

EXEC sys.sp_executesql @_SQL

它将生成并执行代码:

SELECT 
[Col1], 
[Col2], 
[Col3], 
CASE WHEN [Col1] IS NOT NULL THEN 1 ELSE 0 END +
CASE WHEN [Col2] IS NOT NULL THEN 1 ELSE 0 END +
CASE WHEN [Col3] IS NOT NULL THEN 1 ELSE 0 END AS [Populated Columns]
FROM [dbo].[Table1]

在较早的版本中,这种结果是可以实现的,但是可以使用其他字符串聚合解决方法,例如XML STUFFSQLCLR函数...

答案 1 :(得分:1)

只需考虑共享另一种使用UNPIVOT进行计算的方法,并假设您的表中有一个主键/身份。

declare @tmp table (id int, [Name]  varchar(100), Customer  varchar(100), dob datetime, orderno int)
insert into @tmp select  1, 'name1','c1',getdate(),123
insert into @tmp select  2,'name2',null,getdate(),123
insert into @tmp select  3,'name3',null,null,null

    SELECT t.*, 
           t1.notpopulated 
    FROM   @tmp t 
    INNER JOIN (SELECT 4 - Count(*) AS NotPopulated, 
                        id 
                FROM 
    (SELECT id, 
            u.x, 
            u.y 
    FROM   (SELECT id, 
                Cast([name]AS VARCHAR(100))    [name], 
                Cast(customer AS VARCHAR(100)) AS customer, 
                Cast(dob AS VARCHAR(100))      AS dob1, 
                Cast(orderno AS VARCHAR(100))  orderno 
        FROM   @tmp) AS s 
        UNPIVOT ( [y] 
                FOR [x] IN ([name], 
                            [Customer], 
                            dob1, 
                            [orderno]) ) u) t 
            GROUP  BY id) t1 
        ON t1.id = t.id 

Online Demo