How to dynamically calculate sums of many columns in GROUP?

In the table below, I have a variable number of columns, and the number is 1000. I need to sum all the values ​​of each of the 1000 columns grouped by person name. So, smith'stotal test_score_1, total test_score_2, ... total test_score_1000. And then Jackson'stotal test_score_1, total test_score_2, ... total test_score_1000.

I don't know the number of columns ' test_score_n' and they always change.

So, given this table:

name      test_score_1 test_score_2 ...  test_score_1000
  smith        2              1                 0
  jackson      0              3                 1
  jackson      1              1                 2
  jackson      3              0                 3
  smith        4              5                 1

How can I create the table below?

name      test_score_1 test_score_2 ...  test_score_1000
  smith        6              6                1
  jackson      4              4                6
+4
source share
6 answers

SQL to create SQL

DECLARE @generatedSQL nvarchar(max);

SET @generatedSQL = (

SELECT
    'SELECT ' + 
    SUBSTRING(X.foo, 2, 2000) + 
    'FROM ' + 
    QUOTENAME(SCHEMA_NAME(t.schema_id)) + '.' + QUOTENAME(t.name) +
    ' GROUP BY name' --fix this line , edited
FROM
    sys.tables t
    CROSS APPLY 
    (
    SELECT
        ', SUM(' + QUOTENAME(c.name) + ')'
    FROM 
        sys.columns c 
    WHERE 
        c.object_id = t.object_id
        AND
        c.name <> 'Name'
    FOR XML PATH('')
    ) X (foo)
WHERE
    t.name = 'MyTable'
 );

EXEC (@generatedSQL);
+7

: http://rextester.com/MAFCP19297

SQL

DECLARE @cols varchar(max), @sql varchar(max);

SELECT @cols = 
     COALESCE(@cols + ', ', '') + 'SUM(' + COLUMN_NAME + ') AS ' + COLUMN_NAME
     FROM INFORMATION_SCHEMA.COLUMNS
     WHERE table_name = '<tbl name>'
       AND COLUMN_NAME <> 'name'
       -- The AND below may be optional - see "Additional Notes #1"
       AND TABLE_CATALOG = '<database schema name>';

SET @sql = 'SELECT name, ' + @cols + ' FROM tbl GROUP BY name;';

EXEC (@sql); 

  • DECLARE : , SQL, SQL .
  • SELECT INFORMATION_SCHEMA.COLUMNS, tbl, name. ( sys - ). , , (, , FOR XML PATH ('')). , , , - SUM , .
  • SET SQL, - : SELECT name, SUM(test_score_1) AS test_score_1, SUM(test_score_2) AS test_score_2, SUM(test_score_1000) AS test_score_1000 FROM tbl GROUP BY name;.
  • EXEC .

  • , , : AND TABLE_CATALOG = '<database schema name> '
  • MySQL, SQL Server - , -...
+4

tablename -.

     Declare @query as nvarchar(MAX) = (SELECT
    'SELECT name,' + SUBSTRING(tbl.col, 2, 2000) + ' FROM ' + QUOTENAME(SCHEMA_NAME(t.schema_id)) + '.' + QUOTENAME(t.name) + 'Group By name'
FROM
    sys.tables t
    CROSS APPLY 
    (
    SELECT
        ', SUM(' + QUOTENAME(columns.name) + ') as ' + columns.name
    FROM 
        sys.columns columns 
    WHERE 
        columns.object_id = t.object_id and columns.name != 'name'
    FOR XML PATH('')
    ) tbl (col)
WHERE
    t.name = 'tablename')
select @query EXECUTE(@query)
+1

Sql script

DECLARE @Sql nvarchar(max)

SET @Sql=( SELECT DISTINCT 'SELECT'+ 
                    STUFF((SELECT ', '+  ' SUM( '+ COLUMN_NAME +' ) AS '+ QUOTENAME( COLUMN_NAME )
                    FROM INFORMATION_SCHEMA.COLUMNS Where TABLE_NAME ='Tab1000' 
                    FOR XML PATH (''),type).value('.','varchar(max)'),1,2,'')
                    +' From Tab1000'From INFORMATION_SCHEMA.COLUMNS Where TABLE_NAME ='Tab1000')

EXEC (@sql)
+1

script

(set @tableName = [yourTablename] and @nameColumn the name of the field you want to group)

    Declare @tableName varchar(50)='totalscores'
    Declare @nameColumn nvarchar(50)='name'

    Declare @query as nvarchar(MAX) ;

    select @query = 'select ' + nameColumn  + cast(sumColumns as nvarchar(max))  + 'from ' + @tableName +' group by ' + nameColumn     from (
    select @nameColumn nameColumn, (SELECT 
            ', SUM(' + QUOTENAME(c.name) + ') ' + QUOTENAME(c.name)
        FROM
            sys.columns c
        WHERE
            c.object_id=t.object_id and c.name != @nameColumn
        order by c.name
        FOR 
            XML path(''), type
     ) sumColumns
     from sys.tables t where  t.name= @tableName
    )t

    EXECUTE(@query)
+1
source

GBN dynamic SQL would be my first choice (+1) and would be more productive. However , if you are interested in breaking this horrible column loop with more than 1000+ columns, consider the following:

Example

Declare @YourTable Table ([col 1] int,[col 2] int,[col 1000] varchar(50))
Insert Into @YourTable Values 
 (2,1,0)
,(4,5,1)

Select Item  = replace(C.Item,'_x0020_', ' ')
      ,Value = sum(C.Value)
 From @YourTable A
 Cross Apply (Select XMLData= cast((Select A.* for XML RAW) as xml)) B
 Cross Apply (
                Select Item   = a.value('local-name(.)','varchar(100)')
                      ,Value  = a.value('.','int') 
                 From  B.XMLData.nodes('/row')  as C1(n)
                 Cross Apply C1.n.nodes('./@*') as C2(a)
                 Where a.value('local-name(.)','varchar(100)') not in ('Fields','ToExclude')
             ) C
 Group By C.Item

Returns

Item        Value
col 1       6
col 2       6
col 1000    1
0
source

Source: https://habr.com/ru/post/1682494/


All Articles