Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

SQL Contagem múltipla na mesma linha com coluna dinâmica


Como você está usando o SQL Server, pode implementar a função PIVOT e, se tiver um número desconhecido de valores de período, precisará usar o SQL dinâmico:
DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME('PeriodId'+cast(periodid as varchar(10))) 
                    from Periods
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT resourcecode, ' + @cols + ' , Total
            from 
            (
               select s.resourcecode, 
                 ''PeriodId''+cast(p.periodid as varchar(10)) period,
                count(*) over(partition by s.resourcecode) Total
               from periods p
               left join schedules s
                 on p.periodid = s.periodid
            ) x
            pivot 
            (
                count(period)
                for period in (' + @cols + ')
            ) p 
            where resourcecode is not null
            order by resourcecode'

execute(@query)

Consulte SQL Fiddle with Demo . Isso dá um resultado:
| RESOURCECODE | PERIODID1 | PERIODID2 | PERIODID3 | PERIODID4 | PERIODID5 | PERIODID6 | PERIODID7 | PERIODID8 | TOTAL |
------------------------------------------------------------------------------------------------------------------------
|           AA |         2 |         0 |         3 |         0 |         0 |         0 |         0 |         0 |     5 |
|           BB |         2 |         1 |         1 |         0 |         0 |         0 |         0 |         0 |     4 |
|           CC |         1 |         1 |         1 |         0 |         0 |         0 |         0 |         0 |     3 |

Com base na sua pergunta anterior que foi marcada com MySQL, estou assumindo que você está usando o MySQL como banco de dados. Se sim, então você não tem uma função PIVOT, então você terá que usar uma função agregada com uma expressão CASE para transformar as linhas de dados em colunas.

Se os valores da coluna forem conhecidos, você poderá codificar a consulta:
select resourcecode,
  sum(case when period = 'PeriodId1' then 1 else 0 end) PeriodId1,
  sum(case when period = 'PeriodId2' then 1 else 0 end) PeriodId2,
  sum(case when period = 'PeriodId3' then 1 else 0 end) PeriodId3,
  sum(case when period = 'PeriodId4' then 1 else 0 end) PeriodId4,
  sum(case when period = 'PeriodId5' then 1 else 0 end) PeriodId5,
  sum(case when period = 'PeriodId6' then 1 else 0 end) PeriodId6,
  sum(case when period = 'PeriodId7' then 1 else 0 end) PeriodId7,
  sum(case when period = 'PeriodId8' then 1 else 0 end) PeriodId8,
  count(*) Total
from
(
  select concat('PeriodId', p.periodid) Period,
    s.resourcecode
  from periods p
  left join schedules s
    on p.periodid = s.periodid
) d
where resourcecode is not null
group by resourcecode;

Consulte SQL Fiddle with Demo . Mas se os valores forem desconhecidos ou dinâmicos, você precisará usar uma instrução preparada para gerar uma string sql para executar:
SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'sum(CASE WHEN period = ''',
      concat('PeriodId', periodid),
      ''' THEN 1 else 0 END) AS `',
      concat('PeriodId', periodid), '`'
    )
  ) INTO @sql
FROM periods;

SET @sql 
  = CONCAT('SELECT resourcecode, ', @sql, ' , count(*) Total
            from
            (
              select concat(''PeriodId'', p.periodid) Period,
                s.resourcecode
              from periods p
              left join schedules s
                on p.periodid = s.periodid
            ) d
            where resourcecode is not null
            group by resourcecode');


PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

Consulte SQL Fiddle with Demo .