ON DUPLICATE KEY

0

Chcę użyć ON DUPLICATE KEY, ponieważ czytałem że jeżeli istnieje podany rekord w INSERT INTO to wykonuje inną operację (u mnie UPDATE). Mam tak:

INSERT INTO proba (`Nazwa`, `Ilosc`) VALUES('cos', '1') ON DUPLICATE KEY UPDATE `Ilosc` = '3'

Napisałem to do prób. Tabela wygląda tak:
id - int(11) auto increment
Nazwa - char(10)
Ilosc - tinyint(2)

Mimo takiego zastosowania za każdym razem dodaje to samo, zamiast zmienić Ilosc na 3.

Co robię źle ?

0

Jak nazwa wskazuje on duplikate key działa wtedy, gdy klucz główny jest duplikowany. Zgaduję, że pole id jest kluczem głównym. Natomiast pole Ilosc nie jest kluczem, a jeżeli chcesz żeby było unikalne to może spróbuj unique.

0

Czyli działa to tak że sprawdza czy duplikowany jest klucz główny lub unikatowy i wtedy wykonuje UPDATE ?

A może być tak że Primary key to pole id, a unique to pole Ilosc ?

0

UNIQUE źle działa.

Patrząc na tabelę przedstawioną w 1 poście, chcę zrobić tak:

  • jeżeli istnieje już rekord o dokładnie takich samych polach jak dodawany (poza id i Ilosc) to ma zwiększyć pole Ilosc o 1
  • jeżeli nie istnieje to dodaje nowy rekord (id - kolejne z AI, Ilosc - 1).
0

id - int(11) auto increment
Nazwa - char(10)
Ilosc - tinyint(2)

Używasz ON DUPLICATE, tak? Chcesz wywołać akcję, gdy klucz się powtarza, tak?

Podstawowo mamy dwa rekordy, dokładnie takie, które ty chciałbyś sklejać:

+----+----------+-------+
| id | nazwa    | ilosc |
+----+----------+-------+
| 1  | Banan    | 2     |
| 2  | Banan    | 5     |
+----+----------+-------+

To teraz zagadka, względem jakiej kolumny trzeba pogrupować te rekordy?
Hint: Grupowanie według kolumny ma sens tylko jeśli wartości tej kolumny się powtarzają. Dużego wyboru nie masz. I... tak. To ta kolumna musi być kluczem.

0

Nie o to chodzi. Dajmy na to że chcę zapisywać id zalogowanego usera oraz ilość wejść na stronę. Przykładowo mamy tabelę:
rekord_id - int(11) auto increment
user_id - int(11)
count - int(11) - specjalnie dałem int(11)

Teraz ma działać to tak:

  • jeżeli nie ma jeszcze w tabeli tego usera to dodaję go, tak jak to robi:
INSERT INTO tabela VALUES(NULL, 'jakis_numer', '1')
  • jeżeli jest to zmieniam wartość count na count+1;

Z poziomu php nie otrzymuję rekord_id (mysql zwiększa mi to automatycznie). Otrzymuję tylko user_id i tyle.

0

Właśnie to co napisałem powyżej ilustruje ten przypadek...

0

No nie. Ty robisz tak że rekordy mają to samo "wnętrze" (czyli wszystko poza id i ilosc - w tym przypadku jest tylko nazwa, ale u mnie w bazie jest więcej pól).

Może jako lepszy przykład podam koszyk z polami:

id user_id nazwa kolor rozmiar ilosc (standardowo wstawia wartość 1)
1 1 rakietka czarny 100cm 2
2 1 piłka bialy 40cm 4
3 2 piłka czerwony 40cm 1
4 3 samochodzik niebieski 150cm 1

I teraz jest tak że pole id - jest typu auto increment, więc w zapytaniach wpisuję NULL lub po prostu nie podaję.

Chodzi o to że jeżeli mam:

