{"id":97823,"date":"2023-09-07T16:54:22","date_gmt":"2023-09-07T16:54:22","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=97823"},"modified":"2024-02-04T05:15:01","modified_gmt":"2024-02-04T05:15:01","slug":"working-with-mysql-constraints","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/working-with-mysql-constraints\/","title":{"rendered":"MySQL Constraints Guide: PRIMARY KEY, FOREIGN KEY, NOT NULL, DEFAULT, and CHECK Constraints with Examples"},"content":{"rendered":"<p><strong>This article is part of Robert Sheldon's continuing series on Learning MySQL. To see all of the items in the series, <a href=\"https:\/\/www.red-gate.com\/simple-talk\/mysql-coding-basics\/\">click here<\/a>.<\/strong><\/p>\n\n<p>MySQL provides a set of constraints that you can include in your table definitions to help ensure the integrity of the data. The constraints let you better control the types of data that can be added to the database. For example, you can use constraints to set a column\u2019s uniqueness or nullability, specify a default value for a column, or verify that the data falls within a certain range of acceptable values.<\/p>\n<p>MySQL supports six basic types of constraints for ensuring data integrity: <code>PRIMARY<\/code> <code>KEY<\/code>, <code>NOT<\/code> <code>NULL<\/code>, <code>DEFAULT<\/code>, <code>CHECK<\/code>, <code>UNIQUE<\/code>, and <code>FOREIGN<\/code> <code>KEY<\/code>. In this article, I introduce you to each constraint type and provide examples for how they work. The examples include a series of <code>CREATE<\/code> <code>TABLE<\/code> statements that demonstrate different ways to incorporate constraints into your table definitions. If you\u2019re not familiar with the <code>CREATE<\/code> <code>TABLE<\/code> statement or how to create tables in a MySQL database, refer to an <a href=\"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/working-mysql-tables\/\">earlier article<\/a> in this series that introduces you to the statement.<\/p>\n<p>Some resources also consider data types to be constraints because they limit the types of data that can be inserted into a table\u2019s columns. For example, a column configured with an integer data type will take whole numbers but not decimals or string values. I do not cover data types in this article and instead focus only the six other constraint types. For information about data types, see the MySQL article <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/data-types.html\">Data Types<\/a>.<\/p>\n<p>Note: The examples in this article are based on a local instance of MySQL that hosts a very simple database. The last section of the article\u2014\u201cAppendix: Preparing your MySQL environment\u201d\u2014provides information about how I set up my environment and includes a SQL script for creating the database I used when building these examples.<\/p>\n<h2><strong>PRIMARY<\/strong> <strong>KEY<\/strong> constraints<\/h2>\n<p>A <code>PRIMARY<\/code> <code>KEY<\/code> constraint provides a mechanism for uniquely identifying each row in a table. It is defined on one or more of a table\u2019s columns (the key columns) to ensure the row\u2019s uniqueness. When you add a <code>PRIMARY<\/code> <code>KEY<\/code> constraint to a table, MySQL also creates a unique index on the key columns to enforce their uniqueness.<\/p>\n<p>A table can have only one primary key, and the key columns must be defined as <code>NOT<\/code> <code>NULL<\/code>. If they are not explicitly defined as <code>NOT<\/code> <code>NULL<\/code>, MySQL implicitly declares them as such to ensure that each row in the table has an associated primary key value. This is important because a unique index on its own can contain multiple <code>NULL<\/code> values, so <code>NOT<\/code> <code>NULL<\/code> is needed to guarantee that a unique identifier is associated with each row.<\/p>\n<p>You can add a primary key to a table when you create the table. The easiest way to add a single-column primary key is to include it in the column definition, as in the following example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">DROP TABLE IF EXISTS airplanes; \r\n\r\nCREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED PRIMARY KEY,\r\n  plane VARCHAR(50),\r\n  engine_type VARCHAR(50),\r\n  engine_count TINYINT);<\/pre>\n<p>The statement creates a primary key on the <code>plane_id<\/code> column. The column\u2019s definition includes the <code>PRIMARY<\/code> <code>KEY<\/code> keywords, which tells MySQL to create a <code>PRIMARY<\/code> <code>KEY<\/code> constraint on that column when creating the <code>airplanes<\/code> table. MySQL creates the unique index at the same time.<\/p>\n<p>That\u2019s all you need to do to create a primary key. MySQL does the rest. If you want to create a primary key on multiple columns, you must define it separately from the column definition, which I\u2019ll be discussing shortly.<\/p>\n<p><em>Note: The <\/em><code><em>CREATE<\/em><\/code> <code><em>TABLE<\/em><\/code><em> statement in this example is preceded by a <\/em><code><em>DROP<\/em><\/code> <code><em>TABLE<\/em><\/code><em> statement that includes the <\/em><code><em>IF<\/em><\/code> <code><em>EXISTS<\/em><\/code><em> option. Because the examples in this article re-create the <\/em><code><em>airplanes<\/em><\/code><em> table, you should precede each example with the <\/em><code><em>DROP<\/em><\/code> <code><em>TABLE<\/em><\/code><em> statement if trying out the examples for yourself. Although I won\u2019t be repeating the <\/em><code><em>DROP<\/em><\/code> <code><em>TABLE<\/em><\/code><em> statement going forward, this is the approach I used when I created and tested the examples for this article.<\/em><\/p>\n<p>MySQL tracks all constraints defined on all the tables in a database. You can view the constraints by querying the <code>TABLE_CONSTRAINTS<\/code> table in the <code>INFORMATION_SCHEMA<\/code>, which tracks all database metadata. The following <code>SELECT<\/code> statement retrieves information about existing constraints in the <code>travel<\/code> database:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT table_name, constraint_name, constraint_type\r\nFROM information_schema.table_constraints\r\nWHERE constraint_schema = 'travel';<\/pre>\n<p>The statement returns the results shown in the following figure. The results indicate that <code>PRIMARY<\/code> <code>KEY<\/code> constraints have been defined on the <code>airplanes<\/code> table and <code>manufacturers<\/code> table, which was created as part of the setup for this article.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1042\" height=\"288\" class=\"wp-image-97824\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/08\/word-image-97823-1.png\" \/><\/p>\n<p>MySQL automatically assigns the name <code>PRIMARY<\/code> to each primary key constraint and to its associated unique index. Unlike other types of constraints, you cannot change these names. In addition, you should not use the name <code>PRIMARY<\/code> for any other indexes you create.<\/p>\n<p>You can verify the <code>PRIMARY<\/code> <code>KEY<\/code> constraint in the <code>airplanes<\/code> table by running the following <code>INSERT<\/code> statement twice in a row:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, plane, engine_type, engine_count)\r\nVALUES (1001,'A340-600','Jet',4);<\/pre>\n<p>The first time you run the statement, MySQL inserts the data with no problem, but when you run the same statement a second time, MySQL returns the following error because you violated the <code>PRIMARY<\/code> <code>KEY<\/code> constraint:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">Error Code: 1062. Duplicate entry '1001' for key 'airplanes.PRIMARY'<\/pre>\n<p>Another method you can use to define a <code>PRIMARY<\/code> <code>KEY<\/code> constraint is to add a separate constraint definition after the column definitions, as in the following example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED,\r\n  plane VARCHAR(50),\r\n  engine_type VARCHAR(50),\r\n  engine_count TINYINT,\r\n  PRIMARY KEY (plane_id));<\/pre>\n<p>This <code>CREATE<\/code> <code>TABLE<\/code> statement achieves the same results as the previous <code>CREATE<\/code> <code>TABLE<\/code> statement. In this case, however, you must specify the column on which the primary key will be created. MySQL will then create a <code>PRIMARY<\/code> <code>KEY<\/code> constraint on <code>plane_id<\/code> column, naming the constraint and index <code>PRIMARY<\/code>.<\/p>\n<p>In some cases, you might want to create a <code>PRIMARY<\/code> <code>KEY<\/code> constraint on multiple columns. For example, you might have two columns in a table that do no uniquely identify each row individually, but together they do. In the following example, the <code>CREATE<\/code> <code>TABLE<\/code> statement defines a primary key on the <code>plane_id<\/code> and <code>alt_id<\/code> columns:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED,\r\n  alt_id INT UNSIGNED,\r\n  plane VARCHAR(50),\r\n  engine_type VARCHAR(50),\r\n  engine_count TINYINT,\r\n  PRIMARY KEY (plane_id, alt_id));<\/pre>\n<p>A primary key made up of multiple columns is sometimes referred to as a <em>composite<\/em> primary key. The need to use composite primary keys depends on the nature of your data. In this case, the <code>plane_id<\/code> and <code>alt_id<\/code> columns are used together to create a unique identifier for each row, making it possible for them to serve as the primary key. To test how this work, start by running the following <code>INSERT<\/code> statement:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, engine_type, engine_count)\r\nVALUES (1001,173,'A340-600','Jet',4);<\/pre>\n<p>The statement should insert the data with no problem because there are no conflicting primary key values. Now run the next <code>INSERT<\/code> statement, which specifies the same <code>plane_id<\/code> value but a different <code>alt_id<\/code> value:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, engine_type, engine_count)\r\nVALUES (1001,174,'A340-600','Jet',4);<\/pre>\n<p>Once again, the <code>INSERT<\/code> statement should run without problem because together the values in the two columns are still unique. You can verify that the <code>airplanes<\/code> table now contains the two rows of data by running the following <code>SELECT<\/code> statement:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT * FROM airplanes;<\/pre>\n<p>The statement returns the results shown in the following figure, which indicates that the information in both rows is the same except for the <code>alt_id<\/code> values.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1060\" height=\"316\" class=\"wp-image-97825\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/08\/word-image-97823-2.png\" \/><\/p>\n<p>If you were to rerun the previous <code>INSERT<\/code> statement (or use the same <code>plane_id<\/code> and <code>alt_id<\/code> values in a different <code>INSERT<\/code> statement), MySQL would instead return the following error:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">Error Code: 1062. Duplicate entry '1001-174' for key 'airplanes.PRIMARY'<\/pre>\n<p>When defining primary keys on <code>InnoDB<\/code> tables, try to keep the key columns as short as possible to minimize storage overhead, such as using integers rather than 20-character strings. Each secondary index defined on an <code>InnoDB<\/code> table contains a copy of the primary key column for the corresponding rows, and the extra data can add up. Shorter key columns can also result in better query performance, depending on the type of queries.<\/p>\n<p>Note that you do not have to drop the entire table to change the constraint. Using the <code>ALTER TABLE<\/code> statement, you can drop the primary key constraint, and then recreate it.<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">--Remove the existing constraint\r\nALTER TABLE airplanes\r\n   DROP PRIMARY KEY;\r\n\r\n--Add the new PRIMARY KEY constraint\r\nALTER TABLE airplanes\r\n   ADD PRIMARY KEY (plane_id, alt_id);<\/pre>\n<p>If you are new to MySQL, this syntax for altering a primary key may not be what you expect, but the PRIMARY KEY constraint has a set name, unlike in some other RDBMS types.<\/p>\n<h2><strong>NOT<\/strong> <strong>NULL<\/strong> constraints<\/h2>\n<p>When defining a column in a <code>CREATE<\/code> <code>TABLE<\/code> statement, you can specify the column\u2019s nullability, which determines whether the column accepts <code>NULL<\/code> values. A <code>NULL<\/code> value typically means that there is no data or that the column\u2019s value is not known. This is different from a value of <code>0<\/code> or an empty string, although <code>NULL<\/code> is sometimes confused with these values. (A fair amount of confusion and debate continue to surround <code>NULL<\/code>, but this is a discussion well outside the scope of this article.)<\/p>\n<p>You can specify a column\u2019s nullability by including the keywords <code>NULL<\/code> or <code>NOT<\/code> <code>NULL<\/code> in the column definition. By default, MySQL permits <code>NULL<\/code> values, so if you don\u2019t specify a nullability option, MySQL will assume <code>NULL<\/code>, unless the column is a primary key. If you do not want to permit <code>NULL<\/code> values, you must add the <code>NOT<\/code> <code>NULL<\/code> keywords to your column definitions, as in the following example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id INT UNSIGNED NOT NULL,\r\n  plane VARCHAR(50) NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL,\r\n  engine_count TINYINT NOT NULL,\r\n  PRIMARY KEY (plane_id));<\/pre>\n<p>The <code>CREATE<\/code> <code>TABLE<\/code> statement is the same as in the previous example, only now each column definition includes <code>NOT<\/code> <code>NULL<\/code>. You can test a column\u2019s nullability by running a few <code>INSERT<\/code> statements, starting with the following:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, engine_type, engine_count)\r\nVALUES (1001,173,'A340-600','Jet',4);<\/pre>\n<p>This statement should run with no problem because the statement provides a non-<code>NULL<\/code> value for all the columns, but now try to run the following <code>INSERT<\/code> statement, which specifies <code>NULL<\/code> as the <code>engine_type<\/code> value:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, engine_type, engine_count)\r\nVALUES (1002,174,'A350-800 XWB',NULL,2);<\/pre>\n<p>This time MySQL returns the following error, which states that the <code>engine_type<\/code> value cannot be <code>NULL<\/code>:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">Error Code: 1048. Column 'engine_type' cannot be null<\/pre>\n<p>Instead of trying to insert a <code>NULL<\/code> value, you might try to insert the row without specifying an <code>engine_type<\/code> value:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, engine_count)\r\nVALUES (1002,174,'A350-800 XWB',2);<\/pre>\n<p>This time you\u2019ll get a different error message because MySQL doesn\u2019t know what to do with the <code>engine_type<\/code> column:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">Error Code: 1364. Field 'engine_type' doesn't have a default value<\/pre>\n<p>If a default value is assigned to the column (a topic I\u2019ll be discussing shortly), MySQL will insert that value into the column if no value is provided. Without a default value, MySQL returns an error.<\/p>\n<p>However, this is true only if strict mode is enabled on your MySQL server, which is the default setting. If strict mode is disabled, MySQL will implicitly insert the data type\u2019s default value, which in this case, is an empty string. This is because the data type for the <code>engine_type<\/code> column is <code>VARCHAR<\/code>, and MySQL uses an empty string as the implicit default value for all string types except <code>ENUM<\/code>.<\/p>\n<p><em>Note: A discussion about strict mode and how to disable and enable it is beyond the scope of this article. For information about strict mode, see the MySQL topic <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/sql-mode.html\">Server SQL Modes<\/a>.<\/em><\/p>\n<p>At times, you might want to define a column to permit <code>NULL<\/code> values, in which case, you can specify <code>NULL<\/code> in the column definition, or you can omit the nullability option. (Many database teams prefer to include default settings in schema definitions as part of best practices.) The following <code>CREATE<\/code> <code>TABLE<\/code> statement sets the <code>engine_type<\/code> column to <code>NULL<\/code>:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id INT UNSIGNED NOT NULL,\r\n  plane VARCHAR(50) NOT NULL,\r\n  engine_type VARCHAR(50) NULL,\r\n  engine_count TINYINT NOT NULL,\r\n  PRIMARY KEY (plane_id));<\/pre>\n<p>Now try to insert a row into the table without specifying the <code>engine_type<\/code> value:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, engine_count)\r\nVALUES (1001,173,'A340-600',4);<\/pre>\n<p>This time, MySQL will insert <code>NULL<\/code> for the column\u2019s value, which you can confirm by querying the <code>airplanes<\/code> table:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT * FROM airplanes;<\/pre>\n<p>The following figure shows the results returned by the <code>SELECT<\/code> statement. As you can see, the <code>engine_type<\/code> value is set to <code>NULL<\/code>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1080\" height=\"300\" class=\"wp-image-97826\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/08\/word-image-97823-3.png\" \/><\/p>\n<p>The debate over whether to support <code>NULL<\/code> values in a relational database has been going on for years (along with the debate about what <code>NULL<\/code> means). The extent to which you use <code>NULL<\/code> values will depend on the policies that your team has adopted. If you\u2019re trying to limit the use of <code>NULL<\/code>, you can sometimes accommodate unknown values by adding <code>DEFAULT<\/code> constraints to your column definitions.<\/p>\n<h2><strong>DEFAULT<\/strong> constraints<\/h2>\n<p>When creating or updating a table, you can add <code>DEFAULT<\/code> constraints to your column definitions. A <code>DEFAULT<\/code> constraint specifies the value to use for a column when an <code>INSERT<\/code> statement does not provide the value.<\/p>\n<p>The default value can be a literal constant or a scalar expression. If you specify an expression, it must adhere to the following rules:<\/p>\n<ul>\n<li>The expression must be enclosed in parentheses.<\/li>\n<li>The expression can reference other columns, but it cannot depend on a column defined with <code>AUTO_INCREMENT<\/code>.<\/li>\n<li>The expression cannot include subqueries, parameters, variables, stored functions, or loadable functions. However, it can include operators, literals, or built-in functions (both deterministic and nondeterministic).<\/li>\n<\/ul>\n<p>To add a literal <code>DEFAULT<\/code> constraint to a column definition, you need only specify the <code>DEFAULT<\/code> keyword, followed by a default value that conforms to the column\u2019s data type. For example, the following <code>CREATE<\/code> <code>TABLE<\/code> statement defines a <code>DEFAULT<\/code> constraint on the <code>engine_type<\/code> column:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id INT UNSIGNED NOT NULL,\r\n  plane VARCHAR(50) NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL DEFAULT 'unknown',\r\n  engine_count TINYINT NOT NULL,\r\n  PRIMARY KEY (plane_id));<\/pre>\n<p>In this case, the default value is the string <em>unknown<\/em>. You can test this out be running the following <code>INSERT<\/code> statement, which does not include a value for the <code>engine_type<\/code> column:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, engine_count)\r\nVALUES (1001,173,'A340-600',4);<\/pre>\n<p>To verify that the default value has been added, you can run the following <code>SELECT<\/code> statement:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT * FROM airplanes;<\/pre>\n<p>The statement returns the results shown in the following figure, which indicates the <code>engine_type<\/code> column has a value of <code>unknown<\/code>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1070\" height=\"288\" class=\"wp-image-97827\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/08\/word-image-97823-4.png\" \/><\/p>\n<p>As noted above, you can specify an expression for the default value, rather than a literal. For example, the following <code>CREATE<\/code> <code>TABLE<\/code> statement includes the <code>create_date<\/code> and <code>last_update<\/code> columns, which are defined with default values:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id INT UNSIGNED NOT NULL,\r\n  plane VARCHAR(50) NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL DEFAULT 'unknown',\r\n  engine_count TINYINT NOT NULL,\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (plane_id));<\/pre>\n<p>Both new columns use the <code>CURRENT_TIMESTAMP<\/code> function for the default value. The <code>last_update<\/code> column also includes the <code>ON<\/code> <code>UPDATE<\/code> <code>CURRENT_TIMESTAMP<\/code> clause, which instructs MySQL to update the column\u2019s value when the row has been updated. However, this clause is not part of the <code>DEFAULT<\/code> clause. In both column definitions, the default expression is only the <code>CURRENT_TIMESTAMP<\/code> function.<\/p>\n<p>You might have noticed that the <code>DEFAULT<\/code> clauses in the two column definitions do not enclose their expressions in parentheses. It turns out that the parentheses are not required when you use the <code>CURRENT_TIMESTAMP<\/code> function as the default value in <code>TIMESTAMP<\/code> or <code>DATETIME<\/code> columns. You can confirm that it works by running the following <code>INSERT<\/code> and <code>SELECT<\/code> statements:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, engine_type, engine_count)\r\nVALUES (1001,173,'A340-600','Jet',4);\r\n\r\nSELECT * FROM airplanes;<\/pre>\n<p>The <code>INSERT<\/code> statement runs with no problem, and the <code>SELECT<\/code> statement returns the expected results, which are shown in the following figure. MySQL automatically adds the timestamps to the <code>create_date<\/code> and <code>last_update<\/code> columns. If you had enclosed the default expression in parentheses, you would have received the same results.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1532\" height=\"206\" class=\"wp-image-97828\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/08\/word-image-97823-5.png\" \/><\/p>\n<p>If you update the row in any way, MySQL will automatically update the <code>last_update<\/code> column with the current timestamp, providing a record for when the row last changed.<\/p>\n<h2><strong>CHECK<\/strong> constraints<\/h2>\n<p>Another type of constraint that MySQL supports is the <code>CHECK<\/code> constraint, which verifies that each data value inserted into a column meets the requirements specified by the constraint. A <code>CHECK<\/code> constraint defines an expression that must evaluate to <code>TRUE<\/code> or <code>UNKNOWN<\/code> (to accommodate <code>NULL<\/code> values) for a value to be added into the column. If the expression evaluates to <code>FALSE<\/code>, the insert or update fails, and MySQL issues a constraint violation.<\/p>\n<p>A <code>CHECK<\/code> constraint can be specified within a column definition or after the column definitions. In either case, the constraint\u2019s expression must adhere to the following rules:<\/p>\n<ul>\n<li>The expression cannot reference a column defined with <code>AUTO_INCREMENT<\/code> or a column in another table.<\/li>\n<li>The expression cannot include stored functions, loadable functions, procedure and function parameters, variables, or subqueries. However, the expression can include literals, operators, or deterministic built-in functions.<\/li>\n<\/ul>\n<p>To create a <code>CHECK<\/code> constraint as part of a column definition, you need only specify the <code>CHECK<\/code> keyword, following by the expression. For example, the following <code>CREATE<\/code> <code>TABLE<\/code> statement defines a <code>CHECK<\/code> constraint on the <code>wingspan<\/code> column:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id INT UNSIGNED NOT NULL,\r\n  plane VARCHAR(50) NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL DEFAULT 'unknown',\r\n  engine_count TINYINT NOT NULL,\r\n  wingspan DECIMAL(5,2) NOT NULL\r\n    CHECK (wingspan BETWEEN 10 AND 400),\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (plane_id));<\/pre>\n<p>The <code>CHECK<\/code> constraint\u2019s expression specifies that the <code>wingspan<\/code> value must be between 10 and 400. You can verify whether this works correctly by first running the following <code>INSERT<\/code> statement, which specifies a <code>wingspan<\/code> value of <code>208.17<\/code>.<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, engine_type, \r\n    engine_count, wingspan)\r\nVALUES (1001,173,'A340-600','Jet',4,208.17);<\/pre>\n<p>MySQL should insert the row without any issues because the <code>wingspan<\/code> value meets the criteria specified by the <code>CHECK<\/code> constraint, but now try to add a value that falls outside the acceptable range:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes\r\n  (plane_id, alt_id, plane, engine_type, \r\n    engine_count, wingspan)\r\nVALUES (1002,174,'A350-800 XWB','Jet',2,408.17);<\/pre>\n<p>In this case, the specified <code>wingspan<\/code> value is <code>408.17<\/code>, which causes MySQL to baulk and return the following error:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">Error Code: 3819. Check constraint 'airplanes_chk_1' is violated.<\/pre>\n<p>Notice that the error message refers to the constraint as <code>airplanes_chk_1<\/code>. This is the name that MySQL automatically assigned to the constraint when it was created. You can conform this by again querying the <code>INFORMATION_SCHEMA<\/code>, like you did after you added a primary key:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT table_name, constraint_name, constraint_type\r\nFROM information_schema.table_constraints\r\nWHERE constraint_schema = 'travel';<\/pre>\n<p>The following figures shows the results returned by the <code>SELECT<\/code> statement, which include the newly added <code>CHECK<\/code> constraint:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1086\" height=\"274\" class=\"wp-image-97829\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/08\/word-image-97823-6.png\" \/><\/p>\n<p>MySQL follows a specific formula when naming a constraint. For <code>CHECK<\/code> constraints, it uses the table name, followed by _<code>chk_<\/code>, and then followed by an ordinal number that is automatically incremented with each new <code>CHECK<\/code> constraint. However, you can provide a custom name for a <code>CHECK<\/code> constraint, as in the following example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id INT UNSIGNED NOT NULL,\r\n  plane VARCHAR(50) NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL DEFAULT 'unknown',\r\n  engine_count TINYINT NOT NULL,\r\n  wingspan DECIMAL(5,2) NOT NULL\r\n    CONSTRAINT chk_wingspan \r\n      CHECK (wingspan BETWEEN 10 AND 400),\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (plane_id));<\/pre>\n<p>To name a <code>CHECK<\/code> constraint, you proceed the <code>CHECK<\/code> keyword with the <code>CONSTRAINT<\/code> keyword, followed by the constraint name, which in this case, <code>chk_wingspan<\/code>. Now when you query the <code>INFORMATION_SCHEMA<\/code>, the results should reflect the new name, as shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1082\" height=\"288\" class=\"wp-image-97830\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/08\/word-image-97823-7.png\" \/><\/p>\n<p>When naming a <code>CHECK<\/code> constraint or certain types of constraints, the constraint name must be unique within the database and for the constraint type. This means you cannot create two <code>CHECK<\/code> constraints within the same database that are both named <code>chk_wingspan<\/code>, even if they\u2019re defined on different tables. (When naming a constraint, be sure to follow your team\u2019s naming conventions.)<\/p>\n<p>You can also define a <code>CHECK<\/code> constraint after the column definitions, as you saw with <code>PRIMARY<\/code> <code>KEY<\/code> constraints:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id INT UNSIGNED NOT NULL,\r\n  plane VARCHAR(50) NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL DEFAULT 'unknown',\r\n  engine_count TINYINT NOT NULL,\r\n  wingspan DECIMAL(5,2) NOT NULL,\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (plane_id),\r\n  CONSTRAINT chk_wingspan\r\n    CHECK (wingspan BETWEEN 10 AND 400));<\/pre>\n<p>This <code>CREATE<\/code> <code>TABLE<\/code> statement achieves the same results as the previous one, creating a <code>CHECK<\/code> constraint named <code>chk_wingspan<\/code>. One of the advantages of creating a <code>CHECK<\/code> constraint after the column definitions is that you\u2019re not tied to a specific column, making it possible to reference multiple columns in your expression, as in the following example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id INT UNSIGNED NOT NULL,\r\n  plane VARCHAR(50) NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL DEFAULT 'unknown',\r\n  engine_count TINYINT NOT NULL,\r\n  wingspan DECIMAL(5,2) NOT NULL,\r\n  plane_length DECIMAL(5,2) NOT NULL,\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (plane_id),\r\n  CONSTRAINT chk_wingspan\r\n    CHECK (wingspan BETWEEN 10 AND 400),\r\n  CONSTRAINT chk_length \r\n    CHECK (plane_length &lt; (wingspan * 2)));<\/pre>\n<p>The statement defines a <code>CHECK<\/code> constraint named <code>chk_length<\/code>. The constraint\u2019s expression ensures that the <code>plane_length<\/code> value is always less than the <code>wingspan<\/code> value doubled. This is the sort of constraint you might create to avoid inserting anomalous data. You can test the constraint by running a couple <code>INSERT<\/code> statements, starting with the following statement:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, engine_type, \r\n    engine_count, wingspan, plane_length)\r\nVALUES (1001,173,'A340-600','Jet',4,208.17,247.24);<\/pre>\n<p>This <code>INSERT<\/code> statement should run with no problem because the <code>plane_length<\/code> value falls within the acceptable range, but suppose you now try to run the next statement, which specifies <code>498.58<\/code> as the <code>plane_length<\/code> value:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, engine_type, \r\n    engine_count, wingspan, plane_length)\r\nVALUES (1002,174,'A350-800 XWB','Jet',2,212.42,498.58);<\/pre>\n<p>Because the <code>plane_length<\/code> value exceeds the amount specified by the <code>CHECK<\/code> expression, MySQL returns the following error:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">Error Code: 3819. Check constraint 'chk_length' is violated.<\/pre>\n<p>MySQL <code>CHECK<\/code> constraints can be useful when you need to apply business rules that govern what is considered acceptable types of data. For this reason, <code>CHECK<\/code> constraints are often specific to the circumstances in which they\u2019re implemented.<\/p>\n<p>Constraints can be added and removed from a table using the <code>ALTER TABLE<\/code> statement, this time using the name of the constraint:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\"><code>ALTER TABLE airplanes<\/code> <code>   \r\n     DROP CONSTRAINT chk_wingspan;<\/code> <code>\r\nALTER TABLE airplanes<\/code> <code> \r\n   ADD CONSTRAINT chk_wingspan <\/code> <code>      \r\n      CHECK (wingspan BETWEEN 10 AND 400);<\/code><\/pre>\n<p><strong>UNIQUE<\/strong> constraints<\/p>\n<p>A <code>UNIQUE<\/code> constraint creates a unique index on one or more key columns. The index ensures the uniqueness of the data inserted into the columns. The only exception to this is the <code>NULL<\/code> value. Unlike some database management systems, MySQL permits its unique indexes to contain multiple <code>NULL<\/code> values. However, you can avoid the multiple values by configuring the column as <code>NOT<\/code> <code>NULL<\/code>.<\/p>\n<p>The simplest way to define a <code>UNIQUE<\/code> constraint on a single column is to add it to the column definition. For example, the following <code>CREATE<\/code> <code>TABLE<\/code> statement defines a <code>UNIQUE<\/code> constraint on the <code>alt_id<\/code> column:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">DROP TABLE IF EXISTS airplanes; \r\nCREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id INT UNSIGNED NOT NULL UNIQUE,\r\n  plane VARCHAR(50) NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL DEFAULT 'unknown',\r\n  engine_count TINYINT NOT NULL,\r\n  wingspan DECIMAL(5,2) NOT NULL,\r\n  plane_length DECIMAL(5,2) NOT NULL,\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (plane_id),\r\n  CONSTRAINT chk_wingspan\r\n    CHECK (wingspan BETWEEN 10 AND 400),\r\n  CONSTRAINT chk_length \r\n    CHECK (plane_length &lt; (wingspan * 2)));<\/pre>\n<p>As with the other examples, you can test the constraint by running a couple <code>INSERT<\/code> statements, starting with the following one:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, engine_type, \r\n    engine_count, wingspan, plane_length)\r\nVALUES (1001,173,'A340-600','Jet',4,208.17,247.24);<\/pre>\n<p>The statement should run with no problem, but the next one will not because the <code>alt_id<\/code> value violates the <code>UNIQUE<\/code> constraint because the statement is trying to again insert <code>173<\/code>:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, engine_type, \r\n    engine_count, wingspan, plane_length)\r\nVALUES (1002,173,'A350-800 XWB','Jet',2,212.42,198.58);<\/pre>\n<p>Not surprisingly, the statement returns the following error:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">Error Code: 1062. Duplicate entry '173' for key 'airplanes.alt_id'<\/pre>\n<p>As with other constraint types, you can also define a <code>UNIQUE<\/code> constraint after the column definitions, although you must also specify the column name:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id INT UNSIGNED NOT NULL,\r\n  plane VARCHAR(50) NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL DEFAULT 'unknown',\r\n  engine_count TINYINT NOT NULL,\r\n  wingspan DECIMAL(5,2) NOT NULL,\r\n  plane_length DECIMAL(5,2) NOT NULL,\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (plane_id),\r\n  CONSTRAINT chk_wingspan\r\n    CHECK (wingspan BETWEEN 10 AND 400),\r\n  CONSTRAINT chk_length \r\n    CHECK (plane_length &lt; (wingspan * 2)),\r\n  UNIQUE (alt_id));<\/pre>\n<p>After you add a <code>UNIQUE<\/code> constraint to a table definition, you can again query the <code>INFORMATION_SCHEMA<\/code>, which should give you the results shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1110\" height=\"396\" class=\"wp-image-97831\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/08\/word-image-97823-8.png\" \/><\/p>\n<p>MySQL named the <code>UNIQUE<\/code> constraint <code>alt_id<\/code>, after the column on which the constraint is defined. MySQL also assigned this name to the associated index. However, you can provide a name for the constraint (and index), just like you can with <code>CHECK<\/code> constraints:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id INT UNSIGNED NOT NULL,\r\n  plane VARCHAR(50) NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL DEFAULT 'unknown',\r\n  engine_count TINYINT NOT NULL,\r\n  wingspan DECIMAL(5,2) NOT NULL,\r\n  plane_length DECIMAL(5,2) NOT NULL,\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (plane_id),\r\n  CONSTRAINT chk_wingspan\r\n    CHECK (wingspan BETWEEN 10 AND 400),\r\n  CONSTRAINT chk_length \r\n    CHECK (plane_length &lt; (wingspan * 2)),\r\n  CONSTRAINT uc_alt_id UNIQUE (alt_id));<\/pre>\n<p>In this case, the name of the constraint is <code>uc_alt_id<\/code>, which you can again confirm by querying the <code>INFORMATION_SCHEMA<\/code>. You can also define a <code>UNIQUE<\/code> constraint on multiple columns, just like a primary key. In the following example, I define a composite <code>UNIQUE<\/code> constraint on the <code>alt_id1<\/code> and <code>alt_id2<\/code> columns.<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id1 INT UNSIGNED NOT NULL,\r\n  alt_id2 INT UNSIGNED NOT NULL,\r\n  plane VARCHAR(50) NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL DEFAULT 'unknown',\r\n  engine_count TINYINT NOT NULL,\r\n  wingspan DECIMAL(5,2) NOT NULL,\r\n  plane_length DECIMAL(5,2) NOT NULL,\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (plane_id),\r\n  CONSTRAINT chk_wingspan\r\n    CHECK (wingspan BETWEEN 10 AND 400),\r\n  CONSTRAINT chk_length \r\n    CHECK (plane_length &lt; (wingspan * 2)),\r\n  CONSTRAINT uc_alt_id UNIQUE (alt_id1, alt_id2));<\/pre>\n<p>A composite <code>UNIQUE<\/code> constraint works just like a composite <code>PRIMARY<\/code> <code>KEY<\/code> constraint, when it comes to inserting data. For example, the following two <code>INSERT<\/code> statements run with no problem, even though they specify the same <code>alt_id1<\/code> value:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id1, alt_id2, plane, engine_type, \r\n    engine_count, wingspan, plane_length)\r\nVALUES (1001,173,297,'A340-600','Jet',4,208.17,247.24);\r\n\r\nINSERT INTO airplanes \r\n  (plane_id, alt_id1, alt_id2, plane, engine_type, \r\n    engine_count, wingspan, plane_length)\r\nVALUES (1002,173,298,'A350-800 XWB','Jet',2,212.42,198.58);<\/pre>\n<p>However, the next <code>INSERT<\/code> statement tries to add a pair of <code>alt_id1<\/code> and <code>alt_id2<\/code> values that already exist:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id1, alt_id2, plane, engine_type, \r\n    engine_count, wingspan, plane_length)\r\nVALUES (1003,173,298,'A350-900','Jet',2,212.42,198.58);<\/pre>\n<p>As expected, MySQL returns the following error:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">Error Code: 1062. Duplicate entry '173-298' for key 'airplanes.uc_alt_id'<\/pre>\n<p>Adding a <code>UNIQUE<\/code> constraint to a table definition is a fairly straightforward process. Keep in mind however, that MySQL uses the same name for both the constraint and the unique index, so don\u2019t try to create another index with the same name.<\/p>\n<p>Note: just as before, you can drop and alter a UNIQUE constraint using the ALTER TABLE statement.<\/p>\n<h2><strong>FOREIGN<\/strong> <strong>KEY<\/strong> constraints<\/h2>\n<p>Another type of constraint that MySQL supports is the <code>FOREIGN<\/code> <code>KEY<\/code> constraint. This one is different from the other constraints in that it enables you to enforce referential integrity across tables. A foreign key establishes a relationship between a parent table and child table. The parent table holds the referenced column values, and the child table holds the referencing values.<\/p>\n<p><em>Note: The topic of foreign keys is much more involved than what I can cover in this article in depth. This article aims to give you a big picture of all the MySQL constraints. For more specific information about foreign keys, I recommend that you review the MySQL article <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/create-table-foreign-keys.html\">FOREIGN KEY constraints<\/a>.<\/em><\/p>\n<p>Although you can set up a <code>FOREIGN<\/code> <code>KEY<\/code> constraint that references a column in the same table (as you might do when working with hierarchical data), most foreign key relationships reference one or more columns in a different table. For example, the following <code>CREATE<\/code> <code>TABLE<\/code> statement defines a foreign key that references the <code>manufacturer_id<\/code> column in the <code>manufacturers<\/code> table:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id INT UNSIGNED NOT NULL,\r\n  plane VARCHAR(50) NOT NULL,\r\n  manufacturer_id INT UNSIGNED NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL DEFAULT 'unknown',\r\n  engine_count TINYINT NOT NULL,\r\n  wingspan DECIMAL(5,2) NOT NULL,\r\n  plane_length DECIMAL(5,2) NOT NULL,\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (plane_id),\r\n  CONSTRAINT chk_wingspan\r\n    CHECK (wingspan BETWEEN 10 AND 400),\r\n  CONSTRAINT chk_length \r\n    CHECK (plane_length &lt; (wingspan * 2)),\r\n  CONSTRAINT uc_ids UNIQUE (plane_id, alt_id),\r\n  FOREIGN KEY (manufacturer_id) \r\n    REFERENCES manufacturers (manufacturer_id));<\/pre>\n<p>When defining a foreign key, you must specify the <code>FOREIGN<\/code> <code>KEY<\/code> clause, followed the name of the column on which you\u2019re creating the foreign key. You must also include a <code>REFERENCES<\/code> clause that specifies the parent table and the target column within that table. In this case, the <code>manufacturer_id<\/code> column in the <code>airplanes<\/code> table is referencing the <code>manufacturer_id<\/code> column in the <code>manufacturers<\/code> table.<\/p>\n<p>To test the foreign key, you can run the following <code>INSERT<\/code> statement, which uses <code>101<\/code> for the <code>manufacturer_id<\/code> value:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, manufacturer_id, engine_type, \r\n    engine_count, wingspan, plane_length)\r\nVALUES (1001,173,'A340-600',101,'Jet',4,208.17,247.24);<\/pre>\n<p>For the <code>INSERT<\/code> statement to run successfully, the <code>manufacturers<\/code> table must include a row with a <code>manufacturer_id<\/code> value of <code>101<\/code>, which it does (assuming you created and populated the <code>manufacturers<\/code> table). But suppose you were to now run the following <code>INSERT<\/code> statement, which uses a <code>manufacturer_id<\/code> value that does not exist in the <code>manufacturers<\/code> table:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">INSERT INTO airplanes \r\n  (plane_id, alt_id, plane, manufacturer_id, engine_type, \r\n    engine_count, wingspan, plane_length)\r\nVALUES (1002,175,'A350-800 XWB',121,'Jet',2,212.42,198.58);<\/pre>\n<p>When you try to execute the statement, MySQL returns the following error:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk \">Error Code: 1452. Cannot add or update a child row: a foreign key constraint \r\nfails (`travel`.`airplanes`, CONSTRAINT `ibfk_1` FOREIGN KEY (`manufacturer_id`) \r\nREFERENCES `manufacturers` (`manufacturer_id`))<\/pre>\n<p>As you can see in the message, MySQL has named the constraint <code>airplanes_ibfk_1<\/code>. What you don\u2019t see is that MySQL also created a non-unique index on the <code>manufacturer_id<\/code> column in the <code>airplanes<\/code> table and named the index <code>manufacturer_id<\/code>.<\/p>\n<p>As with other constraint types, you can assign a custom name to a foreign key. For this, you must precede the <code>FOREIGN<\/code> <code>KEY<\/code> clause with the <code>CONSTRAINT<\/code> keyword, followed the constraint name, as in the following example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">CREATE TABLE airplanes (\r\n  plane_id INT UNSIGNED NOT NULL,\r\n  alt_id INT UNSIGNED NOT NULL,\r\n  plane VARCHAR(50) NOT NULL,\r\n  manufacturer_id INT UNSIGNED NOT NULL,\r\n  engine_type VARCHAR(50) NOT NULL DEFAULT 'unknown',\r\n  engine_count TINYINT NOT NULL,\r\n  wingspan DECIMAL(5,2) NOT NULL,\r\n  plane_length DECIMAL(5,2) NOT NULL,\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (plane_id),\r\n  CONSTRAINT chk_wingspan\r\n    CHECK (wingspan BETWEEN 10 AND 400),\r\n  CONSTRAINT chk_length \r\n    -- CHECK (wingspan &lt; (plane_length \/ 2)));\r\n    CHECK (plane_length &lt; (wingspan * 2)),\r\n  CONSTRAINT uc_ids UNIQUE (plane_id, alt_id),\r\n  CONSTRAINT fk_manufacturer \r\n    FOREIGN KEY (manufacturer_id) \r\n    REFERENCES manufacturers (manufacturer_id));<\/pre>\n<p>Now both the constraint and associated index will be named <code>fk_manufacturer<\/code>, rather than the names assigned by MySQL. Again, be aware that the name must be unique within the data for the particular constraint type, so don\u2019t try to create another foreign key with the same name, just like you should not try to create an index with the same name.<\/p>\n<h2>Getting started with MySQL constraints<\/h2>\n<p>MySQL constraints are one of the most important tools you have for ensuring the integrity of your data. But you need to understand how they work and how to implement them to realize their full potential. In this article, I\u2019ve introduced you to the various types of constraints and the ways you can add them to your tables. I recommend that you learn more about each constraint type so you fully understand the ways in which it works and its limitations. A good place to start is with the MySQL topic <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/create-table.html#create-table-indexes-keys\">CREATE TABLE statement<\/a>. There you\u2019ll find descriptions of each constraint type and links to additional information.<\/p>\n<h2>Appendix: Preparing your MySQL environment<\/h2>\n<p>For the examples for this article, I used a Mac computer that was set up with a local instance of MySQL 8.0.29 (Community Server edition) and MySQL Workbench. I also created the <code>travel<\/code> database and the <code>manufacturers<\/code> table. If you want to try out the examples, you should first run the following script against your MySQL instance:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">--NOTE: if you have been working through the examples,\r\n--you may need to drop the existing database first (or use\r\n--a different database name.)\r\nCREATE DATABASE IF NOT EXISTS travel;\r\nUSE travel;\r\nCREATE TABLE manufacturers (\r\n  manufacturer_id INT UNSIGNED NOT NULL,\r\n  manufacturer VARCHAR(50) NOT NULL,\r\n  create_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\r\n  last_update TIMESTAMP NOT NULL \r\n    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,\r\n  PRIMARY KEY (manufacturer_id) );\r\nINSERT INTO manufacturers (manufacturer_id, manufacturer)\r\nVALUES (101,'Airbus'), (102,'Beagle Aircraft Limited'), \r\n  (103,'Beechcraft'), (104,'Boeing');<\/pre>\n<p>The script creates the <code>travel<\/code> database, adds the <code>manufacturers<\/code> table, and inserts several rows into the table. Be aware, however that most of the examples in this article do not reference the <code>manufacturers<\/code> table. They simply use a <code>CREATE<\/code> <code>TABLE<\/code> statement to define different versions of the <code>airplanes<\/code> table to demonstrate various types of constraints. The <code>manufacturers<\/code> table is used only when explaining how to define a <code>FOREIGN<\/code> <code>KEY<\/code> constraint.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Complete guide to MySQL constraints &#8211; PRIMARY KEY for unique row identification, FOREIGN KEY for referential integrity, NOT NULL for required columns, DEFAULT for column default values, and CHECK (MySQL 8.0.16+) for custom validation rules. With executable examples for each.&hellip;<\/p>\n","protected":false},"author":221841,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[53,145792],"tags":[],"coauthors":[6779],"class_list":["post-97823","post","type-post","status-publish","format-standard","hentry","category-featured","category-mysql"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/97823","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221841"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=97823"}],"version-history":[{"count":7,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/97823\/revisions"}],"predecessor-version":[{"id":101475,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/97823\/revisions\/101475"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=97823"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=97823"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=97823"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=97823"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}