Обычной операцией является вставка новой строки, если ее не существует, или обновление существующей строки. К сожалению, синтаксис операторов SQL вставки и обновления совершенно другой: вставка принимает список столбцов, за которым следует соответствующий список значений, а обновление принимает список пар столбец=значение. Оператор MySQL «вставить... при обновлении дублирующего ключа» (его оператор upsert) не решает эту проблему, поскольку он по-прежнему требует полных списков столбцов/значений вставки, за которыми следует полный список столбцов/значений обновления. [ОБНОВЛЕНИЕ: Комментарий Wrikken ниже указывает на то, что два оператора могут использовать синтаксис столбец = значение, но другие проблемы остаются.]
С этой проблемой связано то, что если вы используете триггеры для проверки данных (как это делаю я), вам нужны два триггера (перед вставкой и перед обновлением), и, поскольку они должны использовать квалификатор «новый», вы нужно либо написать код проверки дважды, по одному разу для каждого триггера, либо поместить его в процедуру. Если вы используете процедуру, вы должны передавать каждый столбец как отдельный параметр, потому что процедура не может использовать «новый», что является большим количеством потенциально подверженных ошибкам ввода, если у вас много столбцов. Каждый столбец должен иметь свой тип в операторе создания таблицы, а затем во второй раз в определении процедуры проверки. Одна маленькая ошибка, и вы создали незаметную, трудно обнаруживаемую ошибку. Мне не нравится любой подход, предполагающий двойное кодирование одного и того же. (Это эквивалент ненормализации.)
Размышляя об этой проблеме вставки/обновления, я обдумывал следующую идею и хотел бы получить отзывы, особенно если кто-то действительно пробовал это:
Используйте вставку только для строки-заполнителя, содержащей только минимальный объем данных, и для получения или установки первичного ключа. Затем поместите все введенные пользователем данные в оператор обновления. Теперь вам не нужно «вставлять... при обновлении дубликата ключа», как это делает обычное обновление. Также проверять данные нужно только на триггере перед обновлением, так как на вставке проверять нечего. (Все введенные пользователем данные из формы ввода обрабатываются обновлением, а не вставкой.)
Главным недостатком этого метода, конечно же, является то, что есть две операции для новой строки: вставка с последующим обновлением вместо вставки. Но это не может быть фактором, потому что:
Вставки могут быть относительно редкими. Например, в приложении для оценивания учащихся, которое я создал несколько лет назад для школьного округа Ричардсон (Техас), каждый год добавлялось всего около пары тысяч учащихся, в то время как обновления вносились десятками тысяч, так как учителя использовали системы в течение всего учебного года.
В нескольких других системах, которые я построил, производительность не имела значения. Например, в текущей системе, над которой я работаю, всего два или три человека обновляют базу данных всего несколько часов в неделю. Нагрузка настолько мала, что накладные расходы, вызванные двумя операциями (вставка + обновление), когда достаточно только одной, незначительны. (Помните, это только для новых строк.)
Итак, кто-нибудь на самом деле пробовал это: вставить только для создания минималистской строки-заполнителя и использовать обновление для всех обновлений данных, предоставленных пользователем?
INSERT INTO tablename SET col1=1, col2=2
... и т. д. допустимы? И мне еще предстоит найти написание запроса только один раз громоздким... - person Wrikken   schedule 12.12.2012