INSERT INTO koszyk (`user_id`, `nazwa`, `kolor`, `rozmiar`) VALUES('1', 'piłka', 'biały', '40cm')

to taki rekord istnieje i nie powinien go dodać tylko zrobić

UPDATE ilosc = ilosc+1

Natomiast gdy moje zapytanie będzie wyglądać:

INSERT INTO koszyk (`user_id`, `nazwa`, `kolor`, `rozmiar`) VALUES('1', 'piłka', 'niebieski', '40cm')

to doda nowy rekord (dałem tutaj kolor niebieski zamiast biały, dlatego powinien dodać rekord).

1

A masz zdefiniowane ograniczenie na unikalność pól userid + nazwa + kolor + rozmiar ?
Pewno nie, więc nie wystąpi zdarzenie zduplikowanego klucza.

[code]
mysql> create table koszyk(
-> id int primary key auto_increment,
-> user_id int,
-> nazwa varchar(50),
-> kolor varchar(50),
-> rozmiar varchar(50),
-> ilosc int default 1
-> );
Query OK, 0 rows affected (0.10 sec)

mysql> INSERT INTO koszyk (user_id, nazwa, kolor, rozmiar) VALUES('1', 'piłka', 'biały', '40cm');
Query OK, 1 row affected (0.07 sec)

mysql> INSERT INTO koszyk (user_id, nazwa, kolor, rozmiar) VALUES('1', 'piłka', 'biały', '40cm');
Query OK, 1 row affected (0.06 sec)

mysql> SELECT * FROM koszyk;
+----+---------+--------+--------+---------+-------+
| id | user_id | nazwa | kolor | rozmiar | ilosc |
+----+---------+--------+--------+---------+-------+
| 1 | 1 | piłka | biały | 40cm | 1 |
| 2 | 1 | piłka | biały | 40cm | 1 |
+----+---------+--------+--------+---------+-------+
2 rows in set (0.00 sec)

mysql> truncate table koszyk;
Query OK, 0 rows affected (0.07 sec)

