UPDATE Queries

Builds UPDATE queries using SqlUpdate.

All SQL output below shows the result of get_sql(). Where queries have parameters, get_args() is shown alongside.

Basic Update

The .where() method accepts the same parameter variants as SqlTerm.

qb = (SQL.update('films')
      .set('kind', 'Dramatic')
      .where('kind', '=', 'Drama'))
UPDATE films
SET kind = %s
WHERE kind = %s

-- get_args(): ['Dramatic', 'Drama']

Multiple Assignments

Individual columns with literal SQL expressions:

qb = (SQL.update('weather')
      .set('temp_lo = temp_lo + 1')
      .set('temp_hi = temp_lo + 15')
      .set('prcp = DEFAULT'))
UPDATE weather
SET
    temp_lo = temp_lo + 1,
    temp_hi = temp_lo + 15,
    prcp = DEFAULT

With parameterized values:

qb = (SQL.update('weather')
      .set('temp_lo', SQL.cat('temp_lo + ', SQL.value(1)))
      .set('temp_hi', SQL.cat('temp_lo + ', SQL.value(15))))
UPDATE weather
SET
    temp_lo = temp_lo + %s,
    temp_hi = temp_lo + %s

-- get_args(): [1, 15]

Using columns_kwargs() for keyword-style:

qb = (SQL.update('users')
      .columns_kwargs(name='Bob', age=25))
UPDATE users
SET
    age = %s,
    name = %s

-- get_args(): [25, 'Bob']

Column-List Syntax

Use SQL.column_list() to update multiple columns as a group:

qb = (SQL.update('weather')
      .set(SQL.column_list('temp_lo', 'temp_hi', 'prcp')
           .values(SQL.cat('temp_lo + 1'), SQL.cat('temp_lo + 15'), SQL.cat('DEFAULT')))
      .where(SQL.and_expr()
             .add('city', '=', 'San Francisco')
             .add('date', '=', '2003-07-03')))
UPDATE weather
SET (temp_lo, temp_hi, prcp) = (temp_lo + 1, temp_lo + 15, DEFAULT)
WHERE
    city = %s
    AND date = %s

-- get_args(): ['San Francisco', '2003-07-03']

With a subquery:

qb = (SQL.update('accounts')
      .set(SQL.column_list('contact_first_name', 'contact_last_name')
           .query(SQL.select()
                  .columns('first_name', 'last_name')
                  .from_table('employees')
                  .where('employees.id = accounts.sales_person'))))
UPDATE accounts
SET
    (contact_first_name, contact_last_name) = (
        SELECT first_name, last_name
        FROM employees
        WHERE employees.id = accounts.sales_person
    )

Column lists can be mixed freely with single column assignments:

qb = (SQL.update('t')
      .set('a', 1)
      .set(SQL.column_list('b', 'c').values(SQL.cat('2'), SQL.cat('3')))
      .set('d', 4))
UPDATE t
SET
    a = %s,
    (b, c) = (2, 3),
    d = %s

-- get_args(): [1, 4]

Multiple column lists are also supported:

qb = (SQL.update('t')
      .set(SQL.column_list('a', 'b').values(1, 2))
      .set(SQL.column_list('c', 'd').values(3, 4)))
UPDATE t
SET
    (a, b) = (%s, %s),
    (c, d) = (%s, %s)

-- get_args(): [1, 2, 3, 4]

FROM Clause

qb = (SQL.update('employees')
      .set('sales_count', SQL.cat('sales_count + ', SQL.value(1)))
      .from_table('accounts')
      .where(SQL.and_expr()
             .add('accounts.name', '=', 'Acme Corporation')
             .add('employees.id = accounts.sales_person')))
UPDATE employees
SET sales_count = sales_count + %s
FROM accounts
WHERE
    accounts.name = %s
    AND employees.id = accounts.sales_person

-- get_args(): [1, 'Acme Corporation']

UPDATE ONLY

PostgreSQL only.

Restrict update to the named table only (no inherited tables):

qb = (SQL.update('parent_table')
      .only()
      .set('status', 'archived'))
UPDATE ONLY parent_table
SET status = %s

-- get_args(): ['archived']

WITH Clause

qb = (SQL.update('employees')
      .recursive()
      .with_cte_query('subordinates', recursive_select)
      .set('department', 'Engineering')
      .from_table('subordinates')
      .where('employees.id = subordinates.id'))
WITH RECURSIVE subordinates AS (
    ...
)
UPDATE employees
SET department = %s
FROM subordinates
WHERE employees.id = subordinates.id

-- get_args(): ['Engineering']

RETURNING

PostgreSQL only.

qb = (SQL.update('products')
      .set('price = price * 1.10')
      .returning('id', 'price'))
UPDATE products
SET price = price * 1.10
RETURNING id, price

With OLD/NEW references (PostgreSQL 17+):

qb = (SQL.update('products')
      .set('price = price * 1.10')
      .returning_with(old='o', new='n')
      .returning(SQL.column('o.price', 'old_price'),
                 SQL.column('n.price', 'new_price')))
UPDATE products
SET price = price * 1.10
RETURNING WITH (OLD AS o, NEW AS n) o.price AS old_price, n.price AS new_price