Подсчет количества столбцов больше 0 для каждой строки в SQL Server 2012

У меня есть таблица с более чем 150 столбцами. есть ли способ динамически подсчитывать столбцы больше 0 для каждого клиента.

представление таблицы похоже на:

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

Эта таблица имеет 500 тысяч строк. значения от столбца1 до столбца150 либо равны 0, либо нет. как я могу подсчитать количество столбцов больше 0?

Запрос:

Update Table
set NumOfColumnsGreaterThanZero = (select Sum(case when Column1 to Column150 >0 then 1 else 0 end)

person Ariox66    schedule 10.02.2015    source источник
comment
возможный дубликат суммировать все значения столбца в строке в SQL Сервер   -  person Tanner    schedule 10.02.2015
comment
пожалуйста, не вносите серьезных изменений в запрос через 45 минут после публикации.   -  person t-clausen.dk    schedule 10.02.2015
comment
Я только что опубликовал пример запроса, чтобы показать, что я имел в виду. кстати, спасибо за наводку. @t-clausen.dk   -  person Ariox66    schedule 10.02.2015


Ответы (5)


Вы можете создать динамический SQL на основе sys.columns, например:

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)

Конечно, при таком подходе существует риск того, что добавление новых столбцов в таблицу может привести к нежелательным результатам.

person James Z    schedule 10.02.2015
comment
не могли бы вы объяснить часть user_type_id в части (--)? @ДжеймсЗ - person Ariox66; 10.02.2015
comment
Это ограничивает SQL только для столбцов типа int, поэтому вы случайно не вычисляете строки, которые могут вызвать ошибку. Другие числовые типы тоже в порядке, вы можете увидеть их с помощью select * from sys.types - person James Z; 10.02.2015
comment
'выберите CustomerId, ' + //столбцы// + '0 as VALUE from myrealtable' не является допустимым идентификатором. Я получаю эту ошибку @JamesZ - person Ariox66; 10.02.2015
comment
я могу использовать только один знак at в комментарии. я использовал один для вас, поэтому я не мог использовать знак at перед столбцом @JamesZ - person Ariox66; 10.02.2015
comment
Я знаю, что им нужно [], не могли бы вы применить это исправление в своем ответе? (править) @JamesZ - person Ariox66; 10.02.2015
comment
Исправил это и удалил некоторые из моих комментариев, чтобы сделать это короче. - person James Z; 10.02.2015
comment
Я заменил exec at-sign sql на exec (at-sign sql). ошибка ушла. но все значения равны 0. но я знаю, что минимальное значение должно быть как минимум 1. в некоторых случаях 20 или 30 столбцов имеют значения больше 0. @JamesZ - person Ariox66; 10.02.2015
comment
Если вы распечатаете sql, вы можете посмотреть его сами и посмотреть, какие там столбцы. Возможно, ограничение типа теперь игнорирует столбцы, которые у вас есть на самом деле. - person James Z; 10.02.2015
comment
Нет, дорогой, хотя столбцы, которые я хочу подсчитать, имеют тип int, я даже тестировал запрос без этого предложения (user_type_id). все еще значения равны 0 @JamesZ - person Ariox66; 10.02.2015
comment
Просто распечатайте SQL (распечатайте @sql) и посмотрите, какие там столбцы/что это за SQL. Это должно объяснить вам, как это работает и что не так. - person James Z; 10.02.2015

Я сомневаюсь, что у вас есть веская причина иметь 150 столбцов. Однако вот как вы можете подсчитать значения, которые не равны 0, используя Pivot:

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)
person t-clausen.dk    schedule 10.02.2015

Это базовый пример использования 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
person Evaldas Buinauskas    schedule 10.02.2015
comment
почему вы используете агрегат (MAX)? Удаление его и группы не будет иметь никакого значения - person t-clausen.dk; 10.02.2015

чтобы избежать неправильного понимания вашего вопроса, я пытаюсь создать образец таблицы и данных, в основном, как я понимаю из ваших вопросов, каждый из столбцов имеет целочисленный тип, всякий раз, когда запись больше 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
person Low Chee Mun    schedule 10.02.2015

Другой вариант - использовать динамический 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;
person michael.abdulakh    schedule 10.02.2015