2009-05-27 17 views
79

Mam trudny czas tworzenia warunkowego INSERTMySQL Warunkowe Insert

mam x_table z kolumnami (instancja, użytkownik, poz), gdzie instancja ID jest unikalny. Chcę wstawić nowy wiersz tylko wtedy, gdy użytkownik nie ma już danego elementu.

Na przykład próbuje wstawić instancji = 919191 = 123 element obsługi = 456

Insert into x_table (instance, user, item) values (919191, 123, 456) 
    ONLY IF there are no rows where user=123 and item=456 

Każda pomoc lub wskazówki we właściwym kierunku byłoby bardzo mile widziane.

Odpowiedz

90

Jeśli DBMS nie nakłada ograniczeń na której tabeli Ci wybrać od kiedy wykonać wkładkę, spróbuj:

INSERT INTO x_table(instance, user, item) 
    SELECT 919191, 123, 456 
     FROM dual 
     WHERE NOT EXISTS (SELECT * FROM x_table 
          WHERE user = 123 
           AND item = 456) 

w tym, dual jest stół z tylko jednym rzędzie (znaleziono pierwotnie w Oracle, teraz gdzie indziej). Logika jest taka, że ​​instrukcja SELECT generuje pojedynczy wiersz danych z wymaganymi wartościami, ale tylko wtedy, gdy wartości jeszcze nie zostały znalezione.

Alternatywnie, spójrz na instrukcję MERGE.

+1

Czy w tym przypadku trzeba utworzyć słowo "dual", czy też jest to specjalna tabela "tymczasowa" utworzona przez zapytanie dotyczące samego zapytania? – itsmequinn

+8

Jeśli nie masz jeszcze 'dual', musisz go utworzyć. 'CREATE TABLE dual ( manekin CHAR (1) DEFAULT 'x' NOT NULL CHECK (manekin = 'x') PRIMARY KEY ); INSERT INTO VALUES ("x"); REVOKE ALL ON dual FROM PUBLIC; WYBÓR GRANTÓW NA PODSTAWIE DO PUBLICZNEJ; ' –

+0

Dzięki, że świetnie się zna – itsmequinn

0
Insert into x_table (instance, user, item) values (919191, 123, 456) 
    where ((select count(*) from x_table where user=123 and item=456) = 0); 

Składnia mogą się różnić w zależności od DB ...

+2

Po co to jest? MySQL? – Neutralizer

+2

Nie mogłem uruchomić tego w MySQL. – hlin117

1

Jeśli dodać, że ograniczenie (x_table.user, x_table.item) jest unikalny, a następnie wkładając kolejny wiersz z tego samego użytkownika i pozycji zawiedzie.

np

mysql> create table x_table (instance integer primary key auto_increment, user integer, item integer, unique (user, item)); 
Query OK, 0 rows affected (0.00 sec) 

mysql> insert into x_table (user, item) values (1,2),(3,4); 
Query OK, 2 rows affected (0.00 sec) 
Records: 2 Duplicates: 0 Warnings: 0 

mysql> insert into x_table (user, item) values (1,6); 
Query OK, 1 row affected (0.00 sec) 

mysql> insert into x_table (user, item) values (1,2); 
ERROR 1062 (23000): Duplicate entry '1-2' for key 2 
+0

To nie w porządku. Może istnieć wiele wierszy z tym samym użytkownikiem, ale nie z wieloma wierszami z parą elementów użytkownika. –

+0

Tak, tak. Źle przeczytałem. Edytowane w celu utworzenia wiązania na parze. – NickZoic

+0

Miły komentarz ... uruchamiam zapytanie w PHP używając mysql_query ("INSERT") i opuszczam część lub umieram, dlatego jej ostrzeżenie ostrzega mnie przed błędem, więc nie muszę wykonywać żadnych testów –

1

Chociaż dobrze jest sprawdzić przed włożeniem do powielania swoich danych I sugerują, że można umieścić UNIQUE/indeks w kolumnach tak, że żadne zduplikowane dane mogą być wstawiane przez pomyłkę.

