Вставка несовпадающих кортежей - PullRequest
0 голосов
/ 28 мая 2020

У меня есть таблица со следующими столбцами: id, store, category_id и option_id. Содержимое этой таблицы обновляется через веб-ловушку с оригинала на другом сервере. После получения содержимого мне нужно будет проверить, какие строки нужно удалить, а какие вставить.

Для простоты предположим, что кортежи идентификаторов категорий и опций, которые я получил от веб-ловушки, равны (1,1) и (1,2), и что база данных уже содержит (1,1) и (1 , 3). Итак, (1,3) нужно будет удалить, а (1,2) нужно будет вставить.

Я могу выполнить удаление, как это:

DELETE FROM store_category_options 
 WHERE store=1 AND (category_id, option_id) NOT IN ((1,1), (1,2));

Однако вставка требуется два запроса: один для извлечения значений, уже находящихся в базе данных

SELECT category_id, option_id FROM store_category_options WHERE store=1

, а затем после вычисления разницы вне MYSQL другой, чтобы вставить их обратно:

INSERT INTO store_category_option (category_id, option_id) VALUES (1,2)

Мне было интересно, есть ли способ делать вставки с помощью одного запроса вместо двух.

1 Ответ

0 голосов
/ 31 мая 2020

Я в конце концов разобрался сам. Мы можем начать с преобразования данных веб-перехватчика в производную таблицу для выбора с помощью WHERE NOT IN

SELECT 1 as store_category_id, 1 as store_option_id UNION SELECT 1, 2;

В Mysql CLI это дает результат:

+-------------------+-----------------+
| store_category_id | store_option_id |
+-------------------+-----------------+
|                 1 |               1 |
|                 1 |               2 |
+-------------------+-----------------+
2 rows in set (0.00 sec)

Для запроса эту таблицу с предложением where необходимо включить в подзапрос другого select и дать таблице псевдоним:

SELECT store_category_id, store_option_id FROM (
  SELECT 1 as store_category_id, 1 as store_option_id 
  UNION SELECT 1, 2
) AS vt WHERE store_option_id = 1;

Это дает результат:

+-------------------+-----------------+
| store_category_id | store_option_id |
+-------------------+-----------------+
|                 1 |               1 |
+-------------------+-----------------+
1 row in set (0.00 sec)

Теперь мы можно использовать предложение where в сочетании с другим подзапросом для выбора строк для вставки:

SELECT store_category_id, store_option_id FROM (
  SELECT 1 as store_category_id, 1 as store_option_id 
  UNION SELECT 1, 2
) AS vt WHERE (category_id, option_id) NOT IN (
  SELECT store_category_id, store_option_id 
  FROM store_category_options
);

Результат:

+-------------------+-----------------+
| store_category_id | store_option_id |
+-------------------+-----------------+
|                 1 |               2 |
+-------------------+-----------------+
1 row in set (0.00 sec)

Наконец, чтобы вставить строки, которые мы рассчитали, мы включаем предыдущий оператор выбора внутри оператора INSERT INTO SELECT

INSERT INTO store_category_options 
(store_category_id, store_option_id)
SELECT store_category_id, store_option_id FROM (
    SELECT 1 as store_category_id, 1 as store_option_id 
    UNION SELECT 1, 2
) AS vt WHERE (store_category_id, store_option_id) NOT IN (
    SELECT store_category_id, store_option_id 
    FROM store_category_options
);
...