Alguém tem algum exemplo de query com pivot dinâmico?
Estou tentando fazer para deixar automático.
SELECT PRODUTO, [1], [2], [3]
FROM (
SELECT D1_COD AS PRODUTO, MONTH(D1_EMISSAO) AS MES, SUM(D1_TOTAL) D1_TOTAL
FROM SD1120 WHERE MONTH(D1_EMISSAO) BETWEEN ‘1’ AND ‘3’
GROUP BY D1_COD, MONTH(D1_EMISSAO)
) AS ORIGEM
PIVOT (
SUM(D1_TOTAL) FOR MES IN ([1], [2], [3])
) AS PivotTable
ORDER BY PRODUTO;
@dilsoncastro , tente algo assim:
DECLARE @cols NVARCHAR(MAX), @sql NVARCHAR(MAX);
SELECT @cols = STRING_AGG(QUOTENAME(MONTH(D1_EMISSAO)), ',')
FROM (SELECT DISTINCT MONTH(D1_EMISSAO) AS MES FROM SD1120 WHERE MONTH(D1_EMISSAO) BETWEEN 1 AND 3) AS Temp;
SET @sql = '
SELECT PRODUTO, ' + @cols + '
FROM (
SELECT D1_COD AS PRODUTO, MONTH(D1_EMISSAO) AS MES, SUM(D1_TOTAL) D1_TOTAL
FROM SD1120
WHERE MONTH(D1_EMISSAO) BETWEEN 1 AND 3
GROUP BY D1_COD, MONTH(D1_EMISSAO)
) AS ORIGEM
PIVOT (
SUM(D1_TOTAL) FOR MES IN (' + @cols + ')
) AS PivotTable
ORDER BY PRODUTO;';
EXEC sp_executesql @sql;
Gerou erro então alterei:
DECLARE @cols NVARCHAR(MAX), @sql NVARCHAR(MAX);
– Garante que não há duplicatas nos meses extraídos
SELECT @cols = STRING_AGG(QUOTENAME(MES), ‘,’)
FROM (
SELECT DISTINCT MONTH(D1_EMISSAO) AS MES
FROM SD1120
WHERE MONTH(D1_EMISSAO) BETWEEN 1 AND 3
) AS Temp;
– Evita erro caso @cols esteja vazio
IF @cols IS NULL OR @cols = ‘’
BEGIN
PRINT ‘Nenhum dado encontrado para o período especificado.’;
RETURN;
END
SET @sql = ’
SELECT PRODUTO, ’ + @cols + ’
FROM (
SELECT D1_COD AS PRODUTO, MONTH(D1_EMISSAO) AS MES, SUM(D1_TOTAL) AS D1_TOTAL
FROM SD1120
WHERE MONTH(D1_EMISSAO) BETWEEN 1 AND 3
GROUP BY D1_COD, MONTH(D1_EMISSAO)
) AS ORIGEM
PIVOT (
SUM(D1_TOTAL) FOR MES IN (’ + @cols + ‘)
) AS PivotTable
ORDER BY PRODUTO;’;
– Debugging: Ver SQL gerado
PRINT @sql;
EXEC sp_executesql @sql;
Será que tem alguma forma de ordenar as colunas?
Para ordenar os meses, tente isso:
DECLARE @cols NVARCHAR(MAX), @sql NVARCHAR(MAX);
-- Garante que não há duplicatas nos meses extraídos e garante que os meses estejam ordenados corretamente
SELECT @cols = STRING_AGG(QUOTENAME(MES), ',')
FROM (
SELECT DISTINCT MONTH(D1_EMISSAO) AS MES
FROM SD1120
WHERE MONTH(D1_EMISSAO) BETWEEN 1 AND 3
ORDER BY MES -- Garante a ordem correta dos meses
) AS Temp;
-- Evita erro caso @cols esteja vazio
IF @cols IS NULL OR @cols = ''
BEGIN
PRINT 'Nenhum dado encontrado para o período especificado.';
RETURN;
END
-- Monta a query dinâmica
SET @sql = '
SELECT PRODUTO, ' + @cols + '
FROM (
SELECT D1_COD AS PRODUTO, MONTH(D1_EMISSAO) AS MES, SUM(D1_TOTAL) AS D1_TOTAL
FROM SD1120
WHERE MONTH(D1_EMISSAO) BETWEEN 1 AND 3
GROUP BY D1_COD, MONTH(D1_EMISSAO)
) AS ORIGEM
PIVOT (
SUM(D1_TOTAL) FOR MES IN (' + @cols + ')
) AS PivotTable
ORDER BY PRODUTO;';
-- Debugging: Ver SQL gerado
PRINT @sql;
-- Executar a query dinâmica
EXEC sp_executesql @sql;
@dilsoncastro , deu certo a ordenação?
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified.
Veja agora:
DECLARE @cols NVARCHAR(MAX), @sql NVARCHAR(MAX);
-- Garante que não há duplicatas nos meses extraídos e mantém a ordem correta
SELECT @cols = STRING_AGG(QUOTENAME(MES), ',') WITHIN GROUP (ORDER BY MES)
FROM (
SELECT DISTINCT MONTH(D1_EMISSAO) AS MES
FROM SD1120
WHERE MONTH(D1_EMISSAO) BETWEEN 1 AND 3
) AS Temp;
-- Evita erro caso @cols esteja vazio
IF @cols IS NULL OR @cols = ''
BEGIN
PRINT 'Nenhum dado encontrado para o período especificado.';
RETURN;
END
-- Monta a query dinâmica
SET @sql = '
SELECT PRODUTO, ' + @cols + '
FROM (
SELECT D1_COD AS PRODUTO, MONTH(D1_EMISSAO) AS MES, SUM(D1_TOTAL) AS D1_TOTAL
FROM SD1120
WHERE MONTH(D1_EMISSAO) BETWEEN 1 AND 3
GROUP BY D1_COD, MONTH(D1_EMISSAO)
) AS ORIGEM
PIVOT (
SUM(D1_TOTAL) FOR MES IN (' + @cols + ')
) AS PivotTable
ORDER BY PRODUTO;';
-- Debugging: Ver SQL gerado
PRINT @sql;
-- Executar a query dinâmica
EXEC sp_executesql @sql;