29

Can anybody explain (or suggest a site or paper) the exact difference between triggers, assertions and checks, also describe where I should use them?

EDIT: I mean in database, not in any other systems or programing languages.

Am1rr3zA
  • 7,115
  • 18
  • 83
  • 125

5 Answers5

65

Triggers - a trigger is a piece of SQL to execute either before or after an update, insert, or delete in a database. An example of a trigger in plain English might be something like: before updating a customer record, save a copy of the current record. Which would look something like:

CREATE TRIGGER triggerName
AFTER UPDATE
    INSERT INTO CustomerLog (blah, blah, blah)
    SELECT blah, blah, blah FROM deleted

The difference between assertions and checks is a little more murky, many databases don't even support assertions.

Check Constraint - A check is a piece of SQL which makes sure a condition is satisfied before action can be taken on a record. In plain English this would be something like: All customers must have an account balance of at least $100 in their account. Which would look something like:

ALTER TABLE accounts 
ADD CONSTRAINT CK_minimumBalance
CHECK (balance >= 100)

Any attempt to insert a value in the balance column of less than 100 would throw an error.

Assertions - An assertion is a piece of SQL which makes sure a condition is satisfied or it stops action being taken on a database object. It could mean locking out the whole table or even the whole database.

To make matters more confusing - a trigger could be used to enforce a check constraint and in some DBs can take the place of an assertion (by allowing you to run code un-related to the table being modified). A common mistake for beginners is to use a check constraint when a trigger is required or a trigger when a check constraint is required.

An example: All new customers opening an account must have a balance of $100; however, once the account is opened their balance can fall below that amount. In this case you have to use a trigger because you only want the condition evaluated when a new record is inserted.

jellomonkey
  • 1,954
  • 15
  • 15
15

In the SQL standard, both ASSERTIONS and CHECK CONSTRAINTS are what relational theory calls "constraints" : rules that the data actually contained in the database must comply with.

The difference between the two is that CHECK CONSTRAINTS are, in a sense, much "simpler" : they are rules that relate to one single row only, while ASSERTIONs can involve any number of other tables, or any number of other rows in the same table. That obviously makes it (much !) more complex for the DBMS builders to support it, and that is, in turn, the reason why they don't : they just don't know how to do it.

TRIGGERs are pieces of executable code of which it can be declared to the DBMS that those should be executed every time a certain kind of update operation (insert/delete/update) gets done on a certain table. Because triggers can raise exceptions, they are a MEANS for implementing the same thing as an ASSERTION. However, with triggers, it's still the programmer who has to do all the coding, and not make any mistake.

EDIT

Onedaywhen's comments re. ASSERTION/CHECK cnstr. are correct. The difference is way more subtle (AND confusing). The standard indeed allows subqueries in CHECK constraints. (Most products don't support it though, so my "relate to a single row" is true for most SQL products, but not for the standard.) So is there still a difference ? Yes there still is. More than one even.

First case : TABLE MEN (ID:INTEGER) and TABLE WOMEN(ID:INTEGER). Now imagine a rule to the effect that "no ID value can appear both in the MEN and in the WOMEN table". That's a single rule. The intent of ASSERTION is precisely that the database designer would state this single rule [and be done with it], and the DBMS would know how to deal with this [efficiently, of course] and how to enforce this rule, no matter what particular update gets done to the database. In the example, the DBMS would know that it has to do a check for this rule upon INSERT INTO MEN, and upon INSERT INTO WOMEN, but not upon DELETE FROM MEN/WOMEN, or INSERT INTO <anyothertable>.

