Oracle:Rechercher le précédent record pour une liste de classement des prévisions
-
19-09-2019 - |
Question
Salut, je suis face à un problème difficile:
J'ai une table (oracle 9i) des prévisions météorologiques (nombre de 100 millions de disques dans la taille.) dont la composition ressemble à ceci:
stationid forecastdate forecastinterval forecastcreated forecastvalue
---------------------------------------------------------------------------------
varchar (pk) datetime (pk) integer (pk) datetime (pk) integer
où:
stationid
se réfère à l'une des nombreuses stations météorologiques qui peuvent créer une prévision;forecastdate
se réfère à la date de la prévision (date seulement pas le temps.)forecastinterval
se réfère à l'heure dans l'forecastdate
pour la prévision (0 - 23).forecastcreated
se réfère à la fois la prévision a été faite, peut-être plusieurs jours à l'avance.forecastvalue
se réfère à la valeur réelle de la prévision (comme son nom l'indique.)
J'ai besoin de déterminer, pour un stationid
et un forecastdate
et forecastinterval
paire, les dossiers où un forecastvalue
incréments plus qu'un nombre nominal (500).Je vais vous montrer un tableau de la condition ici:
stationid forecastdate forecastinterval forecastcreated forecastvalue
---------------------------------------------------------------------------------
'stationa' 13-dec-09 10 10-dec-09 04:50:10 0
'stationa' 13-dec-09 10 10-dec-09 17:06:13 0
'stationa' 13-dec-09 10 12-dec-09 05:20:50 300
'stationa' 13-dec-09 10 13-dec-09 09:20:50 300
Dans le scénario ci-dessus, j'aimerais sortir le troisième album.C'est l'enregistrement où la prévision de la valeur a augmenté d'un nominal (disons 100) montant.
La tâche s'avère très difficile en raison de la taille du tableau (nombre de 100s de millions d'enregistrements). et de prendre autant de temps pour finir (si longtemps en fait que ma requête n'a jamais retourné.)
Voici ma tentative de mesure de saisir ces valeurs:
select
wtr.stationid,
wtr.forecastcreated,
wtr.forecastvalue,
(wtr.forecastdate + wtr.forecastinterval / 24) fcst_date
from
(select inner.*
rank() over (partition by stationid,
(inner.forecastdate + inner.forecastinterval),
inner.forecastcreated
order by stationid,
(inner.forecastdate + inner.forecastinterval) asc,
inner.forecastcreated asc
) rk
from weathertable inner) wtr
where
wtr.forecastvalue - 100 > (
select lastvalue
from (select y.*,
rank() over (partition by stationid,
(forecastdate + forecastinterval),
forecastcreated
order by stationid,
(forecastdate + forecastinterval) asc,
forecastcreated asc) rk
from weathertable y
) z
where z.stationid = wtr.stationid
and z.forecastdate = wtr.forecastdate
and (z.forecastinterval =
wtr.forecastinterval)
/* here is where i try to get the 'previous' forecast value.*/
and wtr.rk = z.rk + 1)
La solution
Rexem la suggestion de l'utilisation de LAG() est la bonne approche, mais nous avons besoin d'utiliser un partitionnement de la clause.Cela devient évident une fois que nous avons ajouter des lignes pour les différents intervalles de temps et les différentes stations de...
SQL> select * from t
2 /
STATIONID FORECASTDATE INTERVAL FORECASTCREATED FORECASTVALUE
---------- ------------ -------- ------------------- -------------
stationa 13-12-2009 10 10-12-2009 04:50:10 0
stationa 13-12-2009 10 10-12-2009 17:06:13 0
stationa 13-12-2009 10 12-12-2009 05:20:50 300
stationa 13-12-2009 10 13-12-2009 09:20:50 300
stationa 13-12-2009 11 13-12-2009 09:20:50 400
stationb 13-12-2009 11 13-12-2009 09:20:50 500
6 rows selected.
SQL> SELECT v.stationid,
2 v.forecastcreated,
3 v.forecastvalue,
4 (v.forecastdate + v.forecastinterval / 24) fcst_date
5 FROM (SELECT t.stationid,
6 t.forecastdate,
7 t.forecastinterval,
8 t.forecastcreated,
9 t.forecastvalue,
10 t.forecastvalue - LAG(t.forecastvalue, 1)
11 OVER (ORDER BY t.forecastcreated) as difference
12 FROM t) v
13 WHERE v.difference >= 100
14 /
STATIONID FORECASTCREATED FORECASTVALUE FCST_DATE
---------- ------------------- ------------- -------------------
stationa 12-12-2009 05:20:50 300 13-12-2009 10:00:00
stationa 13-12-2009 09:20:50 400 13-12-2009 11:00:00
stationb 13-12-2009 09:20:50 500 13-12-2009 11:00:00
SQL>
Pour supprimer les faux positifs que nous groupe le GAL() par STATIONID, FORECASTDATE et FORECASTINTERVAL.Notez que celui-ci s'appuie sur l'intérieure de la requête qui renvoie la valeur NULL à partir de la première de calcul de chaque fenêtre partition.
SQL> SELECT v.stationid,
2 v.forecastcreated,
3 v.forecastvalue,
4 (v.forecastdate + v.forecastinterval / 24) fcst_date
5 FROM (SELECT t.stationid,
6 t.forecastdate,
7 t.forecastinterval,
8 t.forecastcreated,
9 t.forecastvalue,
10 t.forecastvalue - LAG(t.forecastvalue, 1)
11 OVER (PARTITION BY t.stationid
12 , t.forecastdate
13 , t.forecastinterval
14 ORDER BY t.forecastcreated) as difference
15 FROM t) v
16 WHERE v.difference >= 100
17 /
STATIONID FORECASTCREATED FORECASTVALUE FCST_DATE
---------- ------------------- ------------- -------------------
stationa 12-12-2009 05:20:50 300 13-12-2009 10:00:00
SQL>
Travailler avec de grands volumes de données
Vous décrivez vos tables contenant plusieurs centaines de millions de lignes.De tels tableaux sont comme des trous noirs, ils ont une autre physique.Il existe plusieurs approches possibles, en fonction de vos besoins, les délais, les finances, la base de données de la version et de l'édition, et toute autre utilisation de vos données du système d'information.C'est plus que cinq minutes à répondre.
Mais voici les cinq minutes à répondre de toute façon.
En supposant que votre table est la table en direct c'est sans doute en cours de remplissage par l'ajout prévisions à mesure qu'ils surviennent, qui est essentiellement une opération de concaténation.Cela signifierait prévisions pour chaque station sont dispersés dans tout le tableau.Par conséquent, les indices sur STATIONID ou même FORECASTDATE aurait un mauvais facteur groupement.
Dans cette hypothèse, la seule chose que je vous suggère d'essayer le premier est la création d'un index sur (STATIONID, FORCASTDATE, FORECASTINTERVAL, FORECASTCREATED, FORECASTVALUE)
.Cela va prendre un peu de temps (et de l'espace disque) pour construire, mais il devrait accélérer les requêtes ultérieures considérablement, car il a toutes les colonnes nécessaires pour satisfaire à la requête avec un INDEX RANGE SCAN sans toucher la table.