10

Z UNIQUE(user, item) wykonaj:

Insert into x_table (instance, user, item) values (919191, 123, 456) 
    ON DUPLICATE KEY UPDATE user=123 

user=123 bit jest „no-op”, aby dopasować składnię klauzuli ON DUPLICATE bez faktycznie robi nic, gdy istnieją duplikaty.

+1

Nie mogę ustawić elementu unikatowego (użytkownik, element), ponieważ mogą wystąpić instancje wielu instancji z tym samym użytkownikiem i elementem ... po prostu nie, gdy robię tę wstawkę. –

0

Niewielkie modyfikacje odpowiedzi Aleksa, można też po prostu odwołać się do istniejącej wartości kolumna:

Insert into x_table (instance, user, item) values (919191, 123, 456) 
    ON DUPLICATE KEY UPDATE user=user 
21

Czy próbowałeś kiedyś coś takiego?

INSERT INTO x_table 
SELECT 919191 as instance, 123 as user, 456 as item 
FROM x_table 
WHERE (user=123 and item=456) 
HAVING COUNT(*) = 0; 
+0

o tak!inteligentne i przyjemne rozwiązanie za pomocą tylko jednego polecenia SELECT –

+0

Nice. Działa to dla PostgreSQL po pierwszej próbie, gdzie zaakceptowana odpowiedź nie wydaje mi się. – mightypile

39

Można również użyć INSERT IGNORE który dyskretnie ignoruje wkładkę zamiast aktualizowania lub wstawiania wiersza, gdy masz unikalny indeks (użytkownika), poz.

Kwerenda będzie wyglądać następująco:

INSERT IGNORE INTO x_table(instance, user, item) VALUES (919191, 123, 456) 

Możesz dodać unikatowy indeks z CREATE UNIQUE INDEX user_item ON x_table (user, item).

+1

thx wiele ... proste i łatwe i działa jak czar – Zorox

+0

Dokumentacja Per MySQL INSERT IGNORE jest odpowiednikiem REPLACE ... INSERT IGNORE: zachowaj stare wiersze. REPLACE: zachowaj nowe wiersze. Oba działają na unikalnych klawiszach. –

0

Więc ten wyróżnia PostgreSQL

INSERT INTO x_table 
SELECT NewRow.* 
FROM (SELECT 919191 as instance, 123 as user, 456 as item) AS NewRow 
LEFT JOIN x_table 
ON x_table.user = NewRow.user AND x_table.item = NewRow.item 
WHERE x_table.instance IS NULL 
2

W przypadku, gdy nie chcesz ustawić ograniczenie przez unikalność, to działa jak czar:

INSERT INTO `table` (`column1`, `column2`) SELECT 'value1', 'value2' FROM `table` WHERE `column1` = 'value1' AND `column2` = 'value2' HAVING COUNT(`column1`) = 0 

Nadzieję, że to pomaga!

1

Co chcesz to INSERT INTO table (...) SELECT ... WHERE .... od MySQL 5.6 manual.

W ty przypadku jest to:

INSERT INTO x_table (instance, user, item) SELECT 919191, 123, 456 
WHERE (SELECT COUNT(*) FROM x_table WHERE user=123 AND item=456) = 0 

Albo skoro nie używasz żadnej skomplikowanej logiki determiante czy uruchomić INSERT czy nie można po prostu ustawić UNIQUE klawisz na połączeniu tych dwóch kolumnach a następnie użyj INSERT IGNORE.

+0

Czy uruchomiłeś swoją odpowiedź? Ciągle otrzymuję komunikat "ERROR 1064 (42000): Wystąpił błąd w składni SQL; sprawdź instrukcję, która odpowiada twojej wersji serwera MySQL dla właściwej składni do użycia w pobliżu "gdzie ..." (działa 5.6.34) – hlin117

+0

Myślę, że powinieneś powiedzieć 'from dual' before' where'. – hlin117