But DBMS's aren't smart enough for doing all that. So what needs to be done ? The database designer must add TWO CHECK constraints to his database, one to the MEN table (checking newly inserted MEN ID's against the WOMEN table) and one to the WOMAN table (checking the other way round). There's your first difference : one rule, one ASSERTION, TWO CHECK constraints. CHECK constraints are a lower level of abstraction than ASSERTIONs, because they require the designer to do more thinking himself about (a) all the kinds of update that could potentially cause his ASSERTION to be violated, and (b) what particular check should be carried out for any of the specific "kinds of update" he found in (a). (Although I don't really like making "absolute" statements on what is still "WHAT" and what is "HOW", I'd summarize that CHECK constraints require more "HOW" thinking (procedural) by the database designer, whereas ASSERTIONs allow the database designer to focus exclusively on the "WHAT" (declarative).)

Second case (though I'm not entirely sure of this - so take with a grain of salt) : just your average RI rule. Of course you are used to specify this using some REFERENCES clause. But imagine that a REFERENCES clause was not available. A rule like "Every ORDER must be placed by a known CUSTOMER" is really just that, a rule, thus : a single ASSERTION. However, we all know that such a rule can always be violated in two ways : inserting an ORDER (in this example), and deleting a CUSTOMER. Now, in line with the foregoing MAN/WOMEN example, if we wanted to implement this single rule/ASSERTION using CHECK constraints, then we'd have to write a CHECK constraint that checks CUSTOMER existence upon insertions into ORDER, but what CHECK constraint could we write that does whatever is needed upon deletion from CUSTOMER ? They simply aren't designed for that purpose, as far as I can tell. There's your second difference : CHECK constraints are tied to INSERTs exclusively, ASSERTIONS can define rules that will also be checked upon DELETEs.

Third case : Imagine a table COMPOS (componentID:... percentage:INTEGER), and a rule to the effect that "the sum of all percentages must at all times be equal to 100". That's a single rule, and an ASSERTION is capable of specifying that. But try and imagine how you would go about enforcing such a rule with CHECK constraints ... If you have a valid table with, say, three nonzero rows adding up to a hundred, how would you apply any change to this table that could survive your CHECK constraint ? You can't delete or update(decrease) any row without having to add other replacing rows, or update the remaining rows, that sum up to the same percentage. Likewise for insert or update (increase). You'd need deferred constraint checking at the very least, and then what are you going to CHECK ? There's your third difference : CHECK constraints are targeted to individual rows, while ASSERTIONs can also define/express rules that "span" several rows (i.e. rules about aggregations of rows).

Erwin Smout
  • 18,113
  • 4
  • 33
  • 52
  • `CHECK` constraints do not "relate to one single row only": they may contain subqueries to refer to multiple rows including rows in tables other than the one for which the `CHECK` was declared. The actual difference is that a `CHECK` is only tested when the table for which it was declared is updated, whereas an `ASSERTION` is tested regardless of the tables involved in the update. – onedaywhen Feb 06 '12 at 08:46
  • "the reason why they don't [implement constraints involving more than one row is] they just don't know how to do it" -- I rather think the truth is they don't know how to do it efficiently using their legacy technology. For example, they *could* map a table-level check constraint to a trigger, however they get users to write the trigger hence fail to take responsibly for the resulting poor performance. Or they could rewrite their products from the ground up using new algorithms ;) – onedaywhen Feb 06 '12 at 08:51
  • 1
    "Efficiently" was of course assumed prerequisite. Even my cat knows "how to do it" if "efficiently" is not part of the requirements :-) – Erwin Smout Feb 06 '12 at 16:18
  • You were right about the CHECK constraints. Any remarks to my edits are welcome. – Erwin Smout Feb 06 '12 at 16:22
  • Second case: I don't think that is correct. The constraint could be `CHECK ( NOT EXISTS ( SELECT customer_ID FROM ORDER EXCEPT SELECT customer_ID FROM CUSTOMER )` and if this was applied as two `CHECK` constraints -- one on `ORDER` and one on `CUSTOMER` respectively -- then it would do the same as a FK constraint i.e. would be checked after any update (`INSERT/UPDATE/DELETE`) to either table. What a constraint cannot do, of course, is the referential actions `ON DELETE SET NULL`, `ON UPDATE CASCADE`, etc. – onedaywhen Feb 07 '12 at 06:55
  • Third case: I don't think that is correct: a `CHECK` can also "span several rows" e.g. could be `CHECK ( 100 = ( SELECT SUM ( percentage ) FROM COMPOS ) )`. You are correct that such a constraint would need to be deferrable to be usable. One interesting point is that a constraint will not evaluate to false (hence does not 'bite') when the table is empty... – onedaywhen Feb 07 '12 at 07:01
  • Say the constraint is not deferrable and the table is empty. Assume another table `DUAL` with rows. If the user did this: `INSERT INTO COMPOS ( componentID, percentage ) SELECT componentID, percentage FROM ( SELECT DISTINCT 1, 50 FROM DUAL UNION SELECT DISTINCT 2, 50 FROM DUAL ) AS DT1;` -- that is, inserted two rows in the same SQL statement, the aforementioned `CHECK` should not bite. However, in MS Access it does bite, proving that constraint checking is done on a row-by-row basis but contrary to the SQL Standard and usability... – onedaywhen Feb 07 '12 at 07:07
  • ...SQL Server suffers the same problem when using UDFs in `CHECK` constraints to circumvent the 'no subqueries' restriction. This is what I mean by the problem of 'legacy technology': the row-by-row constraint checking is a 'feature' of the implementation and not how constraint checking is supposed to work. – onedaywhen Feb 07 '12 at 07:10
  • [This article](http://consultingblogs.emc.com/davidportas/archive/2007/03/22/Deferrable-Constraints.aspx) demonstrates the aforementioned UDF problem in SQL Server. (Interestingly, you, me, the author of that article, and the guy name-checked in the first sentence, all supplied answers to [this SO question](http://stackoverflow.com/questions/7633108/which-normal-form-does-this-table-violate/7651968#7651968)!) – onedaywhen Feb 08 '12 at 08:49
  • 1
    "Interestingly, you, me, the author ..., all supplied answers to this SO question!" You can bet there will be a few more of those. (And if Stackoverflow supported Relational Division, we could easily search for them !!!!!!!) Relationland is not a big swimming pool, with not too many swimmers ... (And David is certainly among the more respectable ones.) – Erwin Smout Feb 08 '12 at 12:35
  • 1
    I was intrigued by your further comments re. CHECK constraints. There seems to be indeed nothing in the standard that says that a CHECK is targeted at the individual row level. Curiously, there also doesn't seem to be anything that says explicitly that a CHECK is targeted at the TABLE level !!!!!!! What IS most certain, is that constructs that are sometimes available inside the context of CHECK constraint expressions (e.g. Oracle's :new.) are most certainly targeted at the row level, and most certainly completely incompatible with targeting the table level). ... – Erwin Smout Feb 08 '12 at 12:39
