#php #mysql
#php #mysql
Вопрос:
Моя программа получает список идентификаторов, некоторые из которых есть в нашей системе, некоторые из которых нет. Цель состоит в том, чтобы внести запись в таблицу для идентификаторов, которые существуют в нашей системе, но игнорировать те, которые этого не делают.
Пример:
Incomming My System Inserted
555 583 583
583
599
Моей первоначальной мыслью было использовать INSERT IGNORE
, но список идентификаторов для проверки находится в таблице users, а строки вставляются в таблицу events. Я также попробовал ограничение внешнего ключа, но INSERT IGNORE
оно не завершается без сбоев с FK — оно выдает ошибку, которая уничтожает все последующие вставки.
Мой текущий угол атаки — считывать все идентификаторы из таблицы users в PHP и проверять идентификаторы в PHP перед попыткой вставки, но это кажется неоптимальным. Есть ли способ MySQL сделать это?
Комментарии:
1. Неофициально: если в какой-то момент в будущем производительность станет проблемой, все эти способы MySQL и зависимости между таблицами сделают вашу жизнь несчастной. «Тупой» в большинстве случаев равнозначно «быстрому».
Ответ №1:
INSERT INTO your_id_table (ID)
SELECT ID FROM my_system_table WHERE ID IN (list_of_ids)
Я надеюсь, что это понятно, при этом вам вообще не нужно выполнять какие-либо проверки, вы просто запускаете запрос и заканчиваете с этим.
Ответ №2:
Вы могли бы использовать оператор if exists(), который проверяет, существует ли значение в таблице пользователя перед вставкой.
if exists (select * from user where id = @id)
begin
/*insert*/
end
else
begin
/*return a status message or insert in error table to track failed records*/
end
Ответ №3:
Это довольно уродливый способ сделать это, но он работает:
$ids = array( /* ids */ );
$ids = implode(',', $ids);
$sql = 'SELECT `id` FROM `table` WHERE `id` IN ('.$ids.')';
$result = $db -> query($sql);
$exists = $result -> fetch_all();
$doesntExist = array_diff($ids, $exists);
Комментарии:
1. Мне нравится этот! Минимальный перебор: он включает только идентификаторы из insert, не извлекая ВСЕ идентификаторы пользователей, и использует индекс по идентификатору (который, я надеюсь, существует).
2. Одна загвоздка в том, что он использует
fetch_all
, для которого требуется PHP 5.3 или выше.
Ответ №4:
Вы могли бы попробовать:
INSERT INTO Inserted(id) VALUES SELECT id FROM Incoming WHERE id IN (SELECT id FROM My_System)
Это выбирает идентификаторы в Incomming, которые также находятся в My_System, и вставляет их в Inserted .
Ответ №5:
Вы можете сделать что-то вроде этого:
INSERT INTO events (iduser)
SELECT iduser
FROM users WHERE iduser IN (1,2,3,4,5)
Этот запрос будет возвращать только идентификаторы пользователей, которые присутствуют в таблице, так что это должно сработать.
Если у вас есть больше столбцов для вставки, это будет выглядеть примерно так:
$idsToInsert = "1,2,3,4,5,6";
$query = "INSERT INTO events (iduser, title)
SELECT iduser, ".$title."
FROM users WHERE iduser IN (".$idsToInsert.")";
И не забудьте очистить свой ввод, используя mysql_real_escape, вы также можете использовать параметризованные запросы для достижения этой цели.
Эту последнюю часть запроса вы должны генерировать динамически через PHP, но это не проблема
Ссылка Mysql для вставки в таблицу, выбранную из, находится здесь: http://dev.mysql.com/doc/refman/5.0/en/insert-select.html
Ответ №6:
Вы можете сделать это в коде PHP
$result = mysql_query("SELECT id FROM another_table WHERE id = '100'");
$number_of_rows = mysql_num_rows($result);
if ($number_of_rows > 0) {
// ID exist in other table
}
Ответ №7:
FK выдает ошибку, которая уничтожает все последующие вставки
Почему это убивает следующие вставки? Делать вставки по одному, try
— catch
ошибки mysql.
Комментарии:
1. Уже сделано, но это немного медленно — обработка более 10 000 за раз
Ответ №8:
Это самое элегантное решение, которое я могу придумать:
INSERT INTO events (id)
SELECT id FROM my_system ms
LEFT JOIN incoming i
ON i.id = ms.id
WHERE i.id IS NOT NULL
Идея здесь в том, что вы исключаете те записи во входящей таблице, которые не имеют соответствующей записи в таблице my_system, потому что результирующий набор будет равен null для входящих идентификаторов.
Похоже, что некоторые другие люди уже придумали подобное решение! Надеюсь, это поможет, в любом случае.
Комментарии:
1.
left join where is not null
также известен какinner join
:-).
Ответ №9:
Внутреннее соединение — самый простой способ его выполнить
INSERT INTO events (id)
SELECT incoming.id
FROM my_system ms
INNER JOIN incoming i
USING (id);
Просто загрузите входящие идентификаторы во входящую таблицу. Кроме того, не забудьте использовать идентификатор в качестве ПЕРВИЧНОГО КЛЮЧА обеих таблиц.
Ответ №10:
Просто сделайте:
insert into events (id, value1, value2, ...)
select id, @value1, @value2, ...
from users
where id = @id
Таким образом, он будет вставляться только в том случае, если идентификатор уже существует в вашей users
таблице. Предполагается id
, что значение уникально для каждой строки в users
таблице, но если бы оно не было просто добавлено distinct
после выбора, чтобы убедиться, что вставлена только одна строка.