mysql> alter table koszyk
-> add constraint unique( user_id, nazwa, kolor, rozmiar );
Query OK, 0 rows affected (0.17 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> INSERT INTO koszyk (user_id, nazwa, kolor, rozmiar) VALUES('1', 'piłka', 'biały', '40cm');
Query OK, 1 row affected (0.06 sec)

mysql> INSERT INTO koszyk (user_id, nazwa, kolor, rozmiar) VALUES('1', 'piłka', 'biały', '40cm');
ERROR 1062 (23000): Duplicate entry '1-piłka-biały-40cm' for key 'user_id'

mysql> select * from koszyk;
+----+---------+--------+--------+---------+-------+
| id | user_id | nazwa | kolor | rozmiar | ilosc |
+----+---------+--------+--------+---------+-------+
| 1 | 1 | piłka | biały | 40cm | 1 |
+----+---------+--------+--------+---------+-------+
1 row in set (0.00 sec)

mysql> INSERT INTO koszyk (user_id, nazwa, kolor, rozmiar) VALUES('1', 'piłka', 'biały', '40cm')
-> ON DUPLICATE KEY UPDATE ilosc = ilosc + 1;
Query OK, 2 rows affected (0.09 sec)

mysql> select * from koszyk;
+----+---------+--------+--------+---------+-------+
| id | user_id | nazwa | kolor | rozmiar | ilosc |
+----+---------+--------+--------+---------+-------+
| 1 | 1 | piłka | biały | 40cm | 2 |
+----+---------+--------+--------+---------+-------+
1 row in set (0.00 sec)

[/code]

1

Dzięki wielkie, już wiem gdzie tkwił błąd. Ja ustawiłem unique na próbę dla jednego pola, a powinno być dla wielu by to poprawnie działało.

0

Po licznych zapytaniach na forach i moich testach
i próbach nad zagadnieniem wsadzania nowych danych
do tablicy MYSQL (insert) wraz z update istniejących
rekordów przy pomocy jednego wywołania doszedłem do
następującego wzorca i konkluzji .
Proponuje zastosowanie składni :

1- sekcja INSERT INTO QSOS_AWARDS ( CALL , QSO_DATE , TIME_ON
, BAND , SUM_STRING )
2- sekcja SELECT T_CALL , T_QSO_DATE , T_ TIME_ON , T_BAND ,
T_SUM_STRING from T_QSOS_AWARDS
3-cia sekcja ON DULICATE UPDATE CALL= T_CALL ,
QSO_DATE = T_QSO_DATE ,
TIME_ON = T_ TIME_ON ,
BAND = T_BAND ,
SUM_STRING = T_SUM_STRING

Uwagi dodatkowe :

  1. Wszystkie pola są typu string u mnie - chociaż nie jest to wymagane
  2. Ilość pól we wszystkich sekcjach musi być identyczna - inaczej
    MYSQL zgłasza że Count fields in not this same .
  3. Jedno pole SUM_STRING u musi być kluczem typu PRIMARY -
    ale nie może to być pole AUTO_INCREMENT .
    Nie wystarcza by było to pole typu UNIQUE .
    U mnie było to pole które było po prostu sumą stringową pól CALL ,
    QSO_DATE , TIME_ON , BAND
    co zapewniało że to pole było unikalne i nie tworzyły się
    duplikaty .
    4 . Pole T_SUM_STRING powinno być co najmniej typu UNIQUE .
    Nie robiłem prób z polem typu PRIMARY ale sądzę że też
    by to zadziałało .
  4. W 3-ciej sekcji proszę zwrócić uwage na składnię. Wiele postów
    zaleca tutaj zastosowanie składni CALL= VALUES(T_CALL) lub
    CALL= VALUES(T_QSOS_AWARDS.T_CALL) .
    Nie jest to niestety poprawne - gdyż zawsze w tym
    przypadku otrzymywałem komunikat - Column T_CALL lub
    T_QSOS_AWARDS.T_CALL not found .
    Z praktyki mojej wynika że słowo VALUS () można tylko wykorzystwać
    jeśli w środku podamy konkretne wartości np VALUES(1,'ab' , 3)
    lub VALUES ( SUM_STRING + 'ab') - ale pola te mogą pochodzić tylko z
    1-szej sekcji .
  5. U mnie tablica T_QSOS_AWARDS to była tablica TEMPORARY , a więc
    przechowywana w pamięci ( co znacznie przyspieszyło) i
    stworzona poleceniem :
    CREATE TEMPORARY TABLE if not exists T_QSOS_AWARDS ( T_CALL ,
    T_QSO_DATE , T_ TIME_ON , T_BAND , T_SUM_STRING)
    Oczywiscie w liście pól były jeszcze podane typy pól zgodnie
    ze składnią MYSQL .
  6. Dla tablicy T_QSOS_AWARDS był stworzony dodatkowo index typu
    UNIQUE poleceniem
    ADOCommCreaInsert.CommandText :='CREATE UNIQUE INDEX '
    + 'IDX_T_SUM_STRING'
    + ' ON TEMP_QSOS_AWARDS
    ('T_SUM_STRING' )';
    ADOCommCreaInsert.Execute;
    8 . Tablica QSOS_AWARDS może zawierać jeszcze inne pola -
    ale wyżej musimy podać tylko te pola które insertujemy
    lub podajemy upadate . Ta liczba tych pól musi być
    ta sama .
    9 . Można zastosować jeszcze pole Identyfikator np ID_QSO indeksowane -
    który można ustawić na AUTO_INCREMENT .
    Takiemu polu nigdy nie nadajemy wartości .
    Pozdrawiam Wszystkich - SP9AUV

1 użytkowników online, w tym zalogowanych: 0, gości: 1