7

Assertions do not modify the data, they only check certain conditions

Triggers are more powerful because the can check conditions and also modify the data


Assertions are not linked to specific tables in the database and not linked to specific events

Triggers are linked to specific tables and specific events

Andre
  • 26,751
  • 7
  • 36
  • 80
Mohamed Adel
  • 1,980
  • 17
  • 23
  • Thanks. What do "assesions not linked to specific tables" while "triggers linked to specific tables" mean? –  Jul 10 '18 at 02:27
3

A database constraint involves a condition that must be satisfied when the database is updated. In SQL, if a constraint condition evaluates to false then the update fails, the data remains unchanged and the DBMS generates an error.

Both CHECK and ASSERTION are database constraints defined by the SQL standards. An important distinction is that a CHECK is applied to a specific base table, whereas an ASSERTION is applied to the whole database. Consider a constraint that limits the combined rows in tables T1 and T2 to a total of 10 rows e.g.

CHECK (10 >= (
              SELECT COUNT(*)
                FROM (
                      SELECT *
                        FROM T1
                      UNION
                      SELECT * 
                        FROM T2
                     ) AS Tn
             ))

Assume the tables are empty. If this was applied as an ASSERTION only and a user tried to insert 11 rows into T1 then then the update would fail. The same would apply if the constraint was applied as a CHECK constraint to T1 only. However, if the constraint was applied as a CHECK constraint to T2 only the constraint would succeed because a statement targeting T1 does not cause the constraints applied to T1 to be tested.

Both an ASSERTION and a CHECK may be deferred (if declared as DEFERRABLE), allowing for data to temporarily violate the constraint condition, but only within a transaction.

ASSERTION and CHECK constraints involving subqueries are features outside of core Standard SQL and none of the major SQL products support these features. MS Access (not exactly an industrial-strength product) supports CHECK constraints involving subqueries but not deferrable constraints plus constraint testing is always performed on a row-by-row basis, the practical consequences being that the functionality is very limited.

In common with CHECK constraints, a trigger is applied to a specific table. Therefore, a trigger can be used to implement the same logic as a CHECK constraint but not an ASSERTION. A trigger is procedural code and, unlike constraints, the user must take far more responsibility for concerns such as performance and error handling. Most commercial SQL products support triggers (the aforementioned MS Access does not).

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
onedaywhen
  • 55,269
  • 12
  • 100
  • 138
  • a CHECK is applied to a specific base table, whereas a CHECK constraint is applied to the whole database, I think one of the CHECK must replace with Assertion. – Am1rr3zA Feb 06 '12 at 09:50
0

The expression should be true for trigger to fire, but check will be evaluated wherever the expression is false.

Feri
  • 230
  • 4
  • 11