2010-09-05 4 views
13

Dans SQLite, étant donné ce schéma de base de donnéesincrémente le compteur ou Insérer une ligne dans une instruction, dans SQLite

CREATE TABLE observations (
    src TEXT, 
    dest TEXT, 
    verb TEXT, 
    occurrences INTEGER 
); 
CREATE UNIQUE INDEX observations_index 
    ON observations (src, dest, verb); 

chaque fois qu'une nouvelle observation tuple (:src, :dest, :verb) arrive, je veux soit incrémenter la colonne « occurrences » pour l'existant ligne pour ce tuple, ou ajoutez une nouvelle ligne avec occurrences = 1 s'il n'y en a pas déjà une. Dans le pseudocode concret:

if (SELECT COUNT(*) FROM observations 
     WHERE src == :src AND dest == :dest AND verb == :verb) == 1: 
    UPDATE observations SET occurrences = occurrences + 1 
     WHERE src == :src AND dest == :dest AND verb == :verb 
else: 
    INSERT INTO observations VALUES (:src, :dest, :verb, 1) 

Je me demande s'il est possible de faire toute cette opération dans une instruction SQLite. Cela simplifierait la logique de l'application (qui doit être entièrement asynchrone par rapport aux opérations de la base de données) et éviterait également une double recherche d'index avec exactement la même clé. INSERT OR REPLACE ne semble pas être ce que je veux, et hélas, il n'y a pas UPDATE OU INSERT.

+0

Ne serait-il pas plus logique de déclarer 'occurrences' comme INTEGER? – dan04

+0

D'oh! Je voulais. Édité. – zwol

Répondre

11

J'ai eu cette réponse de Igor Tandetnik sur SQLite utilisateurs:

INSERT OR REPLACE INTO observations 
VALUES (:src, :dest, :verb, 
    COALESCE(
    (SELECT occurrences FROM observations 
     WHERE src=:src AND dest=:dest AND verb=:verb), 
    0) + 1); 

Il est légèrement mais toujours plus rapide que l'approche de dan04.

+1

Désolé si cela est évident, mais n'oubliez pas de créer un index unique selon l'OP ou cela va toujours créer un nouveau compteur et ne jamais incrémenter: 'CREER UNIQUE INDEX observations_index ON observations (src, dest, verbe);' . – ahcox

+0

Notez également qu'il incrémente le ROWID à chaque mise à jour (car chaque mise à jour est par essence un DELETE + INSERT) – ayke

3

Je ne sais pas d'une façon de le faire dans une déclaration, mais vous pouvez essayer

BEGIN; 
    INSERT OR IGNORE INTO observations VALUES (:src, :dest, :verb, 0); 
    UPDATE observeraions SET occurrences = occurrences + 1 WHERE 
     src = :src AND dest = :dest AND verb = :verb; 
COMMIT; 
Questions connexes