# 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 ```