2017-02-17 2 views
1

Я хотел бы обновить несколько строк:Как атомизировать несколько строк и выбирать их тоже?

UPDATE tbl SET x = x + 5 WHERE x < 7; 

Тогда я хотел бы, чтобы выбрать те же строки в результирующем:

SELECT * FROM tbl WHERE (row fulfilled previous condition); 

Как бы мне это сделать?

+0

Примечание для закрытия фей: Пожалуйста, убедитесь, что вы закрыли или объединили это с фактически эквивалентным вопросом, которому не исполнилось 10 лет. – mafu

+1

Сначала выберите ключевые значения из условия Where в таблице temp, обновите, а затем выберите из таблицы temp, соединяющей обновленную таблицу. –

+0

Какая СУБД точно? –

ответ

0

Этот ответ относится к mySQL, но он должен быть достаточно универсальным для применения к другим СУБД. Он избегает дополнительных строк, ограничивающих или уродливых хаков, легко расширяется и не теряет производительности без необходимости.

START TRANSACTION; 
DROP TEMPORARY TABLE IF EXISTS temp; 
CREATE TEMPORARY TABLE temp AS (
    SELECT * FROM tbl WHERE x < 7 
); 
UPDATE temp SET x = x + 5; 
REPLACE INTO tbl SELECT * FROM temp; 
SELECT * FROM temp; 
COMMIT; 

Если вы используете это в PHP/PDO, вам может потребоваться сначала выбрать правильный набор результатов. Ошибка HY000 является показателем этого.

$stmt = db -> prepare ($sql); 
$stmt->execute(); 
for ($i=0; $i<5; $i++) 
    $stmt->nextRowset(); 
$result = $stmt->fetchAll(); 
-1

для MS SQL Server, необходимо использовать команду ВЫВОД MSDN

UPDATE tbl SET x = x + 5 
OUTPUT DELETED.* 
WHERE x < 7 

это перечислит все предыдущие значения

0

Postgres версии

UPDATE tbl t1 
SET x = t1.x + 5 
FROM (SELECT * FROM tbl WHERE x < 7 FOR UPDATE) t2 
WHERE t1.x = t2.x 
RETURNING t2.* 
0

В MySQL, если вы хотите чтобы прочитать строки перед их обновлением, вы можете сделать блокировку чтения в транзакции:

START TRANSACTION; 

SELECT ... FROM tbl WHERE x < 7 FOR UPDATE; 

Это приобретает блокировки на соответствующих строках, точно так же, как если бы вы сделали обновление. Поэтому никто больше не может блокировать эти строки до завершения транзакции.

После этого вы можете обновить строки, когда будете приближаться к нему, но все же в одной транзакции.

UPDATE tbl SET x = x + 5 WHERE x < 7; 

COMMIT; 

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

START TRANSACTION; 

UPDATE tbl SET x = x + 5 WHERE x < 7; 

SELECT ... FROM tbl WHERE x < 7; 

COMMIT; 

Но, конечно, мог бы выбрать другой набор строк, потому что х изменилось. Любая строка, где x> = 2 или больше, перед UPDATE будет иметь x> = 7 после UDPATE и, следовательно, не будет в результате последующего SELECT.

Весь этот синтаксис является стандартным SQL-99, поэтому он должен работать в любой совместимой реализации SQL. Но не все базы данных реализуют стандарт таким же образом, поэтому обратитесь к документации для используемого вами бренда.

E.g. https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html

Другие синтаксисы, такие как RETURNING и OUTPUT, не являются стандартными SQL, насколько я знаю.

Смежные вопросы