На дубликате ключа ничего не делай

14

Я вставляю в следующую таблицу, используя LuaSQL с PtokaX API.

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;

Теперь моя проблема в том, что когда пользователь (представленный nick) пытается вставить тот же запрос снова, UNIQUEиндекс проверяется, и скрипт возвращает ложное значение. Это приводит к сбою моего сценария, и я должен перезапустить сценарий.

Есть ли что-то, что я могу сделать в INSERT ... ON DUPLICATE KEYкоманде, чтобы она ничего не делала или, по крайней мере, НЕ возвращала ошибку в случае DUPLICATE KEY?

В противном случае мне нужно будет обновить datedполе с новым DATETIMEзначением.

hjpotter92
источник

Ответы:

23

Три способа Либо IGNOREповторяющиеся ошибки:

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

или попробуйте выполнить избыточное обновление при наличии дубликата:

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

или проверьте наличие дубликатов перед вставкой:

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!') ) ;

Разница между 3-м способом и первыми двумя заключается в том, что при наличии дубликатов idприращение не будет увеличиваться. С помощью INSERT IGNOREи INSERT ... ON DUPLICATE KEYон будет автоматически увеличен, и поскольку вставка не будет выполнена, у вас будут пробелы в значениях id.

Я также должен добавить, что ваши скрипты должны всегда проверять наличие ошибок и не вызывать их, когда они есть. Любой запрос или утверждение может быть неудачным и время от времени возвращать ошибку по разным причинам. Приведенные выше уловки спасут вас только от одной ошибки.

ypercubeᵀᴹ
источник
1

Варианты отличные, я просто знаю четвертый. Вы можете создать процедуру следующим образом (MySQL 5.5 или выше).

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;;
billmask
источник
Хорошо, я не использовал MySQL в последнее время, поэтому я не знал этого. Можете ли вы обновить и уточнить: что произойдет, если возникнут другие (не повторяющиеся нарушения ключа) ошибки? И как это работает точно (что означает 1062)? Нужно ли, чтобы запрос был одиночной вставкой или он может работать со вставкой нескольких строк?
ypercubeᵀᴹ
1062 - Дублированный ряд. Только эта ошибка SQL вызывает: SET v_dups = v_dups + 1;
Billmask