Un semplice auto unirsi sembrerebbe svolgere molto meglio di una fila riferimento sottoquery
generare 10k righe di dati di test:
drop table test10k
create table test10k (Id int, Number int, constraint test10k_cpk primary key clustered (id))
;WITH digits AS (
SELECT 0 as Number
UNION SELECT 1
UNION SELECT 2
UNION SELECT 3
UNION SELECT 4
UNION SELECT 5
UNION SELECT 6
UNION SELECT 7
UNION SELECT 8
UNION SELECT 9
)
,numbers as (
SELECT
(thousands.Number * 1000)
+ (hundreds.Number * 100)
+ (tens.Number * 10)
+ ones.Number AS Number
FROM digits AS ones
CROSS JOIN digits AS tens
CROSS JOIN digits AS hundreds
CROSS JOIN digits AS thousands
)
insert test10k (Id, Number)
select Number, Number
from numbers
vorrei tirare il caso particolare delle prime 3 righe fuori la query principale, puoi UNIONE TUTTI quelli che rientrano se lo vuoi veramente nel set di righe. Auto unirsi query:
;WITH NumberedRows
AS
(
SELECT rta.*, row_number() OVER (ORDER BY rta.ID ASC) AS RowNumber
FROM test10k rta
)
SELECT nr.ID, nr.Number,
avg(trailing.Number) as MovingAverage
FROM NumberedRows nr
join NumberedRows as trailing on trailing.RowNumber between nr.RowNumber-3 and nr.RowNumber-1
where nr.Number > 3
group by nr.id, nr.Number
Sulla mia macchina questo richiede circa 10 secondi, l'approccio subquery che Aaron Alton dimostrato richiede circa 45 secondi (dopo l'ho cambiato per riflettere il mio test tabella di origine):
;WITH NumberedRows
AS
(
SELECT rta.*, row_number() OVER (ORDER BY rta.ID ASC) AS RowNumber
FROM test10k rta
)
SELECT nr.ID, nr.Number,
CASE
WHEN nr.RowNumber <=3 THEN NULL
ELSE ( SELECT avg(Number)
FROM NumberedRows
WHERE RowNumber < nr.RowNumber
AND RowNumber >= nr.RowNumber - 3
)
END AS MovingAverage
FROM NumberedRows nr
Se si esegue un SET STATISTICS PROFILE ON, è possibile vedere che self join ha eseguito 10k sullo spool della tabella. La subquery esegue 10k sul filtro, sull'aggregazione e su altri passaggi.
Che tipo di database SQL stai usando? –
Sto usando SQL Server 2008. – HYP
Sto pensando che questo è uno di quei casi davvero rari in cui i cursori saranno più veloci ... basta tenere le ultime 3 righe in vars ... –