# SQLAlchemy 2.0(08)更新與刪除
###### tags: `python` `sqlalchemy`
[官方文件](https://docs.sqlalchemy.org/en/20/tutorial/data_update.html)
人生總是希望能回頭,就跟寫入資料一樣,寫入錯誤就需要留個後路來更新、刪除。作法都是差不多的,只是從`select`變成`update, delete`。
## update
```python=
from sqlalchemy import update
stmt = (
update(user_table)
.where(user_table.c.name == "patrick")
.values(fullname="Patrick the Star")
)
print(stmt)
```
```
UPDATE user_account SET fullname=:fullname WHERE user_account.name = :name_1
```
更新資料表`user_table`,條件是`name='patrick'`,把`fullname`更新為`Patrick the Star`。看的出來`values`就是我們用資料庫語法中的`set`。
如果要更新多筆資料的話,倒是可以利用`bindparam`來處理:
```python=
from sqlalchemy import bindparam
stmt = (
update(user_table)
.where(user_table.c.name == bindparam("oldname"))
.values(name=bindparam("newname"))
)
with engine.begin() as conn:
conn.execute(
stmt,
[
{"oldname": "jack", "newname": "ed"},
{"oldname": "wendy", "newname": "mary"},
{"oldname": "jim", "newname": "jake"},
],
)
```
```
UPDATE user_account SET name=? WHERE user_account.name = ?
[...] [('ed', 'jack'), ('mary', 'wendy'), ('jake', 'jim')]
```
這個範例中把預計做為更新的key當做`bindparam`的綁定參數,然後在`execute`這個語法的話再把多筆更新資料利用`dict`綁定賦值,範例中不難看出key值的對應。
當然你也可以弄一個子查詢來做為更新值:
```python=
scalar_subq = (
select(address_table.c.email_address)
.where(address_table.c.user_id == user_table.c.id)
.order_by(address_table.c.id)
.limit(1)
.scalar_subquery()
)
update_stmt = update(user_table).values(fullname=scalar_subq)
print(update_stmt)
```
```
UPDATE user_account SET fullname=(SELECT address.email_address
FROM address
WHERE address.user_id = user_account.id ORDER BY address.id
LIMIT :param_1)
```
不過通常我在oracle更新資料如果要扯到其它資料表的話,我還是比較喜歡使用`merge into`,簡單又直觀。所以如果你的backend database是用oracle的話就直接用`text`自己寫語法好了。
## delete
delete這個動作有些系統是真的把資料刪除,有些系統是給個flag,看你的實際應用,總之就是讓這筆資料不要出現就是:
```python=
from sqlalchemy import delete
stmt = delete(user_table).where(user_table.c.name == "patrick")
print(stmt)
```
```
DELETE FROM user_account WHERE user_account.name = :name_1
```
## rowcount
不論是更新還是刪除,我們都是可以從回傳結果中的`rowcount`來瞭解影響範圍:
```python=
with engine.begin() as conn:
result = conn.execute(
update(user_table)
.values(fullname="Patrick McStar")
.where(user_table.c.name == "patrick")
)
print(result.rowcount)
```
不過官方文件裡面還是特別提了一下:
The value returned is the number of rows matched by the WHERE clause of the statement. It does not matter if the row were actually modified or not.
大概的意思就是說,這個數量就只是跟`where`條件句匹配到的數量,並不是真正被異動到的數量,就當個參考吧。
## returning
當然,跟`insert`一樣,`update`與`delete`也可以搭配`returning`一起服用:
```python=
update_stmt = (
update(user_table)
.where(user_table.c.name == "patrick")
.values(fullname="Patrick the Star")
.returning(user_table.c.id, user_table.c.name)
)
print(update_stmt)
```
```
UPDATE user_account SET fullname=:fullname
WHERE user_account.name = :name_1
RETURNING user_account.id, user_account.name
```
```PYTHON=
delete_stmt = (
delete(user_table)
.where(user_table.c.name == "patrick")
.returning(user_table.c.id, user_table.c.name)
)
print(delete_stmt)
```
```
DELETE FROM user_account
WHERE user_account.name = :name_1
RETURNING user_account.id, user_account.name
```