【问题标题】:Inserting non matching tuples插入不匹配的元组
【发布时间】:2020-09-15 18:47:53
【问题描述】:

我有一个包含以下列的表格:idstorecategory_idoption_id。此表的内容是通过 web-hook 从不同服务器上的原始内容更新的。收到内容后,我需要检查哪些行需要删除,哪些行需要插入。

为简单起见,假设我从 web-hook 收到的类别和选项 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)

我想知道是否有一种方法可以通过一个查询而不是两个查询来进行插入。

【问题讨论】:

  • 样本数据、所需结果和适当的数据库标签都会有所帮助。
  • 为什么不直接删除所有内容 (TRUNCATE store_category_options),然后从 webhook 中插入数据?
  • 有一种感觉,你让这件事变得比它需要的复杂得多
  • @Strawberry 没关系,这正是我想知道答案的问题,如果不是出于好奇。
  • @Nick 我不删除整个内容并重新插入有两个原因:首先,在我的情况下它效率低下,因为我不希望数据经常更改,我不预计数据会发生很大变化:webhook 每小时都会被调用一次,但我预计每隔几个月只有几行发生变化。其次,我想保留一个时间戳列,我没有将其包含在问题中,因为我认为它不相关

标签: mysql sql tuples where-in


【解决方案1】:

最后我自己想通了。我们可以先将 webhook 数据转换为派生表,然后使用 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 语句中包含上一个 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
);

【讨论】:

    猜你喜欢
    • 2012-09-14
    • 1970-01-01
    • 1970-01-01
    • 2017-05-12
    • 1970-01-01
    • 2011-03-03
    • 2015-11-04
    • 2015-01-19
    • 1970-01-01
    相关资源
    最近更新 更多