345 lines
15 KiB
HTML
345 lines
15 KiB
HTML
<!DOCTYPE html>
|
|
<html><head>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
|
<link href="sqlite.css" rel="stylesheet">
|
|
<title>UPSERT</title>
|
|
<!-- path= -->
|
|
</head>
|
|
<body>
|
|
<div class=nosearch>
|
|
<a href="index.html">
|
|
<img class="logo" src="images/sqlite370_banner.gif" alt="SQLite" border="0">
|
|
</a>
|
|
<div><!-- IE hack to prevent disappearing logo --></div>
|
|
<div class="tagline desktoponly">
|
|
Small. Fast. Reliable.<br>Choose any three.
|
|
</div>
|
|
<div class="menu mainmenu">
|
|
<ul>
|
|
<li><a href="index.html">Home</a>
|
|
<li class='mobileonly'><a href="javascript:void(0)" onclick='toggle_div("submenu")'>Menu</a>
|
|
<li class='wideonly'><a href='about.html'>About</a>
|
|
<li class='desktoponly'><a href="docs.html">Documentation</a>
|
|
<li class='desktoponly'><a href="download.html">Download</a>
|
|
<li class='wideonly'><a href='copyright.html'>License</a>
|
|
<li class='desktoponly'><a href="support.html">Support</a>
|
|
<li class='desktoponly'><a href="prosupport.html">Purchase</a>
|
|
<li class='search' id='search_menubutton'>
|
|
<a href="javascript:void(0)" onclick='toggle_search()'>Search</a>
|
|
</ul>
|
|
</div>
|
|
<div class="menu submenu" id="submenu">
|
|
<ul>
|
|
<li><a href='about.html'>About</a>
|
|
<li><a href='docs.html'>Documentation</a>
|
|
<li><a href='download.html'>Download</a>
|
|
<li><a href='support.html'>Support</a>
|
|
<li><a href='prosupport.html'>Purchase</a>
|
|
</ul>
|
|
</div>
|
|
<div class="searchmenu" id="searchmenu">
|
|
<form method="GET" action="search">
|
|
<select name="s" id="searchtype">
|
|
<option value="d">Search Documentation</option>
|
|
<option value="c">Search Changelog</option>
|
|
</select>
|
|
<input type="text" name="q" id="searchbox" value="">
|
|
<input type="submit" value="Go">
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
function toggle_div(nm) {
|
|
var w = document.getElementById(nm);
|
|
if( w.style.display=="block" ){
|
|
w.style.display = "none";
|
|
}else{
|
|
w.style.display = "block";
|
|
}
|
|
}
|
|
function toggle_search() {
|
|
var w = document.getElementById("searchmenu");
|
|
if( w.style.display=="block" ){
|
|
w.style.display = "none";
|
|
} else {
|
|
w.style.display = "block";
|
|
setTimeout(function(){
|
|
document.getElementById("searchbox").focus()
|
|
}, 30);
|
|
}
|
|
}
|
|
function div_off(nm){document.getElementById(nm).style.display="none";}
|
|
window.onbeforeunload = function(e){div_off("submenu");}
|
|
/* Disable the Search feature if we are not operating from CGI, since */
|
|
/* Search is accomplished using CGI and will not work without it. */
|
|
if( !location.origin || !location.origin.match || !location.origin.match(/http/) ){
|
|
document.getElementById("search_menubutton").style.display = "none";
|
|
}
|
|
/* Used by the Hide/Show button beside syntax diagrams, to toggle the */
|
|
function hideorshow(btn,obj){
|
|
var x = document.getElementById(obj);
|
|
var b = document.getElementById(btn);
|
|
if( x.style.display!='none' ){
|
|
x.style.display = 'none';
|
|
b.innerHTML='show';
|
|
}else{
|
|
x.style.display = '';
|
|
b.innerHTML='hide';
|
|
}
|
|
return false;
|
|
}
|
|
</script>
|
|
</div>
|
|
<div class=fancy>
|
|
<div class=nosearch>
|
|
<div class="fancy_title">
|
|
UPSERT
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<h1 id="syntax"><span>1. </span>Syntax</h1>
|
|
<p><b><a href="syntax/upsert-clause.html">upsert-clause:</a></b>
|
|
<button id='x2093' onclick='hideorshow("x2093","x2094")'>hide</button></p>
|
|
<div id='x2094' class='imgcontainer'>
|
|
<img alt="syntax diagram upsert-clause" src="images/syntax/upsert-clause.gif" />
|
|
<p><b><a href="syntax/column-name-list.html">column-name-list:</a></b>
|
|
<button id='x2095' onclick='hideorshow("x2095","x2096")'>show</button></p>
|
|
<div id='x2096' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram column-name-list" src="images/syntax/column-name-list.gif" />
|
|
</div>
|
|
<p><b><a href="syntax/expr.html">expr:</a></b>
|
|
<button id='x2097' onclick='hideorshow("x2097","x2098")'>show</button></p>
|
|
<div id='x2098' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram expr" src="images/syntax/expr.gif" />
|
|
<p><b><a href="syntax/filter-clause.html">filter-clause:</a></b>
|
|
<button id='x2099' onclick='hideorshow("x2099","x2100")'>show</button></p>
|
|
<div id='x2100' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram filter-clause" src="images/syntax/filter-clause.gif" />
|
|
</div>
|
|
<p><b><a href="syntax/literal-value.html">literal-value:</a></b>
|
|
<button id='x2101' onclick='hideorshow("x2101","x2102")'>show</button></p>
|
|
<div id='x2102' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram literal-value" src="images/syntax/literal-value.gif" />
|
|
</div>
|
|
<p><b><a href="syntax/over-clause.html">over-clause:</a></b>
|
|
<button id='x2103' onclick='hideorshow("x2103","x2104")'>show</button></p>
|
|
<div id='x2104' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram over-clause" src="images/syntax/over-clause.gif" />
|
|
<p><b><a href="syntax/frame-spec.html">frame-spec:</a></b>
|
|
<button id='x2105' onclick='hideorshow("x2105","x2106")'>show</button></p>
|
|
<div id='x2106' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram frame-spec" src="images/syntax/frame-spec.gif" />
|
|
</div>
|
|
<p><b><a href="syntax/ordering-term.html">ordering-term:</a></b>
|
|
<button id='x2107' onclick='hideorshow("x2107","x2108")'>show</button></p>
|
|
<div id='x2108' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram ordering-term" src="images/syntax/ordering-term.gif" />
|
|
</div>
|
|
</div>
|
|
<p><b><a href="syntax/raise-function.html">raise-function:</a></b>
|
|
<button id='x2109' onclick='hideorshow("x2109","x2110")'>show</button></p>
|
|
<div id='x2110' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram raise-function" src="images/syntax/raise-function.gif" />
|
|
</div>
|
|
<p><b><a href="syntax/select-stmt.html">select-stmt:</a></b>
|
|
<button id='x2111' onclick='hideorshow("x2111","x2112")'>show</button></p>
|
|
<div id='x2112' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram select-stmt" src="images/syntax/select-stmt.gif" />
|
|
<p><b><a href="syntax/common-table-expression.html">common-table-expression:</a></b>
|
|
<button id='x2113' onclick='hideorshow("x2113","x2114")'>show</button></p>
|
|
<div id='x2114' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram common-table-expression" src="images/syntax/common-table-expression.gif" />
|
|
</div>
|
|
<p><b><a href="syntax/compound-operator.html">compound-operator:</a></b>
|
|
<button id='x2115' onclick='hideorshow("x2115","x2116")'>show</button></p>
|
|
<div id='x2116' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram compound-operator" src="images/syntax/compound-operator.gif" />
|
|
</div>
|
|
<p><b><a href="syntax/join-clause.html">join-clause:</a></b>
|
|
<button id='x2117' onclick='hideorshow("x2117","x2118")'>show</button></p>
|
|
<div id='x2118' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram join-clause" src="images/syntax/join-clause.gif" />
|
|
<p><b><a href="syntax/join-constraint.html">join-constraint:</a></b>
|
|
<button id='x2119' onclick='hideorshow("x2119","x2120")'>show</button></p>
|
|
<div id='x2120' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram join-constraint" src="images/syntax/join-constraint.gif" />
|
|
</div>
|
|
<p><b><a href="syntax/join-operator.html">join-operator:</a></b>
|
|
<button id='x2121' onclick='hideorshow("x2121","x2122")'>show</button></p>
|
|
<div id='x2122' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram join-operator" src="images/syntax/join-operator.gif" />
|
|
</div>
|
|
</div>
|
|
<p><b><a href="syntax/ordering-term.html">ordering-term:</a></b>
|
|
<button id='x2123' onclick='hideorshow("x2123","x2124")'>show</button></p>
|
|
<div id='x2124' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram ordering-term" src="images/syntax/ordering-term.gif" />
|
|
</div>
|
|
<p><b><a href="syntax/result-column.html">result-column:</a></b>
|
|
<button id='x2125' onclick='hideorshow("x2125","x2126")'>show</button></p>
|
|
<div id='x2126' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram result-column" src="images/syntax/result-column.gif" />
|
|
</div>
|
|
<p><b><a href="syntax/table-or-subquery.html">table-or-subquery:</a></b>
|
|
<button id='x2127' onclick='hideorshow("x2127","x2128")'>show</button></p>
|
|
<div id='x2128' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram table-or-subquery" src="images/syntax/table-or-subquery.gif" />
|
|
</div>
|
|
<p><b><a href="syntax/window-defn.html">window-defn:</a></b>
|
|
<button id='x2129' onclick='hideorshow("x2129","x2130")'>show</button></p>
|
|
<div id='x2130' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram window-defn" src="images/syntax/window-defn.gif" />
|
|
<p><b><a href="syntax/frame-spec.html">frame-spec:</a></b>
|
|
<button id='x2131' onclick='hideorshow("x2131","x2132")'>show</button></p>
|
|
<div id='x2132' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram frame-spec" src="images/syntax/frame-spec.gif" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p><b><a href="syntax/type-name.html">type-name:</a></b>
|
|
<button id='x2133' onclick='hideorshow("x2133","x2134")'>show</button></p>
|
|
<div id='x2134' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram type-name" src="images/syntax/type-name.gif" />
|
|
<p><b><a href="syntax/signed-number.html">signed-number:</a></b>
|
|
<button id='x2135' onclick='hideorshow("x2135","x2136")'>show</button></p>
|
|
<div id='x2136' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram signed-number" src="images/syntax/signed-number.gif" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p><b><a href="syntax/indexed-column.html">indexed-column:</a></b>
|
|
<button id='x2137' onclick='hideorshow("x2137","x2138")'>show</button></p>
|
|
<div id='x2138' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram indexed-column" src="images/syntax/indexed-column.gif" />
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<h1 id="description"><span>2. </span>Description</h1>
|
|
|
|
<p>UPSERT is a special syntax addition to <a href="lang_insert.html">INSERT</a> that causes the
|
|
INSERT to behave as an <a href="lang_update.html">UPDATE</a> or a no-op if the INSERT would violate
|
|
a uniqueness constraint.
|
|
UPSERT is not standard SQL. UPSERT in SQLite follows the
|
|
syntax established by PostgreSQL.
|
|
UPSERT syntax was added to SQLite with version 3.24.0 (2018-06-04).
|
|
|
|
</p><p>An UPSERT is an ordinary <a href="lang_insert.html">INSERT</a> statement that is followed by
|
|
the special ON CONFLICT clause shown above.
|
|
|
|
</p><p>The syntax that occurs in between the "ON CONFLICT" and "DO" keywords
|
|
is called the "conflict target". The conflict target specifies a specific
|
|
uniqueness constraint that will trigger the upsert. The conflict target
|
|
is required for DO UPDATE upserts, but is optional for DO NOTHING. When
|
|
the conflict target is omitted, the upsert behavior is triggered by a
|
|
violation of any uniqueness constraint on the table of the INSERT.
|
|
|
|
</p><p>If the insert operation would cause the uniqueness constraint identified
|
|
by the conflict-target clause to fail, then the insert is omitted and
|
|
either the DO NOTHING or DO UPDATE operation is performed instead.
|
|
In the case of a multi-row insert, this decision is made separately
|
|
for each row of the insert.
|
|
|
|
</p><p>The special UPSERT processing happens only for uniqueness constraint on
|
|
the table that is receiving the INSERT. A "uniqueness constraint"
|
|
is an explicit UNIQUE or PRIMARY KEY constraint within
|
|
the CREATE TABLE statement, or a <a href="lang_createindex.html#uniqueidx">unique index</a>.
|
|
UPSERT does not intervene for failed NOT NULL or foreign key constraints
|
|
or for constraints that are implemented using triggers.
|
|
|
|
</p><p>Column names in the expressions of a DO UPDATE refer to the original
|
|
unchanged value of the column, before the attempted INSERT. To use the
|
|
value that would have been inserted had the constraint not failed,
|
|
add the special "excluded." table qualifier to the column name.
|
|
|
|
</p><p>Some examples will help illustrate the difference:
|
|
|
|
</p><blockquote><pre>
|
|
CREATE TABLE vocabulary(word TEXT PRIMARY KEY, count INT DEFAULT 1);
|
|
INSERT INTO vocabulary(word) VALUES('jovial')
|
|
ON CONFLICT(word) DO UPDATE SET count=count+1;
|
|
</pre></blockquote>
|
|
|
|
<p>The upsert above inserts the new vocabulary word "jovial" if that
|
|
word is not already in the dictionary, or if it is already in the
|
|
dictionary, it increments the counter. The "count+1" expression
|
|
could also be written as "vocabulary.count". PostgreSQL requires the
|
|
second form, but SQLite accepts either.
|
|
|
|
</p><blockquote><pre>
|
|
CREATE TABLE phonebook(name TEXT PRIMARY KEY, phonenumber TEXT);
|
|
INSERT INTO phonebook(name,phonenumber) VALUES('Alice','704-555-1212')
|
|
ON CONFLICT(name) DO UPDATE SET phonenumber=excluded.phonenumber;
|
|
</pre></blockquote>
|
|
|
|
<p>In the second example, the expression in the DO UPDATE clause is
|
|
of the form "excluded.phonenumber". The "excluded." prefix causes the
|
|
"phonenumber" to refer to the value for phonenumber that would have been
|
|
inserted had there been no conflict. Hence, the effect of the upsert
|
|
is to insert a phonenumber of Alice if none exists, or to overwrite
|
|
any prior phonenumber for Alice with the new one.
|
|
|
|
</p><p>Note that the DO UPDATE clause acts only on the single row
|
|
that experienced the constraint error during INSERT. It is not
|
|
necessary to include a WHERE clause that restrictions the action
|
|
to that one row. The only use for the WHERE clause at
|
|
the end of the DO UPDATE is to optionally change the DO UPDATE
|
|
into a no-op depending on the original and/or new values.
|
|
For example:
|
|
|
|
</p><blockquote><pre>
|
|
CREATE TABLE phonebook2(
|
|
name TEXT PRIMARY KEY,
|
|
phonenumber TEXT,
|
|
validDate DATE
|
|
);
|
|
INSERT INTO phonebook2(name,phonenumber,validDate)
|
|
VALUES('Alice','704-555-1212','2018-05-08')
|
|
ON CONFLICT(name) DO UPDATE SET
|
|
phonenumber=excluded.phonenumber,
|
|
validDate=excluded.validDate
|
|
WHERE excluded.validDate>phonebook2.validDate;
|
|
</pre></blockquote>
|
|
|
|
<p>In this last example, the phonebook2 entry is only
|
|
updated if the validDate for the newly inserted value is
|
|
newer than the entry already in the table. If the table already
|
|
contains an entry with the same name and a current validDate,
|
|
then the WHERE clause causes the DO UPDATE to become a no-op.
|
|
|
|
<a name="parseambig"></a>
|
|
|
|
|
|
</p><h2 id="parsing_ambiguity"><span>2.1. </span>Parsing Ambiguity</h2>
|
|
|
|
<p>When the <a href="lang_insert.html">INSERT</a> statement to which the UPSERT is attached
|
|
takes its values from a <a href="lang_select.html">SELECT</a> statement, there is a potential
|
|
parsing ambiguity. The parser might not be able to tell if the
|
|
"ON" keyword is introducing the UPSERT or if it is the ON clause
|
|
of a join. To work around this, the SELECT statement should always
|
|
include a WHERE clause, even if that WHERE clause is just
|
|
"WHERE true".
|
|
|
|
</p><p>Ambiguous use of ON:
|
|
|
|
</p><blockquote><pre>
|
|
INSERT INTO t1 SELECT * FROM t2
|
|
ON CONFLICT(x) DO UPDATE SET y=excluded.y;
|
|
</pre></blockquote>
|
|
|
|
<p>Ambiguity resolved using a WHERE clause:
|
|
|
|
</p><blockquote><pre>
|
|
INSERT INTO t1 SELECT * FROM t2 <font color="blue">WHERE true</font>
|
|
ON CONFLICT(x) DO UPDATE SET y=excluded.y;
|
|
</pre></blockquote>
|
|
|
|
<h1 id="limitations"><span>3. </span>Limitations</h1>
|
|
|
|
<p>UPSERT does not currently work for <a href="vtab.html">virtual tables</a>.
|
|
</p>
|