0

我想做的是具有以下逻辑的东西:

IF EXISTS (SELECT * FROM people WHERE ID = 168)
THEN UPDATE people SET calculated_value = complex_queries_and_calculations
WHERE ID = 168

..,因此如果该记录包含给定数据,则更新给定记录的字段,否则什么也不做。要生成将用于更新的数据,我需要查询其他表的值并进行一些计算。如果实际上没有什么可更新的,我想避免这些查询+计算。在这种情况下,什么也不做。因此,我猜想将 EXIST 子句放在 UPDATE 语句的 WHERE 子句中会导致许多查询和计算徒劳无功。

我如何只能有条件地更新而什么都不做,并确保仅在需要更新时才进行计算用于更新的值所需的所有查询 + 计算?然后,最后,只有在complex_queries_and_calculations不为 NULL 时才进行更新?

到目前为止,我最好的解决方案使用公用表表达式(WITH子句),这使得它不可能短路。无论如何,这样你就可以理解我想要实现的逻辑,我正在展示我迄今为止一直在尝试的东西(没有成功;下面的代码不起作用,我不知道为什么..):

-- complex queries and calculations; return result as t.result
WITH t AS(complex queries and calculations)
UPDATE target_table
SET
CASE
WHEN t.result IS NOT NULL
THEN target_table.target_column = t.result WHERE target_table.PK = 180
END;

更新(仍然说语法错误,仍然无法正常工作)

WITH t AS(complex_queries_and_calculations AS stamp)
UPDATE target_table
SET target_column =
CASE
WHEN t.stamp IS NULL
THEN target_column
ELSE t.stamp
END
WHERE ID = 168;

甚至这都不起作用(仍然在 UPDATE 行上报告语法错误):

WITH t AS(complex_queries_and_calculations AS stamp)
UPDATE target_table
SET target_column = target_column
WHERE ID = 168;

(避免冗余 target_column = target_column 更新的最终更好的方法欢迎)

使用 select 它可以工作,所以我完全不理解它为我的更新查询返回的语法错误 #1064:

WITH t AS(complex_queries_and_calculations AS stamp)
SELECT
CASE
WHEN t.stamp IS NULL
THEN "Error!"
ELSE t.stamp
END
FROM t;

附加信息

看起来 MariaDB 实际上不支持CTEs withUPDATE语句;如果我错了,请纠正我......所以我尝试了以下方法:

UPDATE people AS p
INNER JOIN (queries_and_calculations AS result) t
ON p.ID <> t.result -- just to join
SET p.target_column = t.result
WHERE p.ID = 168
AND t.result IS NOT NULL;

现在它说:

#4078 - Illegal parameter data types varchar and row for operation '='
4

3 回答 3

3

只需执行UPDATE. 如果没有那一行ID,它什么也不做。这可能不会比先测试慢。

DELETE当行可能不存在时同上。

“Upsert”/“IODKU” -INSERT ... ON DUPLICATE KEY UPDATE ...当您想要在行存在时修改某些列(根据某些唯一列)或添加新行(当它不存在时)时很有用。 比做SELECT第一个要好。

这样想……很大一部分UPDATE

  • 打开桌子,
  • 定位表中需要修改的块
  • 将该块加载到缓存中(“buffer_pool”)

SELECT您和UPDATE(是的,多余的)都需要所有这些。UPDATE继续:

  • 如果该行不存在,则退出。
  • 修改该行,并将该块标记为“脏”。
  • 在后台,该块最终将被刷新到磁盘。

(我省略了有关事务完整性(“ACID”)等的详细信息。)

即使在最坏的情况下,整个任务(单行)也需要不到 10 毫秒。在最好的情况下,它需要不到 1 毫秒,并且可以与某些其他活动在一定程度上并行完成。

于 2020-11-14T21:07:15.733 回答
0

SQL 中没有 IF,因为它不是必需的:


UPDATE people p
SET calculated_value = c.val
FROM (
        SELECT ID, val
        FROM
        ... complex_queries_and_calculations
        ) c
WHERE c.ID = p.ID
AND ID = 168
AND v.val <> i.val -- maybe add this to avoid idempotent updates. Beware of NULLs, though!
        ;

~

于 2020-11-15T12:46:17.480 回答
0

明白了,下面的查询完全符合我在 Mariadb 中的要求:

UPDATE target_table

LEFT JOIN (complex_queries_and_calculations_to_get_update_value AS update_value) t

ON target_table.ID <> t.update_value -- serves just to have update value in memory, 
-- because it needs to be accessed twice to create the updated column value 
-- on update, sort of a workaround for CTE + UPDATE in MariaDB

SET target_column = JSON_ARRAY( FORMAT_UPDATE_VALUE(t.update_value),
                    FORMAT_2_UPDATE_VALUE(t.update_value) )

WHERE ID = 128 AND t.update_value IS NOT NULL;

如果记录不存在,则查询执行大约需要 0.0006 秒,而不对表执行任何操作。如果确实退出,则执行需要 0.0014 秒,同时相应地更新目标记录。因此,如果在 target_table 中找不到目标记录,它似乎确实可以工作并节省资源。非常感谢所有帮助过的人!

于 2020-11-15T14:06:48.120 回答