INSERT Queries
Builds INSERT queries using SqlInsert.
All SQL output below shows the result of get_sql(). Where queries have
parameters, get_args() is shown alongside.
Basic Insert
qb = (SQL.insert('users')
.column('name', 'Alice')
.column('email', 'alice@example.com'))
INSERT INTO users (name, email)
VALUES (%s, %s)
-- get_args(): ['Alice', 'alice@example.com']
Multiple Columns (kwargs)
Use columns_kwargs() with keyword arguments (columns are sorted
alphabetically):
qb = (SQL.insert('users')
.columns_kwargs(name='Alice', email='alice@example.com', age=30))
INSERT INTO users (age, email, name)
VALUES (%s, %s, %s)
-- get_args(): [30, 'alice@example.com', 'Alice']
Columns and Values
Separate column names from values using columns() and values():
qb = (SQL.insert('films')
.columns('code', 'title', 'did', 'date_prod', 'kind')
.values('T_601', 'Yojimbo', 106, '1961-06-16', 'Drama'))
INSERT INTO films (code, title, did, date_prod, kind)
VALUES (%s, %s, %s, %s, %s)
-- get_args(): ['T_601', 'Yojimbo', 106, '1961-06-16', 'Drama']
Values Only
Omit column names and provide only values:
qb = (SQL.insert('films')
.values('UA502', 'Bananas', 105, '1971-07-13', 'Comedy', '82 minutes'))
INSERT INTO films
VALUES (%s, %s, %s, %s, %s, %s)
-- get_args(): ['UA502', 'Bananas', 105, '1971-07-13', 'Comedy', '82 minutes']
DEFAULT VALUES
qb = (SQL.insert('films')
.default_values())
INSERT INTO films DEFAULT VALUES
Multiple Rows
Use values_list() to insert multiple rows:
qb = (SQL.insert('films')
.columns('code', 'title', 'did', 'date_prod', 'kind')
.values_list([('B6717', 'Tampopo', 110, '1985-02-10', 'Comedy'),
('HG120', 'The Dinner Game', 140, SQL.cat('DEFAULT'), 'Comedy')]))
INSERT INTO films (code, title, did, date_prod, kind)
VALUES
(%s, %s, %s, %s, %s),
(%s, %s, %s, DEFAULT, %s)
-- get_args(): ['B6717', 'Tampopo', 110, '1985-02-10', 'Comedy',
-- 'HG120', 'The Dinner Game', 140, 'Comedy']
INSERT from SELECT
Without column list (columns not derived from query):
qb = (SQL.insert('films')
.query(SQL.select()
.from_table('tmp_films')
.column('*')
.where('date_prod', '<', '2004-05-07')))
INSERT INTO films
SELECT *
FROM tmp_films
WHERE date_prod < %s
-- get_args(): ['2004-05-07']
With column list derived from the query (use query_columns()):
qb = (SQL.insert('archive')
.query_columns()
.query(SQL.select()
.from_table('orders')
.column('id')
.column('total')
.where('status', '=', 'completed')))
INSERT INTO archive (id, total)
SELECT id, total
FROM orders
WHERE status = %s
-- get_args(): ['completed']
Table Alias
Use an alias for the target table (useful with ON CONFLICT DO UPDATE):
qb = (SQL.insert('distributors', 'd')
.column('did', 8)
.column('dname', 'Anvil Distribution')
.on_conflict('(did)',
SQL.update()
.set('dname', SQL.cat("((excluded.dname || ' (formerly ') || d.dname) || ')'"))
.where('d.zipcode', '<>', '21201')))
INSERT INTO distributors AS d (did, dname)
VALUES (%s, %s)
ON CONFLICT (did) DO UPDATE
SET dname = ((excluded.dname || ' (formerly ') || d.dname) || ')'
WHERE d.zipcode <> %s
-- get_args(): [8, 'Anvil Distribution', '21201']
ON CONFLICT (Upsert)
PostgreSQL only. See also MySQL’s SQL.insert().ignore() and SQLite’s
SQL.insert().or_ignore().
Do nothing on conflict:
qb = (SQL.insert('users')
.column('email', 'alice@example.com')
.on_conflict('(email)'))
INSERT INTO users (email)
VALUES (%s)
ON CONFLICT (email) DO NOTHING
-- get_args(): ['alice@example.com']
With update action:
action = (SQL.update()
.set('name', SQL.cat('excluded.name'))
.set('updated_at', SQL.cat('now()')))
qb = (SQL.insert('users')
.column('email', 'alice@example.com')
.column('name', 'Alice')
.on_conflict('(email)', action))
INSERT INTO users (email, name)
VALUES (%s, %s)
ON CONFLICT (email) DO UPDATE
SET
name = excluded.name,
updated_at = now()
-- get_args(): ['alice@example.com', 'Alice']
With a named constraint:
qb = (SQL.insert('distributors')
.column('did', 9)
.column('dname', 'Antwerp Design')
.on_conflict('ON CONSTRAINT distributors_pkey'))
INSERT INTO distributors (did, dname)
VALUES (%s, %s)
ON CONFLICT ON CONSTRAINT distributors_pkey DO NOTHING
-- get_args(): [9, 'Antwerp Design']
WITH Clause
PostgreSQL only (uses RETURNING in the CTE).
qb = (SQL.insert('employees_log')
.with_cte_query('upd',
SQL.update('employees')
.set('sales_count = sales_count + 1')
.where('id', '=',
SQL.select()
.column('sales_person')
.from_table('accounts')
.where('name', '=', 'Acme Corporation'))
.returning('*'))
.query(SQL.select()
.columns('*', 'current_timestamp')
.from_table('upd')))
WITH upd AS (
UPDATE employees
SET sales_count = sales_count + 1
WHERE
id = (
SELECT sales_person
FROM accounts
WHERE name = %s
)
RETURNING *
)
INSERT INTO employees_log
SELECT *, current_timestamp
FROM upd
-- get_args(): ['Acme Corporation']
RETURNING
PostgreSQL only.
qb = (SQL.insert('users')
.column('name', 'Alice')
.returning('id', 'created_at'))
INSERT INTO users (name)
VALUES (%s)
RETURNING id, created_at
-- get_args(): ['Alice']