INSERT JEŚLI NIE ISTNIEJE INNA AKTUALIZACJA?

Znalazłem kilka" byłoby "rozwiązań dla klasycznego" jak wstawić nowy rekord lub zaktualizować jeden, jeśli już istnieje", ale nie mogę dostać żadnego z nich do pracy w SQLite.

Mam tabelę zdefiniowaną następująco:

CREATE TABLE Book 
ID     INTEGER PRIMARY KEY AUTOINCREMENT,
Name   VARCHAR(60) UNIQUE,
TypeID INTEGER,
Level  INTEGER,
Seen   INTEGER

Chcę dodać rekord o unikalnej nazwie. Jeśli nazwa już istnieje, chcę zmodyfikować pola.

Czy ktoś może mi powiedzieć jak to zrobić?
Author: svick, 2010-09-03

8 answers

Spójrz na http://sqlite.org/lang_conflict.html .

Chcesz coś w stylu:

insert or replace into Book (ID, Name, TypeID, Level, Seen) values
((select ID from Book where Name = "SearchName"), "SearchName", ...);

Należy zauważyć, że każde pole spoza listy Wstaw zostanie ustawione na NULL, jeśli wiersz już istnieje w tabeli. Z tego powodu dla kolumny ID istnieje podzbiór: w przypadku zastąpienia polecenie ustawiłoby ją na NULL, a następnie przydzielono nowe ID.

To podejście można również zastosować, jeśli chcemy pozostawić tylko określone wartości pola, jeśli wiersz w przypadek zastępczy, ale ustaw pole na NULL w przypadku wstawienia.

Na przykład, zakładając, że chcesz zostawić Seen w spokoju:

insert or replace into Book (ID, Name, TypeID, Level, Seen) values (
   (select ID from Book where Name = "SearchName"),
   "SearchName",
    5,
    6,
    (select Seen from Book where Name = "SearchName"));
 274
Author: janm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-02 06:34:43

Należy użyć polecenia INSERT OR IGNORE, a następnie polecenia {[2] }: W poniższym przykładzie name jest kluczem podstawowym:

INSERT OR IGNORE INTO my_table (name, age) VALUES ('Karen', 34)
UPDATE my_table SET age = 34 WHERE name='Karen'

Pierwsze polecenie wstawi rekord. Jeśli rekord istnieje, zignoruje błąd spowodowany konfliktem z istniejącym kluczem głównym.

Drugie polecenie zaktualizuje rekord (który teraz na pewno istnieje)

 64
Author: moshik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-20 23:12:57

Musisz ustawić ograniczenie na stole, aby wywołać konflikt " ", który następnie rozwiązujesz, wykonując zastąpienie:

CREATE TABLE data   (id INTEGER PRIMARY KEY, event_id INTEGER, track_id INTEGER, value REAL);
CREATE UNIQUE INDEX data_idx ON data(event_id, track_id);

Wtedy możesz wydać:

INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 2, 2, 3);
INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 5);

"Wybierz * z danych" da ci:

2|2|2|3.0
3|1|2|5.0

Zauważ, że data.id jest "3", a nie "1", ponieważ REPLACE usuwa i wstawia, a nie aktualizuje. Oznacza to również, że musisz upewnić się, że zdefiniujesz wszystkie niezbędne kolumny lub otrzymasz nieoczekiwane wartości NULL.

 61
Author: gaspard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-27 10:54:28

Najpierw zaktualizuj. If affected row count = 0 then insert it. Jest najłatwiejszy i odpowiedni dla wszystkich RDBMS .

 31
Author: Burçin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-03 10:50:07

INSERT OR REPLACE zastąpi pozostałe pola (TypeID, Level) do wartości domyślnej.

INSERT OR REPLACE INTO book(id, name) VALUES(1001, 'Programming')

Używam tego

INSERT OR IGNORE INTO book(id) VALUES(1001);
UPDATE book SET name = 'Programming' WHERE id = 1001;

Możesz również użyć

INSERT OR REPLACE INTO book (id, name) 
VALUES (1001, 'Programming',
  (SELECT typeid FROM book WHERE id = 1001),
  (SELECT level FROM book WHERE id = 1001),
)

Ale myślę, że pierwsza metoda łatwiejsza do odczytania

 15
Author: Steely Wing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-22 04:19:07

Jeśli nie masz klucza głównego, możesz wstawić, jeśli nie istnieje, a następnie wykonać aktualizację. Tabela musi zawierać co najmniej jeden wpis przed jej użyciem.

INSERT INTO Test 
   (id, name)
   SELECT 
      101 as id, 
      'Bob' as name
   FROM Test
       WHERE NOT EXISTS(SELECT * FROM Test WHERE id = 101 and name = 'Bob') LIMIT 1;

Update Test SET id='101' WHERE name='Bob';
 4
Author: matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-01 18:04:35

Wierzę, że chcesz UPSERT .

"Wstaw lub zastąp" bez dodatkowych sztuczek w tej odpowiedzi zresetuje pola, których nie określisz na wartość NULL lub inną wartość domyślną. (Takie zachowanie INSERT lub REPLACE nie przypomina UPDATE; jest dokładnie takie samo jak INSERT, ponieważ w rzeczywistości jest INSERT; jednak jeśli to, co chciałeś, to UPDATE-if-istnieje, prawdopodobnie chcesz semantyki aktualizacji i będziesz nieprzyjemnie zaskoczony faktycznym wynikiem.)

Sztuczka z sugerowanego UPSERT implementacja polega zasadniczo na użyciu Wstaw lub zamień, ale określ wszystkie pola, używając osadzonych klauzul SELECT, aby pobrać bieżącą wartość dla pól, których nie chcesz zmieniać.

 2
Author: metamatt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:31

Myślę, że warto zwrócić uwagę, że może wystąpić nieoczekiwane zachowanie, jeśli nie do końca rozumiesz, jak Klucz podstawowy i UNIQUE oddziałują.

Jako przykład, jeśli chcesz wstawić rekord tylko wtedy, gdy poleNAME nie jest aktualnie zajęte, a jeśli tak, chcesz, aby wyjątek ograniczenia miał ci powiedzieć, to INSERT lub REPLACE nie wyrzuci i wyjątek, a zamiast tego rozwiąże unikalne ograniczenie poprzez zastąpienie sprzeczny rekord (istniejący rekord o tej samej nazwie ). Gaspard ' s pokazuje to bardzo dobrze w swojej odpowiedzi powyżej.

Jeśli chcesz użyć wyjątku ograniczenia do fire, musisz użyć INSERT i polegać na osobnym poleceniu UPDATE, aby zaktualizować rekord, gdy wiesz, że nazwa nie jest zajęta.

 1
Author: Matt Matthias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:30