2015-02-10 23 views
1

我有一个超过150列的表。有没有什么办法可以为每个客户动态计算大于0的列。计算SQL Server 2012中每一行的大于0的列数012 2

表视图是这样的:

 CustomerID (SomeColumns) Coulumn1  Coulumn2 ------------------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) 
+0

的可能重复[将ar中的所有列值相加在SQL Server中](http:// stackoverflow。com/questions/22434651/sum-all-column-value-in-a-row-in-sql-server) – Tanner 2015-02-10 08:58:36

+0

请不要在发布之后45分钟做出重大更改 – 2015-02-10 09:27:26

+0

我刚刚发布了一个示例查询以显示我的意思。顺便说一句,谢谢你的抬头。 @ t-clausen.dk – Ariox66 2015-02-10 09:39:51

回答

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) 

当然有这种方法,添加新的列到风险表可能会导致不需要的结果。

+0

你能解释( - )部分中的user_type_id部分吗? @JamesZ – Ariox66 2015-02-10 09:48:56

+0

这就限制了只有int类型列的SQL,所以你不会意外计算会导致错误的字符串。其他数字类型也可以,您可以使用select * from sys.types – 2015-02-10 09:54:55

+0

'select CustomerId,'+ // columns // +'0'来查看它们,因为myrealtable中的VALUE不是有效的标识符。我得到这个错误@JamesZ – Ariox66 2015-02-10 10:13:39

2

这是一个在临时表上使用3列的基本示例。你可以使用动态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 
+0

你为什么使用聚合(MAX)?删除它和群组不会有任何区别 – 2015-02-10 09:32:40

+0

你先生,是对的。我会纠正它。 – 2015-02-10 09:42:21

2

我怀疑你有150列的有效理由。不过这里是你怎么能指望那些不为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   
('[email protected]+')) AS unpvt 
GROUP BY customer_id' 

EXEC (@sql) 
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 <[email protected] 
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 [email protected]) + ' >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 [email protected]) + ',' 

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;