我有一个超过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)
您可以基于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)
这种方法当然存在风险,即向表中添加新列可能会导致不必要的结果。
我怀疑你有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)
这是在临时表上使用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
为了避免我误解你的问题,我尝试创建样本表和数据,基本上我从你的问题中理解的是,每个列都是整数类型,每当记录大于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
另一种选择是使用动态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;