Approccio
Hai due errori nel tuo approccio, che introduce complessità.
-
Qualsiasi colonna che può essere derivata, come la tua MEDIA, deve non essere immagazzinato.
Se è memorizzato, costituisce una colonna duplicata ... che porta a un'anomalia di aggiornamento, come stai riscontrando. Lo scopo della normalizzazione è eliminare la duplicazione dei dati e quindi eliminare le anomalie di aggiornamento. Elimina anche codice complesso come questo, trigger, ecc.
Calcola SUM(), AVG() e così via nel set di risultati solo , al volo.
-
Utilizzo di colonne ID, che in pratica significa che hai un sistema di archiviazione dei record, non un database relazionale. Senza enumerare i molti problemi che provoca (l'ho fatto altrove), nominando semplicemente il problema qui
- hai una mentalità ID.
L'ID è un puntatore a un record fisico, non fornisce l'univocità della riga, come richiesto per i database relazionali.
L'ID è un puntatore a un record fisico, non significa nulla, l'utente non dovrebbe vederlo. Ma tu (e altri) gli avete dato un significato.
Che ti incolla alla struttura fisica del file, piuttosto che alla struttura logica dei dati. Il che a sua volta complica il tuo codice.
Pertanto, senza darti un
CREATE TABLE
corretto comando, lasciando il tuo così com'è, facciamo finta che l'ID, e la MEDIA, non esistano nel file.
Una terza voce, non relativa all'approccio, sembra che dalla cifra data, 10,58, si vogliano Chilometri per litro, mentre l'aritmetica che hai dettagliato (Litri per 100 Km) produrrà 9,44. Se vuoi una media di qualche tipo, è meglio capire prima gli elementi.
Soluzione
(Code obsolete due to revision)
Domanda modificata
Stavo cercando di ottenere le cifre da lei fornite, mentre la domanda rimaneva confusa (notare i commenti in tal senso). Dal momento che hai Rivisto la tua domanda, il requisito ora è chiaro. Ora sembra che tu voglia (a) litri per 100 Km [ancora non una "media"] e (b) una cifra complessiva per ogni record [una specie di totale parziale]. In tal caso, utilizzare questo codice.
Le note di cui sopra restano valide ed applicabili.
SELECT CARID,
DATETIME,
KM,
LI,
LPCK = ( LI_TOT / ( ( KM_LAST-KM_FIRST / 100 ) ) -- not stored
FROM (
-- create a Derived Table with KM_FIRST
SELECT CARID,
DATETIME,
-- not stored
KM_FIRST = (
SELECT MIN( KM ) -- get the first KM for car
FROM CONSUM
WHERE CARID = C.CARID
),
KM_LAST = (
SELECT MAX( KM ) -- get the last KM for car
FROM CONSUM
WHERE CARID = C.CARID
),
KM, -- KM for this row
LI, -- LI for this row
LI_TOT = (
SELECT SUM( LI ) -- get the total LI for car
FROM CONSUM
WHERE CARID = C.CARID
AND KM != ( -- exclude first LI for car
SELECT MIN( KM ) -- get the first KM for car
FROM CONSUM
WHERE CARID = C.CARID
)
)
FROM CONSUM C
) AS CONSUM_EXT
ORDER BY CARID,
DATETIME
Si noti che sto manipolando i dati e solo i dati, nessun campo fisico, non dovremmo preoccuparci degli aspetti fisici del file. I litri per 100 Km (quello che chiami MEDIA) non vengono memorizzati e lì viene evitata un'anomalia di aggiornamento. La cifra complessiva per ogni record viene calcolata "al volo", solo al momento della visualizzazione.
Questo elimina anche il tuo /first entry
problema.
Naturalmente, CARID
inoltre è privo di significato per l'utente.
Sentiti libero di commentare o porre domande, ecc.
Memorizzazione difficile
Ci sono molti problemi con la memorizzazione di un valore che può essere derivato. Questo è l'hardcoding a livello di archiviazione dei dati. Certo, puoi usare un trigger per alleviare il dolore, ma non funzionerà comunque, perché (a) il principio è infranto e (b) viola i principi ingegneristici esistenti. Per esempio. cosa succede quando il LI di una singola riga viene inserito in modo errato (es. 700.17) e successivamente corretto (es. 70.17)? Tutte le righe successive per quell'auto ora non sono corrette e devono essere ricalcolate e aggiornate. Quindi ora hai bisogno di un trigger di aggiornamento e di un trigger di inserimento. Il cancro si compone da solo.
Il concetto di anomalia di aggiornamento, il divieto di memorizzare valori che possono essere derivati, è presente dal 1970, per una buona ragione. Li evitiamo, per una buona ragione.