589 lines
27 KiB
HTML
589 lines
27 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>CREATE TRIGGER</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">
|
|
CREATE TRIGGER
|
|
</div>
|
|
<div class="fancy_toc">
|
|
<a onclick="toggle_toc()">
|
|
<span class="fancy_toc_mark" id="toc_mk">►</span>
|
|
Table Of Contents
|
|
</a>
|
|
<div id="toc_sub"><div class="fancy-toc1"><a href="#syntax">1. Syntax</a></div>
|
|
<div class="fancy-toc1"><a href="#description">2. Description</a></div>
|
|
<div class="fancy-toc2"><a href="#syntax_restrictions_on_update_delete_and_insert_statements_within_triggers">2.1. Syntax Restrictions On UPDATE, DELETE, and INSERT Statements Within
|
|
Triggers</a></div>
|
|
<div class="fancy-toc1"><a href="#instead_of_triggers">3. INSTEAD OF triggers</a></div>
|
|
<div class="fancy-toc1"><a href="#some_example_triggers">4. Some Example Triggers</a></div>
|
|
<div class="fancy-toc1"><a href="#cautions_on_the_use_of_before_triggers">5. Cautions On The Use Of BEFORE triggers</a></div>
|
|
<div class="fancy-toc1"><a href="#the_raise_function">6. The RAISE() function</a></div>
|
|
<div class="fancy-toc1"><a href="#temp_triggers_on_non_temp_tables">7. TEMP Triggers on Non-TEMP Tables</a></div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
function toggle_toc(){
|
|
var sub = document.getElementById("toc_sub")
|
|
var mk = document.getElementById("toc_mk")
|
|
if( sub.style.display!="block" ){
|
|
sub.style.display = "block";
|
|
mk.innerHTML = "▼";
|
|
} else {
|
|
sub.style.display = "none";
|
|
mk.innerHTML = "►";
|
|
}
|
|
}
|
|
</script>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<h1 id="syntax"><span>1. </span>Syntax</h1>
|
|
|
|
<p><b><a href="syntax/create-trigger-stmt.html">create-trigger-stmt:</a></b>
|
|
<button id='x1461' onclick='hideorshow("x1461","x1462")'>hide</button></p>
|
|
<div id='x1462' class='imgcontainer'>
|
|
<img alt="syntax diagram create-trigger-stmt" src="images/syntax/create-trigger-stmt.gif" />
|
|
<p><b><a href="syntax/delete-stmt.html">delete-stmt:</a></b>
|
|
<button id='x1463' onclick='hideorshow("x1463","x1464")'>show</button></p>
|
|
<div id='x1464' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram delete-stmt" src="images/syntax/delete-stmt.gif" />
|
|
<p><b><a href="syntax/common-table-expression.html">common-table-expression:</a></b>
|
|
<button id='x1465' onclick='hideorshow("x1465","x1466")'>show</button></p>
|
|
<div id='x1466' 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/qualified-table-name.html">qualified-table-name:</a></b>
|
|
<button id='x1467' onclick='hideorshow("x1467","x1468")'>show</button></p>
|
|
<div id='x1468' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram qualified-table-name" src="images/syntax/qualified-table-name.gif" />
|
|
</div>
|
|
</div>
|
|
<p><b><a href="syntax/expr.html">expr:</a></b>
|
|
<button id='x1469' onclick='hideorshow("x1469","x1470")'>show</button></p>
|
|
<div id='x1470' 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='x1471' onclick='hideorshow("x1471","x1472")'>show</button></p>
|
|
<div id='x1472' 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='x1473' onclick='hideorshow("x1473","x1474")'>show</button></p>
|
|
<div id='x1474' 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='x1475' onclick='hideorshow("x1475","x1476")'>show</button></p>
|
|
<div id='x1476' 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='x1477' onclick='hideorshow("x1477","x1478")'>show</button></p>
|
|
<div id='x1478' 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='x1479' onclick='hideorshow("x1479","x1480")'>show</button></p>
|
|
<div id='x1480' 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='x1481' onclick='hideorshow("x1481","x1482")'>show</button></p>
|
|
<div id='x1482' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram raise-function" src="images/syntax/raise-function.gif" />
|
|
</div>
|
|
<p><b><a href="syntax/type-name.html">type-name:</a></b>
|
|
<button id='x1483' onclick='hideorshow("x1483","x1484")'>show</button></p>
|
|
<div id='x1484' 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='x1485' onclick='hideorshow("x1485","x1486")'>show</button></p>
|
|
<div id='x1486' 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/insert-stmt.html">insert-stmt:</a></b>
|
|
<button id='x1487' onclick='hideorshow("x1487","x1488")'>show</button></p>
|
|
<div id='x1488' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram insert-stmt" src="images/syntax/insert-stmt.gif" />
|
|
<p><b><a href="syntax/common-table-expression.html">common-table-expression:</a></b>
|
|
<button id='x1489' onclick='hideorshow("x1489","x1490")'>show</button></p>
|
|
<div id='x1490' 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/upsert-clause.html">upsert-clause:</a></b>
|
|
<button id='x1491' onclick='hideorshow("x1491","x1492")'>show</button></p>
|
|
<div id='x1492' style='display:none;' 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='x1493' onclick='hideorshow("x1493","x1494")'>show</button></p>
|
|
<div id='x1494' 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/indexed-column.html">indexed-column:</a></b>
|
|
<button id='x1495' onclick='hideorshow("x1495","x1496")'>show</button></p>
|
|
<div id='x1496' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram indexed-column" src="images/syntax/indexed-column.gif" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p><b><a href="syntax/select-stmt.html">select-stmt:</a></b>
|
|
<button id='x1497' onclick='hideorshow("x1497","x1498")'>show</button></p>
|
|
<div id='x1498' 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='x1499' onclick='hideorshow("x1499","x1500")'>show</button></p>
|
|
<div id='x1500' 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='x1501' onclick='hideorshow("x1501","x1502")'>show</button></p>
|
|
<div id='x1502' 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='x1503' onclick='hideorshow("x1503","x1504")'>show</button></p>
|
|
<div id='x1504' 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='x1505' onclick='hideorshow("x1505","x1506")'>show</button></p>
|
|
<div id='x1506' 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='x1507' onclick='hideorshow("x1507","x1508")'>show</button></p>
|
|
<div id='x1508' 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='x1509' onclick='hideorshow("x1509","x1510")'>show</button></p>
|
|
<div id='x1510' 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='x1511' onclick='hideorshow("x1511","x1512")'>show</button></p>
|
|
<div id='x1512' 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='x1513' onclick='hideorshow("x1513","x1514")'>show</button></p>
|
|
<div id='x1514' 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='x1515' onclick='hideorshow("x1515","x1516")'>show</button></p>
|
|
<div id='x1516' 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='x1517' onclick='hideorshow("x1517","x1518")'>show</button></p>
|
|
<div id='x1518' 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/update-stmt.html">update-stmt:</a></b>
|
|
<button id='x1519' onclick='hideorshow("x1519","x1520")'>show</button></p>
|
|
<div id='x1520' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram update-stmt" src="images/syntax/update-stmt.gif" />
|
|
<p><b><a href="syntax/column-name-list.html">column-name-list:</a></b>
|
|
<button id='x1521' onclick='hideorshow("x1521","x1522")'>show</button></p>
|
|
<div id='x1522' 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/common-table-expression.html">common-table-expression:</a></b>
|
|
<button id='x1523' onclick='hideorshow("x1523","x1524")'>show</button></p>
|
|
<div id='x1524' 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/join-clause.html">join-clause:</a></b>
|
|
<button id='x1525' onclick='hideorshow("x1525","x1526")'>show</button></p>
|
|
<div id='x1526' 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='x1527' onclick='hideorshow("x1527","x1528")'>show</button></p>
|
|
<div id='x1528' 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='x1529' onclick='hideorshow("x1529","x1530")'>show</button></p>
|
|
<div id='x1530' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram join-operator" src="images/syntax/join-operator.gif" />
|
|
</div>
|
|
</div>
|
|
<p><b><a href="syntax/qualified-table-name.html">qualified-table-name:</a></b>
|
|
<button id='x1531' onclick='hideorshow("x1531","x1532")'>show</button></p>
|
|
<div id='x1532' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram qualified-table-name" src="images/syntax/qualified-table-name.gif" />
|
|
</div>
|
|
<p><b><a href="syntax/table-or-subquery.html">table-or-subquery:</a></b>
|
|
<button id='x1533' onclick='hideorshow("x1533","x1534")'>show</button></p>
|
|
<div id='x1534' style='display:none;' class='imgcontainer'>
|
|
<img alt="syntax diagram table-or-subquery" src="images/syntax/table-or-subquery.gif" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<h1 id="description"><span>2. </span>Description</h1>
|
|
<p>The CREATE TRIGGER statement is used to add triggers to the
|
|
database schema. Triggers are database operations
|
|
that are automatically performed when a specified database event
|
|
occurs. </p>
|
|
|
|
<p>Each trigger must specify that it will fire for one of
|
|
the following operations: <a href="lang_delete.html">DELETE</a>, <a href="lang_insert.html">INSERT</a>, <a href="lang_update.html">UPDATE</a>.
|
|
The trigger fires once for each row that is deleted, inserted,
|
|
or updated. If the "UPDATE OF <span class='yyterm'>column-name</span>"
|
|
syntax is used, then the trigger will only fire if
|
|
<span class='yyterm'>column-name</span> appears on the left-hand side of
|
|
one of the terms in the SET clause of the <a href="lang_update.html">UPDATE</a> statement.</p>
|
|
|
|
<p>Due to an historical oversight, columns named in the "UPDATE OF"
|
|
clause do not actually have to exist in the table being updated.
|
|
Unrecognized column names are silently ignored.
|
|
It would be more helpful if SQLite would fail the CREATE TRIGGER
|
|
statement if any of the names in the "UPDATE OF" clause are not
|
|
columns in the table. However, as this problem was discovered
|
|
many years after SQLite was widely deployed, we have resisted
|
|
fixing the problem for fear of breaking legacy applications.</p>
|
|
|
|
<p>At this time SQLite supports only FOR EACH ROW triggers, not FOR EACH
|
|
STATEMENT triggers. Hence explicitly specifying FOR EACH ROW is optional.
|
|
FOR EACH ROW implies that the SQL statements specified in the trigger
|
|
may be executed (depending on the WHEN clause) for each database row being
|
|
inserted, updated or deleted by the statement causing the trigger to fire.</p>
|
|
|
|
<p>Both the WHEN clause and the trigger actions may access elements of
|
|
the row being inserted, deleted or updated using references of the form
|
|
"NEW.<i>column-name</i>" and "OLD.<i>column-name</i>", where
|
|
<i>column-name</i> is the name of a column from the table that the trigger
|
|
is associated with. OLD and NEW references may only be used in triggers on
|
|
events for which they are relevant, as follows:</p>
|
|
|
|
<table border="0" cellpadding="10">
|
|
<tr>
|
|
<td valign="top" align="right" width="120"><i>INSERT</i></td>
|
|
<td valign="top">NEW references are valid</td>
|
|
</tr>
|
|
<tr>
|
|
<td valign="top" align="right" width="120"><i>UPDATE</i></td>
|
|
<td valign="top">NEW and OLD references are valid</td>
|
|
</tr>
|
|
<tr>
|
|
<td valign="top" align="right" width="120"><i>DELETE</i></td>
|
|
<td valign="top">OLD references are valid</td>
|
|
</tr>
|
|
</table>
|
|
|
|
|
|
<p>If a WHEN clause is supplied, the SQL statements specified
|
|
are only executed if the WHEN clause is true.
|
|
If no WHEN clause is supplied, the SQL statements
|
|
are executed every time the trigger fires.</p>
|
|
|
|
<p>The BEFORE or AFTER keyword determines when the trigger actions
|
|
will be executed relative to the insertion, modification or removal of the
|
|
associated row. BEFORE is the default when neither keyword is present.</p>
|
|
|
|
<p>An <a href="lang_conflict.html">ON CONFLICT</a> clause may be specified as part of an <a href="lang_update.html">UPDATE</a> or <a href="lang_insert.html">INSERT</a>
|
|
action within the body of the trigger.
|
|
However if an <a href="lang_conflict.html">ON CONFLICT</a> clause is specified as part of
|
|
the statement causing the trigger to fire, then conflict handling
|
|
policy of the outer statement is used instead.</p>
|
|
|
|
<p>Triggers are automatically <a href="lang_droptrigger.html">dropped</a>
|
|
when the table that they are
|
|
associated with (the <i>table-name</i> table) is
|
|
<a href="lang_droptable.html">dropped</a>. However if the trigger actions reference
|
|
other tables, the trigger is not dropped or modified if those other
|
|
tables are <a href="lang_droptable.html">dropped</a> or <a href="lang_altertable.html">modified</a>.</p>
|
|
|
|
<p>Triggers are removed using the <a href="lang_droptrigger.html">DROP TRIGGER</a> statement.</p>
|
|
|
|
<h2 id="syntax_restrictions_on_update_delete_and_insert_statements_within_triggers"><span>2.1. </span>Syntax Restrictions On UPDATE, DELETE, and INSERT Statements Within
|
|
Triggers</h2>
|
|
|
|
<p>The <a href="lang_update.html">UPDATE</a>, <a href="lang_delete.html">DELETE</a>, and <a href="lang_insert.html">INSERT</a>
|
|
statements within triggers do not support
|
|
the full syntax for <a href="lang_update.html">UPDATE</a>, <a href="lang_delete.html">DELETE</a>, and <a href="lang_insert.html">INSERT</a> statements. The following
|
|
restrictions apply:</p>
|
|
|
|
<ul>
|
|
<li><p>
|
|
The name of the table to be modified in an <a href="lang_update.html">UPDATE</a>, <a href="lang_delete.html">DELETE</a>, or <a href="lang_insert.html">INSERT</a>
|
|
statement must be an unqualified table name. In other words, one must
|
|
use just "<i>tablename</i>" not "<i>database</i><b>.</b><i>tablename</i>"
|
|
when specifying the table. </p></li>
|
|
|
|
<li><p>
|
|
For non-TEMP triggers,
|
|
the table to be modified or queried must exist in the
|
|
same database as the table or view to which the trigger is attached.
|
|
TEMP triggers are not subject to the same-database rule. A TEMP
|
|
trigger is allowed to query or modify any table in any <a href="lang_attach.html">ATTACH</a>-ed database.
|
|
</p></li>
|
|
|
|
<li><p>
|
|
The "INSERT INTO <i>table</i> DEFAULT VALUES" form of the <a href="lang_insert.html">INSERT</a> statement
|
|
is not supported.
|
|
</p></li>
|
|
|
|
<li><p>
|
|
The INDEXED BY and NOT INDEXED clauses are not supported for <a href="lang_update.html">UPDATE</a> and
|
|
<a href="lang_delete.html">DELETE</a> statements.
|
|
</p></li>
|
|
|
|
<li><p>
|
|
The ORDER BY and LIMIT clauses on <a href="lang_update.html">UPDATE</a> and <a href="lang_delete.html">DELETE</a> statements are not
|
|
supported. ORDER BY and LIMIT are not normally supported for <a href="lang_update.html">UPDATE</a> or
|
|
<a href="lang_delete.html">DELETE</a> in any context but can be enabled for top-level statements
|
|
using the <a href="compile.html#enable_update_delete_limit">SQLITE_ENABLE_UPDATE_DELETE_LIMIT</a> compile-time option. However,
|
|
that compile-time option only applies to top-level <a href="lang_update.html">UPDATE</a> and <a href="lang_delete.html">DELETE</a>
|
|
statements, not <a href="lang_update.html">UPDATE</a> and <a href="lang_delete.html">DELETE</a> statements within triggers.
|
|
</p></li>
|
|
|
|
<li><p>
|
|
<a href="syntax/common-table-expression.html">Common table expression</a> are not supported for
|
|
statements inside of triggers.
|
|
</p></li>
|
|
</ul>
|
|
|
|
<a name="instead_of_trigger"></a>
|
|
|
|
<h1 id="instead_of_triggers"><span>3. </span>INSTEAD OF triggers</h1>
|
|
|
|
<p>Triggers may be created on <a href="lang_createview.html">views</a>, as well as ordinary tables, by
|
|
specifying INSTEAD OF in the CREATE TRIGGER statement.
|
|
If one or more ON INSERT, ON DELETE
|
|
or ON UPDATE triggers are defined on a view, then it is not an
|
|
error to execute an INSERT, DELETE or UPDATE statement on the view,
|
|
respectively. Instead,
|
|
executing an INSERT, DELETE or UPDATE on the view causes the associated
|
|
triggers to fire. The real tables underlying the view are not modified
|
|
(except possibly explicitly, by a trigger program).</p>
|
|
|
|
<p>Note that the <a href="c3ref/changes.html">sqlite3_changes()</a> and <a href="c3ref/total_changes.html">sqlite3_total_changes()</a> interfaces
|
|
do not count INSTEAD OF trigger firings, but the
|
|
<a href="pragma.html#pragma_count_changes">count_changes pragma</a> does count INSTEAD OF trigger firing.</p>
|
|
|
|
<h1 id="some_example_triggers"><span>4. </span>Some Example Triggers</h1>
|
|
|
|
<p>Assuming that customer records are stored in the "customers" table, and
|
|
that order records are stored in the "orders" table, the following
|
|
UPDATE trigger
|
|
ensures that all associated orders are redirected when a customer changes
|
|
his or her address:</p>
|
|
|
|
<blockquote><pre>
|
|
CREATE TRIGGER update_customer_address UPDATE OF address ON customers
|
|
BEGIN
|
|
UPDATE orders SET address = new.address WHERE customer_name = old.name;
|
|
END;
|
|
</pre></blockquote>
|
|
|
|
<p>With this trigger installed, executing the statement:</p>
|
|
|
|
<blockquote><pre>
|
|
UPDATE customers SET address = '1 Main St.' WHERE name = 'Jack Jones';
|
|
</pre></blockquote>
|
|
|
|
<p>causes the following to be automatically executed:</p>
|
|
|
|
<blockquote><pre>
|
|
UPDATE orders SET address = '1 Main St.' WHERE customer_name = 'Jack Jones';
|
|
</pre></blockquote>
|
|
|
|
<p>For an example of an INSTEAD OF trigger, consider the following schema:
|
|
|
|
<blockquote><pre>
|
|
CREATE TABLE customer(
|
|
cust_id INTEGER PRIMARY KEY,
|
|
cust_name TEXT,
|
|
cust_addr TEXT
|
|
);
|
|
CREATE VIEW customer_address AS
|
|
SELECT cust_id, cust_addr FROM customer;
|
|
CREATE TRIGGER cust_addr_chng
|
|
INSTEAD OF UPDATE OF cust_addr ON customer_address
|
|
BEGIN
|
|
UPDATE customer SET cust_addr=NEW.cust_addr
|
|
WHERE cust_id=NEW.cust_id;
|
|
END;
|
|
</pre></blockquote>
|
|
|
|
</p><p>With the schema above, a statement of the form:</p>
|
|
|
|
<blockquote><pre>
|
|
UPDATE customer_address SET cust_addr=$new_address WHERE cust_id=$cust_id;
|
|
</pre></blockquote>
|
|
|
|
<p>Causes the customer.cust_addr field to be updated for a specific
|
|
customer entry that has customer.cust_id equal to the $cust_id parameter.
|
|
Note how the values assigned to the view are made available as field
|
|
in the special "NEW" table within the trigger body.</p>
|
|
|
|
<a name="undef_before"></a>
|
|
|
|
<h1 id="cautions_on_the_use_of_before_triggers"><span>5. </span>Cautions On The Use Of BEFORE triggers</h1>
|
|
|
|
<p>If a BEFORE UPDATE or BEFORE DELETE trigger modifies or deletes a row
|
|
that was to have been updated or deleted, then the result of the subsequent
|
|
update or delete operation is undefined. Furthermore, if a BEFORE trigger
|
|
modifies or deletes a row, then it is undefined whether or not AFTER triggers
|
|
that would have otherwise run on those rows will in fact run.
|
|
</p>
|
|
|
|
<p>The value of NEW.rowid is undefined in a BEFORE INSERT trigger in which
|
|
the rowid is not explicitly set to an integer.</p>
|
|
|
|
<p>Because of the behaviors described above, programmers are encouraged to
|
|
prefer AFTER triggers over BEFORE triggers.</p>
|
|
|
|
<a name="raise"></a>
|
|
|
|
<h1 id="the_raise_function"><span>6. </span>The RAISE() function</h1>
|
|
|
|
<p>A special SQL function RAISE() may be used within a trigger-program,
|
|
with the following syntax</p>
|
|
|
|
<p><b><a href="syntax/raise-function.html">raise-function:</a></b></p><div class='imgcontainer'>
|
|
<img alt="syntax diagram raise-function" src="images/syntax/raise-function.gif"></img>
|
|
</div>
|
|
|
|
|
|
<p>When one of RAISE(ROLLBACK,...), RAISE(ABORT,...) or RAISE(FAIL,...)
|
|
is called during trigger-program
|
|
execution, the specified <a href="lang_conflict.html">ON CONFLICT</a> processing is performed and
|
|
the current query terminates.
|
|
An error code of <a href="rescode.html#constraint">SQLITE_CONSTRAINT</a> is returned to the application,
|
|
along with the specified error message.</p>
|
|
|
|
<p>When RAISE(IGNORE) is called, the remainder of the current trigger program,
|
|
the statement that caused the trigger program to execute and any subsequent
|
|
trigger programs that would have been executed are abandoned. No database
|
|
changes are rolled back. If the statement that caused the trigger program
|
|
to execute is itself part of a trigger program, then that trigger program
|
|
resumes execution at the beginning of the next step.
|
|
</p>
|
|
|
|
<a name="temptrig"></a>
|
|
|
|
<h1 id="temp_triggers_on_non_temp_tables"><span>7. </span>TEMP Triggers on Non-TEMP Tables</h1>
|
|
|
|
<p>A trigger normally exists in the same database as the table named
|
|
after the "ON" keyword in the CREATE TRIGGER statement. Except, it is
|
|
possible to create a TEMP TRIGGER on a table in another database.
|
|
Such a trigger will only fire when changes
|
|
are made to the target table by the application that defined the trigger.
|
|
Other applications that modify the database will not be able to see the
|
|
TEMP trigger and hence cannot run the trigger.</p>
|
|
|
|
<p>When defining a TEMP trigger on a non-TEMP table, it is important to
|
|
specify the database holding the non-TEMP table. For example,
|
|
in the following statement, it is important to say "main.tab1" instead
|
|
of just "tab1":</p>
|
|
|
|
<blockquote><pre>
|
|
CREATE TEMP TRIGGER ex1 AFTER INSERT ON <b>main.</b>tab1 BEGIN ...
|
|
</pre></blockquote>
|
|
|
|
<p>Failure to specify the schema name on the target table could result
|
|
in the TEMP trigger being reattached to a table with the same name in
|
|
another database whenever any schema change occurs.</p>
|
|
|