计算SQL Server 2012中每行的大于0的列数

问题描述 投票:1回答:5

我有一个超过150列的表。有没有办法动态计算每个客户大于0的列。

表视图如下:

     CustomerID  (SomeColumns)    Column1       Column2 ------------------ Column150
         1           -----           0            12        0  33  0  18       97
         2           -----           1             0        54  0  72  0        0
         .
         .
         .

该表有500K行。 column1到column150的值是0还是0。如何计算大于0的列数?

查询:

Update Table
set NumOfColumnsGreaterThanZero = (select Sum(case when Column1 to Column150 >0 then 1 else 0 end)
sql-server count sql-server-2012 calculated-columns
5个回答
2
投票

您可以基于sys.columns创建动态SQL,例如:

declare @columns varchar(8000), @sql varchar(8000)

set @columns = ''

select @columns = @columns + 'case when [' + name + '] > 0 then 1 else 0 end+'
from sys.columns 
where 
    object_id = object_id('TABLENAME') and 
    name not in ('not','wanted','columns') and 
    user_type_id in (select user_type_id from sys.types where name = 'int')


set @sql = 'select CustomerId, ' + @columns + '0 as VALUE from TABLENAME'
exec (@sql)

这种方法当然存在风险,即向表中添加新列可能会导致不必要的结果。


2
投票

我怀疑你有150列的正当理由。但是,以下是使用Pivot计算非0值的方法:

DECLARE @table TABLE(customer_id int, col1 int, col2 int, 
                     col3 int, col4 int, col5 int);  

INSERT INTO @table
VALUES(1, 1, 2, 3, 4, 5) ,(2, 0, 2, 0, 4, 5) 

SELECT count(CASE WHEN columns <> 0 THEN 1 END), customer_id
FROM @table as p  
UNPIVOT      
(columns FOR Seq IN           
([col1], [col2], [col3], [col4], [col5]) ) AS unpvt  
GROUP BY customer_id

结果:

5   1
3   2

如果要动态选择列:

CREATE TABLE 
  test_table(customer_id int, col1 int, col2 int,
             col3 int, col4 int, col5 int);  

INSERT INTO test_table
VALUES(1, 1, 2, 3, 4, 5) ,(2, 0, 2, 0, 4, 5) ;

DECLARE @columnnames varchar(max)
SELECT @columnnames = coalesce(@columnnames + ',['+ column_name + ']' , '['+ column_name + ']' )
FROM INFORMATION_SCHEMA.Columns 
WHERE
  table_name = 'test_table' and 
  column_name like 'col[0-9]%' and
  table_schema = 'dbo'
ORDER BY column_name

DECLARE @sql varchar(max) = 
'SELECT count(CASE WHEN columns <> 0 THEN 1 END), customer_id
FROM test_table as p  
UNPIVOT      
(columns FOR Seq IN           
('+@columnnames+') ) AS unpvt  
GROUP BY customer_id'

EXEC (@sql)

2
投票

这是在临时表上使用3列的基本示例。您可以使用Dynamic SQL为您的结构调整它。

样本数据:

CREATE TABLE #Customers
(
    CustomerID INT
    , SomeColumn VARCHAR(100)
    , Column1 INT
    , Column2 INT
    , Column3 INT
);


INSERT INTO #Customers
    (CustomerID, SomeColumn, Column1, Column2, Column3)
VALUES
    (1, 'aaa', 1, 0, 2)
    , (2, 'bbb', 0, 0, 3)
    , (3, 'ccc', 0, 0, 0)

实际查询:

SELECT CustomerID, SomeColumn, IIF(Column1 > 0, 1, 0) + IIF(Column2 > 0, 1, 0) + IIF(Column3 > 0, 1, 0) AS T
FROM #Customers

结果如下:

CustomerID  SomeColumn  T
1           aaa         2
2           bbb         1
3           ccc         0

2
投票

为了避免我误解你的问题,我尝试创建样本表和数据,基本上我从你的问题中理解的是,每个列都是整数类型,每当记录大于0然后设置为1,否则为0;如果您能够提供样本数据和预期输出,这是很好的。 :)

CREATE TABLE tblTEST
(
COLUMN1 INT,
COLUMN2 INT,
COLUMN3 INT,
COLUMN4 INT,
COLUMN5 INT
)

INSERT INTO tblTEST
SELECT 1,0,5,12,6
UNION ALL
SELECT 1,10,0,12,6
UNION ALL
SELECT 1,30,5,0,6

DECLARE @ColumnName NVARCHAR(MAX) = ''
DECLARE @Table_Name NVARCHAR(1000) = 'TBLTEST'
DECLARE @Query NVARCHAR(MAX) = ''

DECLARE @nStart INT = 1
DECLARE @nLast INt = (SELECT COUNT(1) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = @Table_Name )

WHILE @nStart <=@nLast
BEGIN

SET @ColumnName = @ColumnName + ' CASE WHEN '+  (SELECT COLUMN_NAME FROM(SELECT COLUMN_NAME,ROW_NUMBER() OVER(ORDER BY COLUMN_NAME) RN FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @Table_Name) T1 WHERE RN=@nStart) + ' >0 THEN 1 ELSE 0 END '+ (SELECT COLUMN_NAME FROM(SELECT COLUMN_NAME,ROW_NUMBER() OVER(ORDER BY COLUMN_NAME) RN FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @Table_Name) T1 WHERE RN=@nStart) + ','

SET @nStart = @nStart + 1
END

SET @ColumnName = SUBSTRING(@ColumnName,1,LEN(@ColumnName)-1)

SET @Query = 'SELECT ' + @ColumnName + ' FROM ' + @Table_Name

EXECUTE SP_EXECUTESQL @Query

2
投票

另一种选择是使用动态sql和while循环

样本数据

 -- Populate some sample data

IF OBJECT_ID('tempdb..#T','U') IS NOT NULL DROP TABLE #T;

CREATE TABLE #T
 (Column1 INT, Column2 INT, Column3 INT, Column4 INT, Column5 INT);

INSERT INTO #T VALUES 
 (0,0,0,1,0), 
 (0,1,0,1,0), 
 (1,0,0,2,0), 
 (1,0,0,0,1);

动态SQL与while循环

DECLARE @ResultTable TABLE (HasZeroValue TINYINT);
-- Number of columns to search for zero values
DECLARE @ColumnsCount INT = 5;
-- Dynamic sql statement
DECLARE @SQL NVARCHAR(MAX);

DECLARE @i INT = 1;

WHILE @i <= @ColumnsCount
BEGIN

 SET @SQL = 'SELECT CASE COUNT(*) WHEN 0 THEN 0 ELSE 1 END FROM #T WHERE Column' + CAST(@i AS VARCHAR) + ' > 0;'; 

 INSERT @ResultTable
 EXEC sp_executesql @SQL;

 SET @i = @i + 1;

END

SELECT SUM(HasZeroValue) FROM @ResultTable;
© www.soinside.com 2019 - 2024. All rights reserved.