如何在运行前测试SQL Update语句?


96

在某些情况下,在生产环境中运行UPDATE语句可以节省一天的时间。但是,更新失败可能比最初的问题更严重。

除了不使用测试数据库,还有哪些选项可以告诉您更新语句在运行前将要执行的操作?

Answers:


50

除了使用Imad所说的事务(无论如何应该强制执行)之外,您还可以通过使用与UPDATE相同的WHERE子句运行select来进行完整性检查。

因此,如果您的UPDATE是

UPDATE foo
  SET bar = 42
WHERE col1 = 1
  AND col2 = 'foobar';

下面将向您显示将更新哪些行:

SELECT *
FROM foo
WHERE col1 = 1
  AND col2 = 'foobar';

1
这样,使用事务来检查数据更好。假设他想检查结果,我认为他的陈述要比'SET bar = 42'更复杂,因此他在会议期间将能够进行几次查询以测试所得数据集……
Imad Moqaddem

3
@ImadMoqaddem:我同意,这就是为什么我写了“ 除了使用Imad所说的使用事务
a_horse_with_no_name 2012年

而且,如果您FOREIGN KEY UPDATE CASCADE的SQL失败了
绿色

@格林:“失败”是什么意思?
a_horse_with_no_name

73

交易呢?它们具有回滚功能。

@请参阅https://dev.mysql.com/doc/refman/5.0/en/commit.html

例如:

START TRANSACTION;
SELECT * FROM nicetable WHERE somthing=1;
UPDATE nicetable SET nicefield='VALUE' WHERE somthing=1;
SELECT * FROM nicetable WHERE somthing=1; #check

COMMIT;
# or if you want to reset changes 
ROLLBACK;

SELECT * FROM nicetable WHERE somthing=1; #should be the old value

下面的@rickozoe回答问题:

通常,这些行不会一​​次执行。在PHP fe中,您将编写类似的内容(也许更简洁一些,但是想快速回答;-)):

$MysqlConnection->query('START TRANSACTION;');
$erg = $MysqlConnection->query('UPDATE MyGuests SET lastname='Doe' WHERE id=2;');
if($erg)
    $MysqlConnection->query('COMMIT;');
else
    $MysqlConnection->query('ROLLBACK;');

另一种方法是使用MySQL变量(请参阅https://dev.mysql.com/doc/refman/5.7/en/user-variables.htm l和 https://stackoverflow.com/a/18499823/1416909 ):

# do some stuff that should be conditionally rollbacked later on

SET @v1 := UPDATE MyGuests SET lastname='Doe' WHERE id=2;
IF(v1 < 1) THEN
    ROLLBACK;
ELSE
    COMMIT;
END IF;

但是我建议使用您喜欢的编程语言中可用的语言包装器。


1
嵌套事务会产生意外结果。
烤饼

你能举个例子吗?
马塞尔·兰格

@JCM和其他人,您如何得知更新语句是否在第3行成功执行,以便您可以提交和回滚?
ricko zoe

56

自动提交关闭...

的MySQL

set autocommit=0;

它为当前会话设置自动取消。

您可以执行语句,查看其更改,然后在错误的情况下回滚,或者在期望的情况下进行提交!

编辑:使用事务而不是运行选择查询的好处是您可以更轻松地检查结果集。


4
@dystroy:每个明智的DBMS都支持事务。
a_horse_with_no_name 2012年

7
只要记住要快速提交或回滚事务,否则就有可能阻止其他事务-在最坏的情况下会使您的应用程序陷入停顿。执行查询不是一个好主意,然后吃午餐,然后再回来查看结果!:-)
Gary McGill 2012年

@GaryMcGill:挂起的事务(至少在现代DBMS中)只会阻止其他事务。
a_horse_with_no_name 2012年

5
@dystroy:不幸的是,MyISAM随处可见,我不是DBA。
static_rtti 2012年

1
添加了Sql语句:)
Imad Moqaddem,2014年

11

我知道这是其他答案的重复,但是它有情感上的支持,可以采取额外的步骤来测试更新:D

对于测试更新,#是您的朋友。

如果您有类似以下内容的更新语句:

UPDATE 
wp_history
SET history_by="admin"
WHERE
history_ip LIKE '123%'

您对UPDATE进行哈希处理并开始进行测试,然后将其哈希回去:

SELECT * FROM
#UPDATE
wp_history
#SET history_by="admin"
WHERE
history_ip LIKE '123%'

它适用于简单的语句。

另一个实际上强制性的解决方案是,每当在生产表上使用update时,就获得一个副本(备份副本)。Phpmyadmin>操作>复制:table_yearmonthday。<= 100M的表只需要几秒钟。


5

这不是一个直接的答案,但是我已经看到许多烦人的prod数据情况,可以通过首先键入该WHERE子句来避免!有时,a WHERE 1 = 0也可以帮助将工作陈述安全地组合在一起。并且查看估计的执行计划,该计划将估计受影响的行,将很有用。除此之外,您还可以像其他人所说的那样回滚交易。


2
@SystemParadox-没有任何东西,但是WHERE 1 = 0如果有人遇到这个正在使用其他DBMS的人,则没有什么可移植的。例如,SQL Server将不接受WHERE FALSE
David M

2

在您要测试的这些情况下,最好只关注当前列值以及即将更新的值列值。

请查看以下为更新WHMCS价格而编写的代码:

# UPDATE tblinvoiceitems AS ii

SELECT                        ###  JUST
    ii.amount AS old_value,   ###  FOR
    h.amount AS new_value     ###  TESTING
FROM tblinvoiceitems AS ii    ###  PURPOSES.

JOIN tblhosting AS h ON ii.relid = h.id
JOIN tblinvoices AS i ON ii.invoiceid = i.id

WHERE ii.amount <> h.amount   ### Show only updatable rows

# SET ii.amount = h.amount

这样,我们可以清楚地将现有值与新值进行比较。


1

where使用在更新查询中应用的所有条件,在同一表上运行选择查询。


0

做一个SELECT吧,

就像你有

UPDATE users SET id=0 WHERE name='jan'

转换成

SELECT * FROM users WHERE name='jan'

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.