カーソルを使用して動的テーブルを作成し、それらの列を使用してSQL Server 2008でデータを集計することはできますか?
たとえば、次の表を見てください。
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);
私ができることは、この形式でテーブルを作成することです
+-------------+---------+---------+-----------------+---------+--------------+---------+----------+
| [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 |
+-------------+---------+---------+-----------------+---------+--------------+---------+----------+
これを達成するために私が考えた唯一の方法は、垂直テーブルを集計することでした。
次のクエリのようなことをすることによって
SELECT MAX(BillingId), MAX(Feature), SUM(Usage), MAX(Measurement), SUM(Cost)
FROM BillingData;
ただし、特にBillingDataが月によって異なる場合があるため、これらの列を動的にBillingテーブルに結合する必要があります。例えば:
SELECT DISTINCT Feature FROM BillingData WHERE BillYear=2018 AND BillMonth=5;
とは違う
SELECT DISTINCT Feature FROM BillingData WHERE BillYear=2018 and BillMonth=4;
したがって、BillingId、Walks、Baths、Litter change、Groom、Scratching、Usage、Costの列は4月に適していますが、5月の列はBillingId、Pilling、Groom、Exercise、Usage、およびCostのみです。
ここではピボットテーブルが必要だと思いますが、月ごとに列を変える必要があるため、動的にする必要があるのではないかと思います。
これを行う最善の方法はわかりません。いくつかの助けをいただければ幸いです。
これは PIVOT
で実行でき、動的に実行できますが、動的に実行する前に、静的またはハードを使用して必要な結果を取得する必要がありますでコード化されたバージョンのクエリを使用して、動的SQLに変換します。
SQL Server 2008を使用していて、Usage
とCost
の両方の合計列が必要なため、最初に sum(<your column) over(...)
から見ていきます。 。これにより、データをピボットする前に1つのステップでデータを集約できます。
静的バージョンを取得するには、まず次のようなクエリから始めます。
_select
b.BillingId,
bd.Feature,
bd.Usage,
TotalUsage = sum(bd.Usage) over(partition by bd.BillingId),
TotalCost = sum(bd.Cost) over(partition by bd.BillingId)
from Billing b
inner join BillingData bd
on b.BillingId = bd.BillingId
where b.BillYear = 2018 and b.BillMonth = 4
_
SQLフィドルを参照 。このクエリは、ピボットしたい基本的なデータを取得します。
_| BillingId | Feature | Usage | TotalUsage | TotalCost |
|-----------|---------------|-------|------------|-----------|
| 1 | Walks | 25 | 583 | 14037.95 |
| 1 | Baths | 5 | 583 | 14037.95 |
| 1 | Walks | 500 | 583 | 14037.95 |
| 1 | Baths | 53 | 583 | 14037.95 |
| 2 | Baths | 53 | 344 | 1591.21 |
| 2 | Litter change | 53 | 344 | 1591.21 |
| 2 | Groom | 25 | 344 | 1591.21 |
| 2 | Scratching | 213 | 344 | 1591.21 |
_
BillingId
を含めて、最終的に新しい列に含めるFeatures
のそれぞれ、次にUsage
、TotalUsage
、およびTotalCost
各BillingId
。 sum(<yourcolumn> over(partition by bd.BillingId)
は、_GROUP BY
_を使用せずに各アカウントの値を提供します。このデータを取得したら、PIVOT
関数を適用できます。
_select
BillingId,
Walks = IsNull(Walks, 0),
Baths = IsNull(Baths, 0),
[Litter Change] = IsNull([Litter Change], 0),
Groom = IsNull(Groom, 0),
Scratching = IsNull(Scratching, 0),
Usage = TotalUsage,
Cost = TotalCost
from
(
select
b.BillingId,
bd.Feature,
bd.Usage,
TotalUsage = sum(bd.Usage) over(partition by bd.BillingId),
TotalCost = sum(bd.Cost) over(partition by bd.BillingId)
from Billing b
inner join BillingData bd
on b.BillingId = bd.BillingId
where b.BillYear = 2018 and b.BillMonth = 4
) x
pivot
(
sum(Usage)
for Feature in ([Walks], [Baths], [Litter Change], [Groom], [Scratching])
) piv;
_
SQLを参照Fiddle これにより結果が得られます。
_| 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 |
_
探している最終結果が得られたので、クエリを動的SQLに変換することができます。これを行うには、Feature
値として列にしたい値のリストを取得する必要があります。これは、必要なBillYear
とBillMonth
を使用してテーブルにクエリを実行し、値を文字列に連結して、その列のリストを取得し、完全なSQL文字列を実行することによって行われます。完全なコードは次のようになります。
_DECLARE
@BillYear int = 2018,
@BillMonth int = 4,
@colsNull AS NVARCHAR(MAX),
@cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ', ' + QUOTENAME(bd.Feature)
from Billing b
inner join BillingData bd
on b.BillingId = bd.BillingId
where b.BillYear = @BillYear
and b.BillMonth = @BillMonth
group by bd.Feature
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select @colsNull = STUFF((SELECT ', IsNull(' + QUOTENAME(bd.Feature)+',0) as '+ QUOTENAME(bd.Feature)
from Billing b
inner join BillingData bd
on b.BillingId = bd.BillingId
where b.BillYear = @BillYear
and b.BillMonth = @BillMonth
group by bd.Feature
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'');
set @query = N'SELECT BillingId, ' + @colsNUll + N', TotalUsage, TotalCost
from
(
select
b.BillingId,
bd.Feature,
bd.Usage,
TotalUsage = sum(bd.Usage) over(partition by bd.BillingId),
TotalCost = sum(bd.Cost) over(partition by bd.BillingId)
from Billing b
inner join BillingData bd
on b.BillingId = bd.BillingId
where b.BillYear = '+cast(@BillYear as nvarchar(4))+N'
and b.BillMonth = '+cast(@BillMonth as nvarchar(2))+N'
) x
pivot
(
sum(Usage)
for Feature in (' + @cols + N')
) p '
exec sp_executesql @query;
_
SQLを参照Fiddle with Demo 。列には2つの変数があることに気づくでしょう-1つの_@cols
_これはPIVOT
関数、次に_@colsNull
_これは最初のものと似ていますが、最終選択リストのnulls
をゼロに置き換えます-必要がない場合は、これを使用しないようにできます。これを_BillingMonth = 4
_に対して実行すると、静的バージョンと同じ結果が得られます。
_| BillingId | Baths | Groom | Litter change | Scratching | Walks | TotalUsage | TotalCost |
|-----------|-------|-------|---------------|------------|-------|------------|-----------|
| 1 | 58 | 0 | 0 | 0 | 525 | 583 | 14037.95 |
| 2 | 53 | 25 | 53 | 213 | 0 | 344 | 1591.21 |
_
次に、_BillingMonth = 5
_を変更すると、クエリを変更せずに結果が得られます( Demo ):
_| BillingId | Exercise | Groom | Pilling | TotalUsage | TotalCost |
|-----------|----------|-------|---------|------------|-----------|
| 3 | 0 | 0 | 11 | 11 | 10 |
| 4 | 1 | 5 | 0 | 6 | 75.12 |
_