2012-04-04 13 views
7

Vorrei creare una vista in SQLite in cui un campo in una riga dipende dal valore di un campo nella riga precedente. Potrei farlo in Oracle usando la funzione analitica LAG, ma non sono sicuro di come farlo in SQLite.Creare una vista SQLite in cui una riga dipende dalla riga precedente

Per esempio, se il mio tavolo sembrava:

ITEM  DAY   PRICE 
apple  2011-01-07 1.25 
orange  2011-01-02 1.00 
apple  2011-01-01 1.00 
orange  2011-01-03 2.00 
apple  2011-01-08 1.00 
apple  2011-01-10 1.50 

Vorrei che il mio scopo di assomigliare, con WHERE item = 'apple':

DAY   PRICE CHANGE 
2011-01-01 1.00  (null) 
2011-01-07 1.25  0.25 
2011-01-08 2.00  0.75 
2011-01-10 1.50  -0.50 

Edit:

L'equivalente del la query che sto cercando avrebbe cercato in Oracle qualcosa come (non ho provato questo, ma penso che sia corretto):

SELECT day, price, 
     price - LAG(price, 1) OVER (ORDER BY day) AS change 
    FROM mytable 
WHERE item = 'apple' 
+0

Definire "precedente". Sembra il singolo record consentito per la data un giorno prima del record corrente. È sempre vero? –

+0

No. Ho ampliato l'esempio. Con "precedente" intendo fondamentalmente la fila di righe prima di quella in questione, una volta ordinate. – eaolson

+0

Definisci "ordinato". Fondamentalmente, il problema è che i database SQL (per definizione) non hanno alcun concetto di ordinamento delle righe a parte quello che si specifica specificamente, per nome di colonna, sul recupero. In genere puoi ottenere il risultato desiderato, ma dovrai ricavare la "riga precedente" nell'algebra relazionale nella definizione della tua vista e, per farlo, devi essere molto chiaro su come definire "precedente" in chiaro linguaggio. –

risposta

0

Partendo dal presupposto che non si elimina questo funzionerà:


SELECT t2.DAY, t2.price, t2.price-t1.price 
FROM TABLENAME t1, TABLENAME t2 
WHERE t1.rowid=t2.rowid-1 

Questo funziona perché ogni riga ha un proprio identificativo, anche se non si specifica nella dichiarazione CREATE.

Se non elimina, diventa:


SELECT t2.day, t2.price, t2.price-t1.price 
FROM 
    (SELECT l1.day, l1.price, 
      (SELECT COUNT(*) 
      FROM TABLENAME l2 
      WHERE l2.rowid < l1.rowid) AS count 
     FROM TABLENAME l1) AS t1, 
    (SELECT l1.day, l1.price, 
      (SELECT COUNT(*) 
      FROM TABLENAME l2 
      WHERE l2.rowid < l1.rowid) AS count 
     FROM TABLENAME l1) AS t2 
WHERE t1.count=t2.count-1 

Questo funziona in base al presupposto che ROWID sono sempre in aumento.

+0

Questo fa supposizioni sulla storia della tabella (ordina che le file siano state inserite, che non siano mai state aggiornate, ecc.) Che preferirei non fare. – eaolson

2

È la stessa idea dell'altra, ma utilizza solo i campi anziché il rowid. Questo fa esattamente ciò che si vuole:


CREATE TABLE Prices (
    day DATE, 
    price FLOAT 
); 

INSERT INTO Prices(day, price) VALUES(date('now', 'localtime', '+1 day'), 0.5); 
INSERT INTO Prices(day, price) VALUES(date('now', 'localtime', '+0 day'), 1); 
INSERT INTO Prices(day, price) VALUES(date('now', 'localtime', '-1 day'), 2); 
INSERT INTO Prices(day, price) VALUES(date('now', 'localtime', '-2 day'), 7); 
INSERT INTO Prices(day, price) VALUES(date('now', 'localtime', '-3 day'), 8); 
INSERT INTO Prices(day, price) VALUES(date('now', 'localtime', '-4 day'), 10); 

SELECT p1.day, p1.price, p1.price-p2.price 
FROM 
    Prices p1, Prices p2, 
    (SELECT t2.day AS day1, MAX(t1.day) AS day2 
    FROM Prices t1, Prices t2 
    WHERE t1.day < t2.day 
    GROUP BY t2.day) AS prev 
WHERE p1.day=prev.day1 
    AND p2.day=prev.day2 

Se si desidera aggiungere il bit WHERE item='apple' che ci si aggiunge che, per entrambi i WHERE clausole.

1

Questo dovrebbe fare il trucco per ogni item (testato su SQLite):

SELECT 
    day 
    ,price 
    ,price - (SELECT t2.price 
       FROM mytable t2 
       WHERE 
        t2.item = t1.item AND 
        t2.day < t1.day  
       ORDER BY t2.day DESC 
       LIMIT 1 
      ) AS change 
FROM mytable t1 

Questo presuppone la combinazione tra il day e item è unico. E il modo in cui funziona è prendere tutti i valori meno di il dato day, l'ordinamento discendente e quindi LIMIT solo il primo valore, simulando una funzione LAG.

Per un comportamento LEAD, basta capovolgere < a > e DESC a ASC.

Problemi correlati