Na duplikacie klucza nie rób nic

14

Wstawiam do poniższej tabeli za pomocą LuaSQL z API PtokaX.

CREATE TABLE `requests` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `ctg` VARCHAR(15) NOT NULL,
    `msg` VARCHAR(250) NOT NULL,
    `nick` VARCHAR(32) NOT NULL,
    `filled` ENUM('Y','N') NOT NULL DEFAULT 'N',
    `dated` DATETIME NOT NULL,
    `filldate` DATETIME NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    UNIQUE INDEX `nick_msg` (`nick`, `msg`),
    UNIQUE INDEX `ctg_msg` (`ctg`, `msg`)
)
COMMENT='Requests from users in any of the categories.'
COLLATE='utf8_general_ci'
ENGINE=MyISAM;

Mój problem polega na tym, że gdy użytkownik (reprezentowany przez nick) próbuje ponownie wstawić to samo żądanie, UNIQUEindeks jest sprawdzany, a skrypt zwraca wartość false. Powoduje to awarię skryptu i muszę go ponownie uruchomić.

Czy jest coś, co mogę zrobić w INSERT ... ON DUPLICATE KEYpoleceniu, aby nic nie robiło, a przynajmniej NIE zwraca błędu w przypadku DUPLICATE KEY?

W przeciwnym razie musiałbym przejść do aktualizacji mojego datedpola o nową DATETIMEwartość.

hjpotter92
źródło

Odpowiedzi:

23

Trzy drogi. Powielone IGNOREbłędy:

INSERT IGNORE 
  ... ;                   -- without ON DUPLICATE KEY

lub spróbuj wykonać redundantną aktualizację, gdy istnieje duplikat:

INSERT 
  ... 
ON DUPLICATE KEY UPDATE
  id = id ;

lub sprawdź duplikaty przed wstawieniem:

INSERT INTO requests
  (id, ctg, msg, nick, filled, dated, filldate)
SELECT
  NULL, 'urgent', 'Help!', 'Hermione', 'Y', NOW(), NOW()
FROM
  dual
WHERE NOT EXISTS
      ( SELECT *  FROM requests  WHERE (nick, msg) = ('Hermione', 'Help!') )
  AND NOT EXISTS
      ( SELECT *  FROM requests  WHERE (ctg, msg) = ('urgent', 'Help!') ) ;

Różnica między trzecim sposobem a pierwszymi dwoma polega na tym, że gdy są duplikaty, idnie będą one zwiększane. Przy pomocy INSERT IGNOREi INSERT ... ON DUPLICATE KEY, będzie on automatycznie zwiększany, a ponieważ wstawianie nie zostanie wykonane, będziesz mieć luki w wartościach id.

Powinienem również dodać, że skrypty i tak zawsze powinny sprawdzać, czy nie występują błędy, i nie kończyć się niepowodzeniem, gdy taki istnieje. Każde zapytanie lub instrukcja może się nie powieść i od czasu do czasu zwrócić błąd z różnych powodów. Powyższe wskazówki pozwolą ci uchronić się od jednego rodzaju błędu.

ypercubeᵀᴹ
źródło
1

Opcje są świetne, po prostu znam czwarty. Możesz utworzyć następującą procedurę (MySQL 5.5 lub nowszy).

DELIMITER ;;
CREATE PRODECURE...
...necessary parameters...
BEGIN

DECLARE v_dups BIGINT;
DECLARE CONTINUE HANDLER FOR 1062 SET v_dups = v_dups + 1;

-- RUN SIMPLE INSERT, IF IT TAKES DUPLICATE KEY NOTHING HAPPENS
END;;
maska
źródło
Fajnie, ostatnio nie korzystałem z MySQL, więc nie wiedziałem o tym. Czy możesz zaktualizować i opracować: co się stanie, jeśli wystąpią inne błędy (nie powielone naruszenia zasad)? I jak to dokładnie działa (co oznacza skrót 1062)? Czy zapytanie musi być pojedynczą wstawką, czy może współpracować z wstawieniem wielu wierszy?
ypercubeᵀᴹ
1062 to zduplikowany wiersz. Tylko ten błąd SQL powoduje: SET v_dups = v_dups + 1;
billmask