É possível usar um cursor para criar uma tabela dinâmica e depois usar essas colunas para agregar dados no SQL Server 2008?
Por exemplo, pegue a tabela a seguir.
CREATE TABLE Billing (
BillingId BIGINT IDENTITY,
SubscriptionId BIGINT,
ExternalServiceName VARCHAR(50),
BillYear INT NOT NULL,
BillMonth INT NOT NULL
);
INSERT INTO Billing (BillingId, SubscriptionId, ExternalServiceName,
BillYear, BillMonth)
VALUES (1, 1, 'Dogs', 2018, 4),
(2, 2, 'Cats', 2018, 4),
(3, 1, 'Dogs', 2018, 5),
(4, 2, 'Cats', 2018, 5);
CREATE TABLE BillingData (
BillingDataId INT IDENTITY PRIMARY KEY,
BillingId INT NOT NULL,
Feature VARCHAR(50) NOT NULL,
Usage INT NOT NULL,
Measurement VARCHAR(50),
Cost NUMERIC(18,2) NOT NULL
);
INSERT INTO BillingData(BillingId, Feature, Usage, Measurement, Cost)
VALUES (1, 'Walks', 25, 'walks', 200.32),
(1, 'Baths', 5, 'baths', 251.32),
(2, 'Litter change', 53, 'changes', 110.21),
(2, 'Groom', 25, 'brushings', 123),
(2, 'Scratching', 213, 'clipping', 123),
(3, 'Pilling', 11, 'medicate', 10),
(4, 'Groom', 5, 'brushings', 50),
(4, 'Exercise', 1, 'run', 25.12),
(1, 'Walks', 500, 'walks', 12351.31),
(1, 'Baths', 53, 'baths', 1235),
(2, 'Baths', 53, 'baths', 1235);
O que eu gostaria de poder fazer é criar uma tabela com este formato
+-------------+---------+---------+-----------------+---------+--------------+---------+----------+
| [BillingId] | [Walks] | [Baths] | [Litter change] | [Groom] | [Scratching] | [Usage] | [Cost] |
+-------------+---------+---------+-----------------+---------+--------------+---------+----------+
| 1 | 525 | 58 | 0 | 0 | 0 | 583 | 14037.95 |
| 2 | 0 | 53 | 53 | 25 | 213 | 344 | 1591.21 |
+-------------+---------+---------+-----------------+---------+--------------+---------+----------+
A única maneira que consegui pensar para fazer isso foi agregar a tabela vertical.
Fazendo algo como a seguinte consulta
SELECT MAX(BillingId), MAX(Feature), SUM(Usage), MAX(Measurement), SUM(Cost)
FROM BillingData;
Mas então eu teria que juntar dinamicamente essas colunas na tabela Billing, especialmente porque o BillingData pode não ser o mesmo mês a mês. Por exemplo:
SELECT DISTINCT Feature FROM BillingData WHERE BillYear=2018 AND BillMonth=5;
É diferente de
SELECT DISTINCT Feature FROM BillingData WHERE BillYear=2018 and BillMonth=4;
Assim, enquanto as colunas BillingId, Walks, Baths, Litter change, Groom, Scratching, Usage, Cost são apropriadas para abril, as colunas de maio seriam apenas BillingId, Pilling, Groom, Exercise, Usage e Cost.
Acredito que uma tabela dinâmica pode ser o que eu preciso aqui, mas suspeito que ela precise ser dinâmica, pois as colunas precisariam ser diferentes para cada mês.
Não tenho certeza da melhor maneira de fazer isso. Alguma ajuda seria muito apreciada.
Isso pode ser feito
PIVOT
e pode ser feito dinamicamente, mas antes de tentar fazer isso dinamicamente, você deve tentar obter o resultado desejado usando uma versão estática ou codificada da consulta e convertê-la em sql dinâmico .Como você está usando o SQL Server 2008 e deseja uma coluna total para
Usage
eCost
, eu começaria primeiro examinandosum(<your column) over(...)
. Isso permitirá que você agregue seus dados em uma única etapa antes de dinamizá-los.Para obter a versão estática, eu começaria primeiro com uma consulta semelhante a esta:
Consulte SQL Fiddle . Essa consulta fornece os dados básicos que você deseja dinamizar:
Incluindo seu
BillingId
, cada um dosFeatures
que você eventualmente deseja em uma nova coluna, depois oUsage
,TotalUsage
eTotalCost
para cadaBillingId
. Osum(<yourcolumn> over(partition by bd.BillingId)
dá-lhe o valor de cada conta sem ter que usarGROUP BY
. Depois de obter esses dados, você pode aplicar aPIVOT
função:Consulte SQL Fiddle para demonstração . Isso dá um resultado:
Agora que você obteve o resultado final que procura, pode começar a converter a consulta em SQL dinâmico. Para fazer isso, você precisará obter uma lista dos valores que deseja que sejam a coluna, também conhecida como
Feature
valores. Isso é feito consultando suas tabelas com oBillYear
eBillMonth
você deseja e concatenando os valores em uma string, pegando essa lista de colunas e executando uma string sql completa. O código completo pode ser semelhante a:Consulte SQL Fiddle com demonstração . Você notará que existem duas variáveis para as colunas - uma
@cols
que é usada dentro daPIVOT
função e, em seguida,@colsNull
é semelhante à primeira, mas substitui anulls
na lista de seleção final por zero - você pode excluir usando isso se não não precisa. Se você executar isso paraBillingMonth = 4
obterá o mesmo resultado que a versão estática:Então, se você alterar o
BillingMonth = 5
, obterá os resultados sem precisar alterar a consulta ( Demo ):