Як протестувати оператор оновлення SQL перед запуском?


96

У деяких випадках запуск оператора UPDATE у виробничій роботі може заощадити день. Однак перерване оновлення може бути гіршим за початкову проблему.

Якщо не використовувати тестову базу даних, які варіанти можуть сказати, що робитиме оператор оновлення перед запуском?

Відповіді:


50

На додаток до використання транзакції, як сказав Імад (що в будь-якому випадку має бути обов'язковою), ви також можете перевірити обгрунтованість, на які рядки впливає, запустивши вибір, використовуючи те саме речення WHERE, що і 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', тому протягом своєї сесії він зможе зробити кілька запитів для перевірки отриманого набору даних ...
Імад Мокаддем

3
@ImadMoqaddem: Я згоден, і тому я написав " Окрім використання транзакції, як сказав Імад "
a_horse_with_no_name

А якщо FOREIGN KEY UPDATE CASCADEваш sql не вдався
Green

@Green: що ви маєте на увазі під фразою?
a_horse_with_no_name

73

А як щодо транзакцій? Вони мають функцію ROLLBACK.

@see 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

Autocommit OFF ...

MySQL

set autocommit=0;

Він вимикає автоматичну передачу поточного сеансу.

Ви виконуєте свою заяву, бачите, що вона змінила, а потім відкочуєте, якщо це неправильно, або фіксуєте, якщо це те, що ви очікували!

EDIT: Перевага використання транзакцій замість запуску запиту select полягає в тому, що ви можете легше перевірити отриманий набір.


4
@dystroy: кожна розумна СУБД підтримує транзакції.
a_horse_with_no_name

7
Просто пам’ятайте про те, щоб швидко здійснити або відмовити транзакцію, інакше ви ризикуєте заблокувати інші транзакції - і в гіршому випадку зупиніть свою програму. Не гарна ідея виконати запит, потім обідати, а потім повернутися, щоб побачити результати! :-)
Гері Макгілл

@GaryMcGill: що очікує операція буде (принаймні в сучасних СУБД) тільки блокувати інші записи транзакції , хоча.
a_horse_with_no_name

5
@dystroy: На жаль, MyISAM використовується скрізь, і я не DBA.
static_rtti

1
Додано заяву Sql :)
Імад Мокаддем

11

Я знаю, що це повторення інших відповідей, але він має певну емоційну підтримку, щоб зробити додатковий крок для тестування оновлення: D

Для тестування оновлення, хеш # - ваш друг.

Якщо у вас є заява про оновлення, наприклад:

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

Ви хешуєте ОНОВЛЕННЯ і ВСТАНОВИТИ для тестування, а потім хеш їх назад:

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

Це працює для простих висловлювань.

Додатковим практично обов'язковим рішенням є отримання копії (резервної копії) при кожному використанні оновлення у виробничій таблиці. Phpmyadmin> операції> копія: table_yearmonthday. Для таблиць <= 100M потрібно лише кілька секунд.


5

Не пряма відповідь, але я бачив багато ситуацій зі зловмисними даними, яких можна було б уникнути, набравши WHEREспершу речення ! Іноді WHERE 1 = 0може допомогти безпечно скласти робочу заяву. І розгляд кошторисного плану виконання, який оцінить рядки, на які впливає, може бути корисним. Крім цього, у транзакції, яку ви відмовляєте, як казали інші.


2
@SystemParadox - нічого, хоча WHERE 1 = 0є більш портативним, якщо хтось стикається з цим, хто працює з іншою СУБД. Наприклад, SQL Server не приймає WHERE FALSE.
Девід М

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'

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.