Note Always specify column names explicitly. Relying on column order breaks when the table schema changes. Strings must be in single quotes - double quotes are for identifiers in ANSI SQL.
Note Multi-row INSERT is much faster than individual INSERTs because it reduces round trips and allows batch optimization. Most databases support this syntax. There may be a limit on the number of rows per statement.
-- Increases price by 10% for all products in category 5
Note Always include a WHERE clause unless you genuinely want to update every row. Running UPDATE without WHERE is a common disaster. Test with a SELECT using the same WHERE first.
update rowmodify datachange valueedit record
UPDATE with JOIN
Syntax
-- PostgreSQLUPDATE table1 SET col = t2.colFROM table2 t2 WHERE table1.ref= t2.id;-- MySQLUPDATE table1 t1 JOIN table2 t2 ON t1.ref= t2.idSET t1.col= t2.col;
Example
-- PostgreSQLUPDATE orders
SET shipping_region = u.regionFROM users u
WHERE orders.user_id= u.idAND orders.shipping_regionISNULL;
Output
-- Fills in missing shipping regions from the users table
Note Syntax differs between databases. PostgreSQL uses UPDATE ... FROM. MySQL uses UPDATE ... JOIN. Standard SQL uses a correlated subquery in SET. Always test with a SELECT first.
update from another tableupdate with joinupdate using join
DELETE
Syntax
DELETEFROMtableWHERE condition;
Example
DELETEFROM sessions
WHERE last_active <CURRENT_DATE- INTERVAL '90 days';
Output
-- Removes sessions inactive for over 90 days
Note DELETE without WHERE deletes ALL rows. Use TRUNCATE TABLE for faster full-table deletion (it resets auto-increment too). DELETE fires row-level triggers; TRUNCATE usually does not.
delete rowsremove recordsdelete datadelete where
UPSERT (PostgreSQL ON CONFLICT)
Syntax
INSERTINTOtable(columns)VALUES(values)ONCONFLICT(conflict_column)
DO UPDATESET col = EXCLUDED.col;
Example
INSERTINTOuser_preferences(user_id, theme, language)VALUES(42,'dark','en')ONCONFLICT(user_id)
DO UPDATESET
theme = EXCLUDED.theme,
language = EXCLUDED.language;
Output
-- Inserts if user_id 42 has no row, otherwise updates
Note EXCLUDED refers to the row that was proposed for insertion. You need a unique constraint or unique index on the conflict column for ON CONFLICT to work.
upsertinsert or updateon conflictmerge rowinsert on duplicate
UPSERT (MySQL ON DUPLICATE KEY)
Syntax
INSERTINTOtable(columns)VALUES(values)ON DUPLICATE KEYUPDATE col =VALUES(col);
Example
INSERTINTOuser_preferences(user_id, theme, language)VALUES(42,'dark','en')ON DUPLICATE KEYUPDATE
theme =VALUES(theme),
language =VALUES(language);
Output
-- Inserts or updates, same as PostgreSQL ON CONFLICT
Note MySQL 8.0.19+ also supports VALUES(col) replacement with the alias syntax: AS new_row followed by new_row.col. The VALUES() function in ON DUPLICATE KEY UPDATE is deprecated in MySQL 8.0.20+.
mysql upserton duplicate keyinsert or update mysql
MERGE (ANSI SQL)
Syntax
MERGE INTO target USING source
ON target.id= source.idWHEN MATCHED THENUPDATESET...WHENNOT MATCHED THENINSERT(...)VALUES(...);
Example
MERGE INTO inventory t
USING shipments s ON t.product_id= s.product_idWHEN MATCHED THENUPDATESET t.quantity= t.quantity+ s.quantityWHENNOT MATCHED THENINSERT(product_id, quantity)VALUES(s.product_id, s.quantity);
Output
-- Updates existing inventory or inserts new product rows
Note MERGE is supported by SQL Server, Oracle, and PostgreSQL 15+. MySQL does not support MERGE - use ON DUPLICATE KEY UPDATE instead. MERGE can include a WHEN MATCHED AND condition for conditional updates.
merge statementupsert ansisync tablesmerge into
RETURNING Clause
Syntax
INSERTINTOtable(columns)VALUES(values)RETURNING*;UPDATEtableSET col = val WHERE condition RETURNING col;DELETEFROMtableWHERE condition RETURNING id;
Note RETURNING avoids a separate SELECT to get generated IDs or default values. Supported in PostgreSQL natively. MySQL 8.0 does not support RETURNING - use LAST_INSERT_ID() instead. SQL Server uses the OUTPUT clause.
returning clauseget inserted idreturn after insertoutput clause
TRUNCATE TABLE
Syntax
TRUNCATETABLE table_name;
Example
TRUNCATETABLE temp_import_data;
Output
-- All rows removed instantly, auto-increment reset
Note TRUNCATE is much faster than DELETE for removing all rows because it deallocates data pages instead of logging individual row deletions. It cannot be rolled back in MySQL (it can in PostgreSQL). It also cannot have a WHERE clause.
truncate tabledelete all rows fastempty tableclear table