Self-Join auf variablen Daten
-
12-09-2019 - |
Frage
Ich habe eine Tabelle mit den folgenden Daten:
Fiscal Year | Fiscal Quarter | Fiscal Week | Data
2009 | 2 | 22 | 9.5
2009 | 2 | 24 | 8.8
2009 | 2 | 26 | 8.8
2009 | 3 | 28 | 8.8
2009 | 3 | 31 | 9.1
2009 | 3 | 33 | 8.8
Ich möchte eine Abfrage schreiben, die die folgende erzeugen würde:
Fiscal Year | Fiscal Quarter | Fiscal Week | Data | Trend
2009 | 2 | 22 | 9.5 | NULL
2009 | 2 | 24 | 8.8 | -0.7
2009 | 2 | 26 | 8.8 | 0
2009 | 3 | 28 | 8.8 | 0
2009 | 3 | 31 | 9.1 | 0.3
2009 | 3 | 33 | 8.8 | -0.3
Ich weiß, das kann einfach, indem Sie ein einfache die Tabelle mit der vorherige Geschäft Woche zu ihnen kommen erzielt werden, jedoch wird dies nicht immer eine einfache t1.[Fiscal Week] = t2.[Fiscal Week] - 2
sein, weil manchmal der Unterschied 3 Wochen ist.
Ich kann die maximale Satz leicht mit etwas wie folgt ziehen:
SELECT
MAX(t1.[Fiscal Week]) "LastWeek"
FROM t1
WHERE t1.[Fiscal Year] = 2009
AND t1.[Fiscal Week] < 31
Aber ich bin ratlos, wenn es darum geht, sie zu abstrahieren die Join-Arbeit zu machen.
Wie kann ich ein Selbst auf „der größte Geschäft Woche, die kleiner ist als der aktuelle Datensatz ist“ join?
Lösung
Der einfachste Weg, dies mit Sql 2005+ zu tun ist, die verwenden Ranking und Windowing-Funktionen - einfach Partition / Ihre Daten bestellen und eine entsprechende Sequenz zu jeder Datensatz zuweisen (in diesem Fall Sie die Partitionierung von FiscalYear und Bestellung von fiscalWeek über das Fenster) - würde wie folgt aussehen:
with data as
(
select row_number() over (partition by a.fiscalYear order by a.fiscalWeek) as rn,
a.fiscalYear, a.fiscalQuarter, a.fiscalWeek, a.Data
from #TableName a
)
select a.fiscalYear, a.fiscalQuarter, a.fiscalWeek, a.Data,
a.Data - b.Data as Trend
from data a
left join data b
on a.fiscalYear = b.fiscalYear
and a.rn = b.rn + 1
order by a.fiscalYear, a.rn
Diese besondere Abfrage erlauben würde, nicht Erweiterung über FiscalYear Grenzen - wenn Sie dieses Jahr, Grenzen überschreiten verlängern wollen würden Sie einfach die „Partition“ -Klausel und „FiscalYear“ Join-Bedingung fallen wollen und stattdessen durch eine Kombination des festgelegte Reihenfolge der FiscalYear und fiscalWeek, so etwas wie folgt aus:
with data as
(
select row_number() over (order by a.fiscalYear + a.fiscalWeek) as rn,
a.fiscalYear, a.fiscalQuarter, a.fiscalWeek, a.Data
from #TableName a
)
select a.fiscalYear, a.fiscalQuarter, a.fiscalWeek, a.Data,
a.Data - b.Data as Trend
from data a
left join data b
on a.rn = b.rn + 1
order by a.rn
Andere Tipps
funktionierts? Die Inline-Abfrage ist ein bisschen wie ein Schluck und gibt es wahrscheinlich einen besseren Weg, es zu tun ...
select
[fiscal year]
, [fiscal quarter]
, [fiscal week]
, [data]
, (
select top 1 (i.data - t1.data) from t1 as i
where i.[fiscal year] >= t1.[fiscal year]
and i.[fiscal quarter] >= t1.[fiscal quarter]
and i.[fiscal week] >= t1.[fiscal week]
and (
i.[fiscal year] <> t1.[fiscal year]
or i.[fiscal quarter] <> t1.[fiscal quarter]
or i.[fiscal week] <> t1.[fiscal week]
)
order by [fiscal year] asc, [fiscal quarter] asc, [fiscal week] asc
) as trend
from t1
Wenn Sie SQL Server 2005 verwenden, können Sie CROSS APPLY
-Klausel verwenden.
Hier konnte man eine Tabelle bewertet Funktion hat, die die Zeile für das Geschäft Woche zurück, vor das man in der aktuellen Zeile.
CREATE FUNCTION dbo.fn_GetFiscalWeekBeforeThis(@Year AS int,
@CurrentWeek as int)
RETURNS TABLE
AS
RETURN
SELECT TOP 1 *
FROM t1
WHERE [Fiscal Year] = @Year
AND [Fiscal Week] < @CurrentWeek
ORDER BY [Fiscal Week] DESC
GO
Und dann,
SELECT A.*,
A.Data - B.Data
FROM
t1 A
CROSS APPLY
dbo.fn_GetFiscalWeekBeforeThis(A.[Fiscal Year],
A.[Fiscal Week]) AS B
EDIT: Beachten Sie, dass ich durch einen Blick auf einen Artikel, der die SQL angepasst haben und ohne eine IDE
.
Auch ich weiß nicht, -., Wie es für die erste Zeile arbeiten
Also, bitte Art:)
EDIT2: Lassen Sie mich wissen, wenn es überhaupt nicht arbeiten
.
Das wird mir helfen, zu wissen, -. Dinge nicht zu beantworten, ohne die Ergebnisse überprüfen
EDIT3:. Ich habe die Notwendigkeit Quarter Parameter aus der Funktion entfernt
DECLARE @Fiscal TABLE
(
FiscalYear int
,FiscalQuarter int
,FiscalWeek int
,[Data] decimal(4,1)
)
INSERT INTO @Fiscal
( FiscalYear, FiscalQuarter, FiscalWeek, [Data] )
SELECT 2009, 2, 22, 9.5 UNION
SELECT 2009, 2, 24, 8.8 UNION
SELECT 2009, 2, 26, 8.8 UNION
SELECT 2009, 3, 28, 8.8 UNION
SELECT 2009, 3, 31, 9.1 UNION
SELECT 2009, 3, 33, 8.8 UNION
SELECT 2010, 1, 1, 9.0 UNION
SELECT 2010, 1, 2, 9.2
;
WITH abcd
AS ( SELECT FiscalYear
,FiscalQuarter
,FiscalWeek
,[Data]
,row_number() OVER ( ORDER BY FiscalYear, FiscalWeek ) AS rn
FROM @Fiscal
)
SELECT a.FiscalYear
,a.FiscalQuarter
,a.FiscalWeek
,a.[Data]
,a.[Data] - b.[Data] AS [Trend]
FROM abcd AS a
LEFT JOIN abcd AS b ON b.rn = ( a.rn - 1 )
ORDER BY a.FiscalYear
,a.FiscalWeek