Auto Registrazione su dati variabili
-
12-09-2019 - |
Domanda
Ho una tabella con i seguenti dati:
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
Vorrei scrivere una query che produrrebbe il seguente:
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
So che questo può essere facilmente raggiunto facendo una semplice join della tabella a se stesso con la settimana fiscale precedente, tuttavia questo non sarà sempre un semplice t1.[Fiscal Week] = t2.[Fiscal Week] - 2
perché a volte la differenza è di 3 settimane.
posso tirare il record massimo facilmente con qualcosa di simile:
SELECT
MAX(t1.[Fiscal Week]) "LastWeek"
FROM t1
WHERE t1.[Fiscal Year] = 2009
AND t1.[Fiscal Week] < 31
Ma io sono in perdita quando si tratta di astrazione per rendere il lavoro unirsi.
Come posso fare un self join su "la più grande settimana fiscale che è più piccola del record corrente"?
Soluzione
Il modo più semplice per fare questo con Sql 2005+ è quello di utilizzare la classifica e funzioni di windowing - semplicemente partizione / ordinare i dati e assegnare una sequenza appropriata per ogni record (in questo caso si sta partizionamento fiscalYear e l'ordinazione da fiscalWeek oltre quella finestra) - sarebbe simile a questa:
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
Questa query particolare non avrebbe permesso l'estensione oltre i confini fiscalYear - se si voleva estendere ad attraversare questi confini anno si dovrebbe semplicemente vuole far cadere la "partizione" clausola e "fiscalYear" condizione di join e invece ordinare il set da una combinazione del fiscalYear e fiscalWeek, qualcosa di simile a questo:
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
Altri suggerimenti
funziona? La query in linea è un po 'di un boccone e c'è probabilmente un modo migliore di farlo ...
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
Se si utilizza SQL Server 2005, è possibile utilizzare la clausola CROSS APPLY
.
Qui si potrebbe avere una tabella di funzione a valori, che restituirà la riga per la settimana fiscale, precedente a quello in riga corrente.
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
E poi,
SELECT A.*,
A.Data - B.Data
FROM
t1 A
CROSS APPLY
dbo.fn_GetFiscalWeekBeforeThis(A.[Fiscal Year],
A.[Fiscal Week]) AS B
EDIT: Si noti che ho adattato il codice SQL, cercando in un articolo e senza un IDE
.
Inoltre, non so -. Come funzionerà per la prima riga
Quindi, si prega di essere gentile:)
EDIT2: Fatemi sapere, se non funziona in tutte le nazioni. Questo mi aiuterà a conoscere -. Non rispondere le cose, senza controllare i risultati
Edit3:. Ho rimosso la necessità di parametri trimestre dalla funzione
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