Я знаю, что вы можете вставить сразу несколько строк, есть ли способ обновить сразу несколько строк (например, в одном запросе) в MySQL?
Редактировать: Например, у меня есть следующие
Name id Col1 Col2
Row1 1 6 1
Row2 2 2 3
Row3 3 9 5
Row4 4 16 8
Я хочу объединить все следующие обновления в один запрос
UPDATE table SET Col1 = 1 WHERE id = 1;
UPDATE table SET Col1 = 2 WHERE id = 2;
UPDATE table SET Col2 = 3 WHERE id = 3;
UPDATE table SET Col1 = 10 WHERE id = 4;
UPDATE table SET Col2 = 12 WHERE id = 4;






UPDATE table1, table2 SET table1.col1='value', table2.col1='value' WHERE table1.col3='567' AND table2.col6='567'
Это должно сработать для тебя.
В руководство по MySQL есть ссылка на несколько таблиц.
Следующее обновит все строки в одной таблице
Update Table Set
Column1 = 'New Value'
Следующий обновит все строки, в которых значение Column2 больше 5.
Update Table Set
Column1 = 'New Value'
Where
Column2 > 5
Есть все примеры Unkwntech обновления более чем одной таблицы
UPDATE table1, table2 SET
table1.col1 = 'value',
table2.col1 = 'value'
WHERE
table1.col3 = '567'
AND table2.col6='567'
Вы также можете быть заинтересованы в использовании объединений для обновлений, что тоже возможно.
Update someTable Set someValue = 4 From someTable s Inner Join anotherTable a on s.id = a.id Where a.id = 4
-- Only updates someValue in someTable who has a foreign key on anotherTable with a value of 4.
Обновлено: если обновляемые значения не поступают откуда-то еще в базе данных, вам необходимо выполнить несколько запросов на обновление.
UPDATE tableName SET col1='000' WHERE id='3' OR id='5'
Это должно достичь того, что вы ищете. Просто добавьте еще идентификаторы. Я это проверил.
Да, это возможно - вы можете использовать INSERT ... ON DUPLICATE KEY UPDATE.
Используя ваш пример:
INSERT INTO table (id,Col1,Col2) VALUES (1,1,1),(2,2,3),(3,9,3),(4,10,12)
ON DUPLICATE KEY UPDATE Col1=VALUES(Col1),Col2=VALUES(Col2);
так что, если это похоже на вставку в пропустить null или пропустить пустой при дублировании обновления ... тогда это было бы хорошо.
Примечание: этот ответ также предполагает, что идентификатор является первичным ключом.
Значит, сначала нужно выбрать значения? Не похоже на оптимизированное обновление. Второй ответ кажется более надежным.
@JayapalChandran, вы должны использовать INSERT IGNORE вместе с ON DUPLICATE KEY UPDATE. dev.mysql.com/doc/refman/5.5/en/insert.html
@HaralanDobrev Использование INSERT IGNORE по-прежнему вставляет недублированные записи. чего Джаяпал хотел избежать. INSERT IGNORE просто превращает любые ошибки в предупреждение :( stackoverflow.com/questions/548541/…
@ JM4: этот ответ предполагает, что идентификатор является первичным ключом ИЛИ уникальным ключом (но, конечно, наиболее вероятно, что первичный ключ)
Этот ответ предполагает, что идентификатор является уникальным ключом (может быть первичным, как говорили другие), но, что более важно, он предполагает, что других уникальных ключей нет. Если они есть, это может помешать работе.
Вы также должны позаботиться о своем приращении (если он существует), он ТАКЖЕ увеличится, если вы вставите O.D.K.U. даже если новая запись не вставлена! Если вы будете делать много обновлений таким образом, ваш автоинкремент так скоро переполнится!
Мое решение проблемы только обновления, но не вставки новых записей состоит в том, чтобы иметь поле в части вставки, которое отсутствует в части обновления, и после того, как я удалю все записи, которые имеют значения в этом поле. пример: вставить в tbl (идентификатор, заголовок, обходной путь) значения ('realId', 'realTitle', 'Эта строка должна умереть!') при обновлении повторяющегося ключа id = values (id), title = values (title); удалить из таблицы, где обходной путь = 'Эта строка должна умереть!'
@ user2602807 Только что протестировал, и похоже, что это не так
Еще одно предостережение: любые дополнительные столбцы, объявленные как NOT NULL без значения по умолчанию, должны быть включены во вставку. Однако их можно игнорировать в обновлении, поэтому вы можете использовать фиктивные значения.
Я получаю "синтаксическую ошибку 1064". Формат для DUPLICATE KEY UPDATE Col1=VALUES(Col1) colName1 = VALUES (colName1)? т.е. где `будет окружать colName1
Обратите внимание, что я также пытался без `окружающего colName1 ... в настоящее время тестирую, чтобы убедиться, что это не данные конкретной строки, вызывающие ошибку
Я разместил вопрос по проблеме: stackoverflow.com/questions/48490630/…
Это не идеальное решение. Вот намного лучше stackoverflow.com/questions/25674737/…
user2602807 @Dakusan, вы оба правы, в зависимости от двух вещей: 1. myisam не увеличивает автоинкремент. 2. innodb увеличивается по умолчанию, вы можете предотвратить это, изменив режим автоинкремента на классический.
@ Омер Ан - Да. Я обновил свой ответ ниже этой информацией некоторое время назад. К сожалению, переполнение стека не позволяет мне редактировать мой вышеупомянутый комментарий.
Поскольку у вас есть динамические значения, вам нужно использовать IF или CASE для обновляемых столбцов. Это выглядит некрасиво, но должно работать.
Используя ваш пример, вы могли бы сделать это так:
UPDATE table SET Col1 = CASE id
WHEN 1 THEN 1
WHEN 2 THEN 2
WHEN 4 THEN 10
ELSE Col1
END,
Col2 = CASE id
WHEN 3 THEN 3
WHEN 4 THEN 12
ELSE Col2
END
WHERE id IN (1, 2, 3, 4);
может быть не так красиво писать для динамического обновления, но интересно посмотреть на функционал корпуса ...
@ user2536953, может быть неплохо и для динамического обновления. Например, я использовал это решение в цикле на php: $commandTxt = 'UPDATE operations SET chunk_finished = CASE id '; foreach ($blockOperationChecked as $operationID => $operationChecked) $commandTxt .= " WHEN $operationID THEN $operationChecked "; $commandTxt .= 'ELSE id END WHERE id IN ('.implode(', ', array_keys(blockOperationChecked )).');';
Существует параметр, который вы можете изменить, называемый «multi statement», который отключает «механизм безопасности» MySQL, реализованный для предотвращения (более чем одной) команды внедрения. Типичный для «блестящей» реализации MySQL, он также мешает пользователю выполнять эффективные запросы.
Здесь (http://dev.mysql.com/doc/refman/5.1/en/mysql-set-server-option.html) - некоторая информация о реализации этой настройки на языке C.
Если вы используете PHP, вы можете использовать mysqli для выполнения нескольких операторов (я думаю, что php уже некоторое время поставляется с mysqli)
$con = new mysqli('localhost','user1','password','my_database');
$query = "Update MyTable SET col1='some value' WHERE id=1 LIMIT 1;";
$query .= "UPDATE MyTable SET col1='other value' WHERE id=2 LIMIT 1;";
//etc
$con->multi_query($query);
$con->close();
Надеюсь, это поможет.
Это то же самое, что и отправка запросов по отдельности. Единственное отличие состоит в том, что вы отправляете все это в одном сетевом пакете, но ОБНОВЛЕНИЯ по-прежнему будут обрабатываться как отдельные запросы. Лучше заключить их в одну транзакцию, тогда изменения сразу будут зафиксированы в таблице.
Как их завернуть в одну транзакцию? Покажи нам, пожалуйста.
@TomeeNS Используйте mysqli::begin_transaction(..) перед отправкой запроса и mysql::commit(..) после. Или используйте START TRANSACTION в качестве первого и COMMIT в качестве последнего оператора в самом запросе.
Используйте временную таблицу
// Reorder items
function update_items_tempdb(&$items)
{
shuffle($items);
$table_name = uniqid('tmp_test_');
$sql = "CREATE TEMPORARY TABLE `$table_name` ("
." `id` int(10) unsigned NOT NULL AUTO_INCREMENT"
.", `position` int(10) unsigned NOT NULL"
.", PRIMARY KEY (`id`)"
.") ENGINE = MEMORY";
query($sql);
$i = 0;
$sql = '';
foreach ($items as &$item)
{
$item->position = $i++;
$sql .= ($sql ? ', ' : '')."({$item->id}, {$item->position})";
}
if ($sql)
{
query("INSERT INTO `$table_name` (id, position) VALUES $sql");
$sql = "UPDATE `test`, `$table_name` SET `test`.position = `$table_name`.position"
." WHERE `$table_name`.id = `test`.id";
query($sql);
}
query("DROP TABLE `$table_name`");
}
Вы можете использовать псевдоним той же таблицы, чтобы указать идентификатор, который вы хотите вставить (если вы выполняете построчное обновление:
UPDATE table1 tab1, table1 tab2 -- alias references the same table
SET
col1 = 1
,col2 = 2
. . .
WHERE
tab1.id = tab2.id;
Кроме того, должно казаться очевидным, что вы также можете обновлять данные из других таблиц. В этом случае обновление дублируется как оператор «SELECT», предоставляющий вам данные из указанной вами таблицы. Вы явно указываете в своем запросе значения обновления, поэтому вторая таблица не затронута.
Вопрос старый, но я хотел бы расширить тему другим ответом.
Я хочу сказать, что самый простой способ добиться этого - просто обернуть транзакцией несколько запросов. Принятый ответ INSERT ... ON DUPLICATE KEY UPDATE - хороший прием, но следует помнить о его недостатках и ограничениях:
"Field 'fieldname' doesn't have a default value" MySQL, даже если вы вообще не вставляете ни одной строки. У вас возникнут проблемы, если вы решите быть строгим и превратите предупреждения mysql в исключения времени выполнения в своем приложении.Я провел несколько тестов производительности для трех из предложенных вариантов, включая вариант INSERT ... ON DUPLICATE KEY UPDATE, вариант с предложением «case / when / then» и наивный подход с транзакцией. Вы можете получить код Python и результаты здесь. Общий вывод заключается в том, что вариант с оператором case оказывается в два раза быстрее, чем два других варианта, но для него довольно сложно написать правильный и безопасный для инъекций код, поэтому я лично придерживаюсь самого простого подхода: использования транзакций.
Редактировать: Результаты Дакусан доказывают, что мои оценки производительности не совсем верны. Пожалуйста, см. этот ответ для другого, более детального исследования.
Использование транзакций, очень приятный (и простой) совет!
Что делать, если мои таблицы не относятся к типу InnoDB?
Может ли кто-нибудь предоставить ссылку на то, как это выглядит? И / или код для безопасного для инъекций кода для варианта с оператором case?
Я считаю, что информация о скорости в этом посте неверна. Я написал об этом в посте ниже. stackoverflow.com/questions/3432/multiple-updates-in-mysql/…
@ Дакусан, отличный ответ. Большое спасибо за расширение, комментирование и исправление моих результатов.
UPDATE `your_table` SET
`something` = IF(`id` = "1","new_value1",`something`), `smth2` = IF(`id` = "1", "nv1",`smth2`),
`something` = IF(`id` = "2","new_value2",`something`), `smth2` = IF(`id` = "2", "nv2",`smth2`),
`something` = IF(`id` = "4","new_value3",`something`), `smth2` = IF(`id` = "4", "nv3",`smth2`),
`something` = IF(`id` = "6","new_value4",`something`), `smth2` = IF(`id` = "6", "nv4",`smth2`),
`something` = IF(`id` = "3","new_value5",`something`), `smth2` = IF(`id` = "3", "nv5",`smth2`),
`something` = IF(`id` = "5","new_value6",`something`), `smth2` = IF(`id` = "5", "nv6",`smth2`)
// Вы просто создаете его на php, например
$q = 'UPDATE `your_table` SET ';
foreach($data as $dat){
$q .= '
`something` = IF(`id` = "'.$dat->id.'","'.$dat->value.'",`something`),
`smth2` = IF(`id` = "'.$dat->id.'", "'.$dat->value2.'",`smth2`),';
}
$q = substr($q,0,-1);
Таким образом, вы можете обновить таблицу отверстий одним запросом
Я не голосовал против, но я думаю, что возражение заключается в том, чтобы делать набор, когда он не нужен (и вы все еще делаете это, когда вы устанавливаете something на something)
Не уверен, почему еще не упоминается еще один полезный вариант:
UPDATE my_table m
JOIN (
SELECT 1 as id, 10 as _col1, 20 as _col2
UNION ALL
SELECT 2, 5, 10
UNION ALL
SELECT 3, 15, 30
) vals ON m.id = vals.id
SET col1 = _col1, col2 = _col2;
Это лучшее. Особенно, если вы извлекаете значения для обновления из другого SQL-запроса, как это делал я.
Это было отличным вариантом для обновления таблицы с огромным количеством столбцов. Я, вероятно, буду часто использовать этот запрос в будущем. Спасибо!
Я пробовал этот тип запроса. Но когда записи достигают 30к, пограничный сервер останавливается. Есть ли другое решение?
Выглядит отлично. Я попытаюсь объединить это с предложением WHERE, в котором первичные ключи не обновляются, а используются для идентификации столбцов, которые нужно изменить.
@BhavinChauhan Пробовали ли вы использовать временную таблицу вместо join-select, чтобы обойти проблему?
Я обнаружил тот же подход, когда пытался избежать [явных] временных таблиц. @BhavinChauhan, вам всегда следует избегать слишком длинных строк запроса. Вместо этого смешайте их. По моим (ограниченным) измерениям 2500 строк были идеальным размером партии.
Да .. это возможно с помощью инструкции sql INSERT ON DUPLICATE KEY UPDATE .. синтаксис: INSERT INTO имя_таблицы (a, b, c) VALUES (1,2,3), (4,5,6) ПРИ ДВОЙНОМ ОБНОВЛЕНИИ КЛЮЧА a = ЗНАЧЕНИЯ (a), b = ЗНАЧЕНИЯ (b), c = ЗНАЧЕНИЯ (c)
использовать
REPLACE INTO`table` VALUES (`id`,`col1`,`col2`) VALUES
(1,6,1),(2,2,3),(3,9,5),(4,16,8);
Пожалуйста, обрати внимание:
Все следующее применимо к InnoDB.
Я чувствую, что важно знать скорость трех разных методов.
Есть 3 метода:
Я только что проверил это, и метод INSERT был для меня 6,7x быстрее, чем метод TRANSACTION. Я пробовал набор из 3000 и 30 000 строк.
Метод TRANSACTION по-прежнему должен запускать каждый индивидуальный запрос, что требует времени, хотя он пакетирует результаты в памяти или в чем-то еще во время выполнения. Метод TRANSACTION также довольно затратен как для репликации, так и для журналов запросов.
Хуже того, метод CASE был на 41,1x медленнее, чем метод INSERT с 30 000 записей (в 6,1 раза медленнее, чем TRANSACTION). И 75x медленнее в MyISAM. Методы INSERT и CASE оказались безубыточными при ~ 1000 записях. Даже при 100 записях метод CASE ОЧЕНЬ быстрее.
В общем, я считаю, что метод INSERT является лучшим и самым простым в использовании. Запросы меньше по размеру и легче читаются, и для них требуется только 1 запрос действия. Это относится как к InnoDB, так и к MyISAM.
Бонус:
Решением проблемы INSERT с полем, отличным от поля по умолчанию, является временное отключение соответствующих режимов SQL: SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES",""). Обязательно сначала сохраните sql_mode, если вы планируете вернуть его обратно.
Что касается других комментариев, которые я видел, в которых говорится, что auto_increment увеличивается с использованием метода INSERT, похоже, что это имеет место в InnoDB, но не в MyISAM.
Код для запуска тестов следующий. Он также выводит файлы .SQL для устранения накладных расходов интерпретатора php.
<?php
//Variables
$NumRows=30000;
//These 2 functions need to be filled in
function InitSQL()
{
}
function RunSQLQuery($Q)
{
}
//Run the 3 tests
InitSQL();
for($i=0;$i<3;$i++)
RunTest($i, $NumRows);
function RunTest($TestNum, $NumRows)
{
$TheQueries=Array();
$DoQuery=function($Query) use (&$TheQueries)
{
RunSQLQuery($Query);
$TheQueries[]=$Query;
};
$TableName='Test';
$DoQuery('DROP TABLE IF EXISTS '.$TableName);
$DoQuery('CREATE TABLE '.$TableName.' (i1 int NOT NULL AUTO_INCREMENT, i2 int NOT NULL, primary key (i1)) ENGINE=InnoDB');
$DoQuery('INSERT INTO '.$TableName.' (i2) VALUES ('.implode('), (', range(2, $NumRows+1)).')');
if ($TestNum==0)
{
$TestName='Transaction';
$Start=microtime(true);
$DoQuery('START TRANSACTION');
for($i=1;$i<=$NumRows;$i++)
$DoQuery('UPDATE '.$TableName.' SET i2='.(($i+5)*1000).' WHERE i1='.$i);
$DoQuery('COMMIT');
}
if ($TestNum==1)
{
$TestName='Insert';
$Query=Array();
for($i=1;$i<=$NumRows;$i++)
$Query[]=sprintf("(%d,%d)", $i, (($i+5)*1000));
$Start=microtime(true);
$DoQuery('INSERT INTO '.$TableName.' VALUES '.implode(', ', $Query).' ON DUPLICATE KEY UPDATE i2=VALUES(i2)');
}
if ($TestNum==2)
{
$TestName='Case';
$Query=Array();
for($i=1;$i<=$NumRows;$i++)
$Query[]=sprintf('WHEN %d THEN %d', $i, (($i+5)*1000));
$Start=microtime(true);
$DoQuery("UPDATE $TableName SET i2=CASE i1\n".implode("\n", $Query)."\nEND\nWHERE i1 IN (".implode(',', range(1, $NumRows)).')');
}
print "$TestName: ".(microtime(true)-$Start)."<br>\n";
file_put_contents("./$TestName.sql", implode(";\n", $TheQueries).';');
}
Вы делаете здесь работу ГОСПОДА;) Очень признателен.
Тестируя некоторую производительность между GoLang и PHP, используя 40k строк на MariaDB, я получал 2 секунды на PHP и более 6 секунд на golang .... Ну, мне всегда говорили, что GoLang будет работать быстрее, чем PHP !!! Итак, я начинаю задаваться вопросом, как улучшить производительность ... Используя INSERT ... ON DUPLICATE KEY UPDATE ... У меня 0,74 секунды на Golang и 0,86 секунды на PHP !!!!
Суть моего кода в том, чтобы ограничить результаты по времени строго операторами SQL, а не кодом для языка или библиотек. GoLang и PHP - это два совершенно разных языка, предназначенных для совершенно разных вещей. PHP предназначен для одноразовой среды сценариев в одном потоке с в основном ограниченной и пассивной сборкой мусора. GoLang предназначен для долго работающих скомпилированных приложений с агрессивной сборкой мусора и многопоточностью в качестве одной из основных функций языка. Они едва ли могли быть более разными с точки зрения языковой функциональности и разума. [Продолжение]
Поэтому при выполнении тестов убедитесь, что измерения скорости строго ограничены вызовами функции «Запрос» для оператора SQL. Сравнение и оптимизация других частей исходного кода, которые не являются строго вызовом запроса, похожи на сравнение яблок и апельсинов. Если вы ограничите свои результаты этим (предварительно скомпилированные и готовые к работе строки), то результаты должны быть очень похожими. Любые различия на этом этапе являются ошибкой библиотеки SQL языка, а не обязательно самого языка. На мой взгляд, решение INSERT ON DUPLICATE было и всегда будет лучшим вариантом. [Продолжение]
Что касается вашего комментария о том, что GoLang работает быстрее, это невероятно широкое утверждение, которое не принимает во внимание ни одно из множества предостережений или нюансов этих языков и их дизайна. Java - это интерпретируемый язык, но 15 лет назад я обнаружил, что он фактически может почти соответствовать (а может быть, даже иногда превосходить) C по скорости в определенных сценариях. А C - это компилируемый язык и самый распространенный из системных языков нижнего уровня, помимо ассемблера. Мне очень нравится то, что делает GoLang, и он определенно обладает мощностью и гибкостью, чтобы стать одной из наиболее распространенных и оптимизированных систем [Продолжение]
языки приложений. Он компилируется намного быстрее по сравнению с C / C++. Он имеет строгий синтаксис, который помогает устранить войны за форматирование кода (хотя лично мне это не нравится). Его сборка мусора является революционной, с обычными запусками GC, которые занимают МИКРОСЕКУНД. И простота его формата канала IPC почти не имеет себе равных. Это довольно революционно, для чего он построен. Например, запуск пустого цикла for и сравнение скоростей между языками мало что вам скажет. Хорошо, я уже набрал слишком много и не позволю этому столкнуться с другим комментарием.
Почему никто не упоминает несколько операторов в одном запросе?
В php вы используете метод multi_query экземпляра mysqli.
MySQL optionally allows having multiple statements in one statement string. Sending multiple statements at once reduces client-server round trips but requires special handling.
Вот результат по сравнению с другими 3 методами в обновлении 30,000 raw. Код можно найти здесь, который основан на ответе @Dakusan
Транзакция: 5.5194580554962
Вставка: 0.20669293403625
Корпус: 16.474853992462
Мульти: 0,0412278175354
Как видите, запрос с несколькими операторами более эффективен, чем самый высокий ответ.
Если вы получили такое сообщение об ошибке:
PHP Warning: Error while sending SET_OPTION packet
Возможно, вам потребуется увеличить max_allowed_packet в конфигурационном файле mysql, который на моем компьютере является /etc/mysql/my.cnf, а затем перезапустить mysqld.
Все нижеприведенные сравнения сравниваются с тестом INSERT. Я просто провел тест в тех же условиях, и без транзакций он был медленнее на 145x на 300 строках и 753x на 3000 строках. Изначально я начал с 30 000 строк, но пошел приготовить себе обед, а потом вернулся, и он все еще продолжался. Это имеет смысл, поскольку выполнение отдельных запросов и сброс каждого из них в базу данных по отдельности было бы смехотворно дорогим. Особенно с репликацией. Однако включение транзакций имеет большое значение. При 3000 строках потребовалось больше В 1,5 раза, а при 30 000 строках - В 2,34 раза. [продолжение]
Но вы были правы, что это было быстро (с транзакциями). И для 3000, и для 30 000 строк это было быстрее, чем все, кроме метода INSERT. Нет абсолютно никакого способа получить лучшие результаты от выполнения 1 запроса, чем 30 000 запросов, даже если они объединены в специальный вызов MySQL API. Выполняя всего 300 строк, он был НАМНОГО быстрее, чем все другие методы (к моему удивлению), который следует примерно по той же кривой графика, что и метод CASE. Это можно объяснить двумя способами. Во-первых, метод INSERT по существу всегда вставляет 2 строки из-за «ON DUPLICATE KEY [продолжение]
UPDATE "вызывает как" INSERT ", так и" UPDATE ". Другое дело, что в процессоре SQL меньше работы для редактирования только одной строки за раз из-за поиска по индексу. Я не уверен, как вы получили другие результаты, чем я, но ваш дополнительный тест выглядит надежным. На самом деле я даже не уверен, как репликация будет обрабатывать этот вызов. Это также будет работать только для выполнения вызовов UPDATE. Вызовы вставки ВСЕГДА будут самыми быстрыми с одним запросом INSERT.
Я делал 300 ОБНОВЛЕНИЙ за раз для таблицы, чтобы исправить ошибку в цикле for, который занял 41 секунду. Помещение тех же запросов UPDATE в один $mysqli->multi_query($sql) заняло «0» секунд. Однако последующие запросы не удались, из-за чего я выделил эту «программу».
Спасибо. Смог обновить около 5 тыс. Строк (больше не тестировал) за минуту, используя несколько запросов. Если кто-то ищет решение PDO: stackoverflow.com/questions/6346674/…
А теперь легкий путь
update my_table m, -- let create a temp table with populated values
(select 1 as id, 20 as value union -- this part will be generated
select 2 as id, 30 as value union -- using a backend code
-- for loop
select N as id, X as value
) t
set m.value = t.value where t.id=m.id -- now update by join - quick
Я взял ответ от @newtover и расширил его, используя новую функцию json_table в MySql 8. Это позволяет вам создать хранимую процедуру для обработки рабочей нагрузки, а не создавать собственный текст SQL в коде:
drop table if exists `test`;
create table `test` (
`Id` int,
`Number` int,
PRIMARY KEY (`Id`)
);
insert into test (Id, Number) values (1, 1), (2, 2);
DROP procedure IF EXISTS `Test`;
DELIMITER $$
CREATE PROCEDURE `Test`(
p_json json
)
BEGIN
update test s
join json_table(p_json, '$[*]' columns(`id` int path '$.id', `number` int path '$.number')) v
on s.Id=v.id set s.Number=v.number;
END$$
DELIMITER ;
call `Test`('[{"id": 1, "number": 10}, {"id": 2, "number": 20}]');
select * from test;
drop table if exists `test`;
Это на несколько мс медленнее, чем чистый SQL, но я счастлив принять удар, а не генерировать текст sql в коде. Не уверен, насколько он эффективен с огромными наборами записей (объект JSON имеет максимальный размер 1 ГБ), но я использую его все время при обновлении 10 тыс. Строк за раз.
Если нет дубликатов, я не хочу, чтобы эта строка была вставлена. что должен делать id? потому что я получаю информацию с другого сайта, который поддерживает таблицы с идентификаторами. Я вставляю значения по этому идентификатору. если на сайте есть новые записи, я вставлю только идентификаторы и подсчет, за исключением всей другой информации. если и только если есть запись для идентификатора, он должен обновиться, иначе он должен пропустить. что мне делать?