From 22c6f417a49d42a54ef25cc6c4c4a9f85e7487d3 Mon Sep 17 00:00:00 2001 From: Sean Loiselle Date: Fri, 30 Dec 2016 14:45:21 -0500 Subject: [PATCH] copy editing constraint pages --- _data/sidebar_doc.yml | 2 +- add-constraint.md | 3 +- alter-column.md | 8 +-- check.md | 32 +++++---- constraints.md | 119 +++++++++++++++++++++++++++++----- create-index.md | 6 +- create-table.md | 9 +-- default-value.md | 28 +++----- delete.md | 6 +- drop-constraint.md | 5 +- foreign-key.md | 21 +++--- frequently-asked-questions.md | 2 +- indexes.md | 8 +-- information-schema.md | 10 +-- insert.md | 2 +- learn-cockroachdb-sql.md | 4 +- not-null.md | 40 +++++++----- null-handling.md | 6 +- primary-key.md | 39 +++++++---- select.md | 2 +- serial.md | 2 +- show-constraints.md | 6 +- sql-feature-support.md | 12 ++-- transactions.md | 2 +- unique.md | 57 +++++++++++----- upsert.md | 8 +-- 26 files changed, 286 insertions(+), 153 deletions(-) diff --git a/_data/sidebar_doc.yml b/_data/sidebar_doc.yml index b68ba1f710c..5a8024de0c2 100644 --- a/_data/sidebar_doc.yml +++ b/_data/sidebar_doc.yml @@ -232,7 +232,7 @@ entries: - title: Default Value url: /default-value.html - - title: Foreign Keys + - title: Foreign Key url: /foreign-key.html - title: Not Null diff --git a/add-constraint.md b/add-constraint.md index 156ad0d8f47..e9acf1755ed 100644 --- a/add-constraint.md +++ b/add-constraint.md @@ -11,8 +11,7 @@ The `ADD CONSTRAINT` [statement](sql-statements.html) is part of `ALTER TABLE` a - [Unique](unique.html) {{site.data.alerts.callout_info}} -The Primary Key constraint can only be applied through CREATE TABLE. The Default constraint is managed through ALTER COLUMN. -{{site.data.alerts.end}} +The Primary Key and Not Null constraints can only be applied through CREATE TABLE. The Default constraint is managed through ALTER COLUMN.{{site.data.alerts.end}}
diff --git a/alter-column.md b/alter-column.md index 94724f5676f..cb497d5c6c5 100644 --- a/alter-column.md +++ b/alter-column.md @@ -22,15 +22,15 @@ The user must have the `CREATE` [privilege](privileges.html) on the table. | Parameter | Description | |-----------|-------------| -| `table_name` | The name of the table with the column whose Default value you want to modify. | +| `table_name` | The name of the table with the column whose Default Value you want to modify. | | `name` | The name of the column you want to modify. | -| `a_expr` | The new Default value you want to use. | +| `a_expr` | The new Default Value you want to use. | ## Examples ### Set or Change a Default Value -Setting the [Default value constraint](default-value.html) inserts the value when data's written to the table without explicitly defining the value for the column. If the column already has a Default value set, you can use this statement to change it. +Setting the [Default Value constraint](default-value.html) inserts the value when data's written to the table without explicitly defining the value for the column. If the column already has a Default Value set, you can use this statement to change it. The below example inserts the Boolean value `true` whenever you inserted data to the `subscriptions` table without defining a value for the `newsletter` column. @@ -40,7 +40,7 @@ The below example inserts the Boolean value `true` whenever you inserted data to ### Remove Default Constraint -If the column has a defined [Default value](default-value.html), you can remove the constraint, which means the column will no longer insert a value by default if one is not explicitly defined for the column. +If the column has a defined [Default Value](default-value.html), you can remove the constraint, which means the column will no longer insert a value by default if one is not explicitly defined for the column. ``` sql > ALTER TABLE subscriptions ALTER COLUMN newsletter DROP DEFAULT; diff --git a/check.md b/check.md index 98d4335e2de..8fc27ef6e3b 100644 --- a/check.md +++ b/check.md @@ -1,24 +1,25 @@ --- title: Check Constraint -summary: The Check constraint specifies that the column value must satisfy a Boolean expression. +summary: The Check constraint specifies that values for the column in INSERT or UPDATE statements must satisfy a Boolean expression. toc: false --- -The Check [constraints](constraints.html) specifies that the column value must satisfy a Boolean expression. +The Check [constraint](constraints.html) specifies that values for the column in [`INSERT`](insert.html) or [`UPDATE`](update.html) statements must return `TRUE` or `NULL` for a Boolean expression. If any values return `FALSE`, the entire statement is rejected.
## Details -- Check constraints requires that the column values satisfy a Boolean expression within the constraint. The expression must evaluate to `TRUE` (or *NULL*) for every row affected by an `INSERT` or `UPDATE` statement. The DML statement will fail if the condition evaluates to `FALSE` for any row. -- Check constraints may be specified at the column or table level and can reference other columns within the table. Internally, all column level Check constrints are converted to table level constraints so they can be handled in a consistent fashion. -- You can have multiple Check constraints on a single column but ideally, for performance optimization, these should be combined using the logical operators. So, for example, +- If you add a Check constraint to an existing table, existing values are not checked. However, any updates to those values will be. + {{site.data.alerts.callout_info}}In the future we plan to expand the Check constraint to include a check on any existing values in the column.{{site.data.alerts.end}} +- Check constraints may be specified at the column or table level and can reference other columns within the table. Internally, all column-level Check constraints are converted to table-level constraints so they can be handled consistently. +- You can have multiple Check constraints on a single column but ideally, for performance optimization, these should be combined using the logical operators. For example ~~~ sql warranty_period INT CHECK (warranty_period >= 0) CHECK (warranty_period <= 24) ~~~ - should be specified as + should be specified as: ~~~ sql warranty_period INT CHECK (warranty_period BETWEEN 0 AND 24) @@ -26,9 +27,11 @@ The Check [constraints](constraints.html) specifies that the column value must s ## Syntax -The syntax of the Check constraint depends on whether you want the constraint to use a [single column](#single-column-column-level) or [multiple columns](#multiple-column-table-level). +Check constraints can be defined at the [table level](#table-level). However, if you only want the constraint to apply to a single column, it can be applied at the [column level](#column-level). -### Single Column (Column Level) +{{site.data.alerts.callout_info}}You can also add the Check constraint to existing tables through ADD CONSTRAINT.{{site.data.alerts.end}} + +### Column Level {% include sql/diagrams/check_column_level.html %} @@ -38,7 +41,7 @@ The syntax of the Check constraint depends on whether you want the constraint to | `column_name` | The name of the constrained column. | | `column_type` | The constrained column's [data type](data-types.html). | | `check_expr` | An expression that returns a Boolean value; if the expression evaluates to `FALSE`, the value cannot be inserted.| -| `column_constraints` | Any other column-level [constraints](constraints.html) you want to apply. | +| `column_constraints` | Any other column-level [constraints](constraints.html) you want to apply to this column. | | `column_def` | Definitions for any other columns in the table. | | `table_constraints` | Any table-level [constraints](constraints.html) you want to apply. | @@ -53,7 +56,7 @@ The syntax of the Check constraint depends on whether you want the constraint to ); ~~~ -### Multiple Column (Table Level) +### Table Level {% include sql/diagrams/check_table_level.html %} @@ -63,12 +66,12 @@ The syntax of the Check constraint depends on whether you want the constraint to | `column_def` | Definitions for any other columns in the table. | | `name` | The name you want to use for the constraint, which must be unique to its table and follow these [identifier rules](keywords-and-identifiers.html#identifiers). | | `check_expr` | An expression that returns a Boolean value; if the expression evaluates to `FALSE`, the value cannot be inserted.| -| `table_constraints` | Any table-level [constraints](constraints.html) you want to apply. | +| `table_constraints` | Any other table-level [constraints](constraints.html) you want to apply. | **Example** ~~~ sql -> CREATE TABLE inventories( +> CREATE TABLE inventories ( product_id INT NOT NULL, warehouse_id INT NOT NULL, quantity_on_hand INT NOT NULL, @@ -79,7 +82,7 @@ The syntax of the Check constraint depends on whether you want the constraint to ## Usage Example -Check constraints may be specified at the column or table level and can reference other columns within the table. Internally, all column level Check constrints are converted to table level constraints so they can be handled in a consistent fashion. +Check constraints may be specified at the column or table level and can reference other columns within the table. Internally, all column-level Check constraints are converted to table-level constraints so they can be handled in a consistent fashion. ~~~ sql > CREATE TABLE inventories ( @@ -89,7 +92,7 @@ Check constraints may be specified at the column or table level and can referenc PRIMARY KEY (product_id, warehouse_id) ); -> INSERT INTO inventories (product_id, warehouse_id, quantity_on_hand) VALUES (1, 2, -20); +> INSERT INTO inventories (product_id, warehouse_id, quantity_on_hand) VALUES (1, 2, 0); ~~~ ~~~ pq: failed to satisfy CHECK constraint (quantity_on_hand > 0) @@ -98,6 +101,7 @@ pq: failed to satisfy CHECK constraint (quantity_on_hand > 0) ## See Also - [Constraints](constraints.html) +- [`DROP CONSTRAINT`](drop-constraint.html) - [Default Value constraint](default-value.html) - [Foreign Key constraint](foreign-key.html) - [Not Null constraint](not-null.html) diff --git a/constraints.md b/constraints.md index e47ef4c388f..7da139aaaba 100644 --- a/constraints.md +++ b/constraints.md @@ -1,27 +1,116 @@ --- title: Constraints -summary: Constraints offer additional data integrity by enforcing conditions on the data within a column or row. +summary: Constraints offer additional data integrity by enforcing conditions on the data within a column. toc: false --- -Constraints offer additional data integrity by enforcing conditions on the data within a column or row. They are checked during DML operations and restrict the data values within a column to those specified within the constraint. +Constraints offer additional data integrity by enforcing conditions on the data within a column. Whenever values are manipulated (inserted, deleted, or updated), constraints are checked and modifications that violate constraints are rejected. -If a constraint refers to only one column (column-level constraint), it can be defined against the column as part of its definition. If a constraint refers to more than one column (table-level constraint), it needs to be defined as a separate entry in the tables definition. +For example, the Unique constraint requires that all values in a column be unique from one another (except *NULL* values). If you attempt to write a duplicate value, the constraint rejects the entire statement. -The order of the constraints within the table definition is not important and does not determine the order in which the constraints are checked. Use the [`SHOW CONSTRAINTS`](show-constraints.html) or [`SHOW CREATE TABLE`](show-create-table.html) statement to show the constraints defined on a table. +
-The different types of constraints are: +## Supported Constraints -| Constraint Type | Description | -|-----------------|-------------| -| [Check](check.html) | Specifies that the column value must satisfy a Boolean expression. | -| [Default Value](default-value.html) | Specifies a value to populate a column with if none is provided.| -| [Foreign Keys](foreign-key.html) | Specifies a column can only contain values exactly matching existing values from the column it references. | -| [Not Null](not-null.html) | Specifies the column **may not** contain *NULL* values.| -| [Primary Key](primary-key.html) | Specifies that the columns values are unique and that the columns **may not** contain *NULL* values. | -| [Unique](unique.html) | Specifies that the columns values are unique and that the columns **may** contain *NULL* values. | +| Constraint | Description | +|------------|-------------| +| [Check](check.html) | Values must return `TRUE` or `NULL` for a Boolean expression. | +| [Default Value](default-value.html) | If a value is not defined for the constrained column in an `INSERT` statement, the Default Value is written to the column. | +| [Foreign Keys](foreign-key.html) | Values must exactly match existing values from the column it references. | +| [Not Null](not-null.html) | Values may not be *NULL*. | +| [Primary Key](primary-key.html) | Values must uniquely identify each row *(one per table)*. This behaves as if the Not Null and Unique constraints are applied, as well as automatically creates an [index](indexes.html) for the table using the constrained columns. | +| [Unique](unique.html) | Each non-*NULL* value must be unique. This also automatically creates an [index](indexes.html) for the table using the constrained columns. | + +## Using Constraints + +### Add Constraints + +How you add constraints depends on the number of columns you want to constrain, as well as whether or not the table is new. + +- **One column of a new table** has its constraints defined after the column's data type. For example, this statement applies the Primary Key constraint to `foo.a`: + + ``` sql + > CREATE TABLE foo (a INT PRIMARY KEY); + ``` +- **Multiple columns of a new table** have their constraints defined after the table's columns. For example, this statement applies the Primary Key constraint to `foo`'s columns `a` and `b`: + + ``` sql + > CREATE TABLE bar (a INT, b INT, PRIMARY KEY (a,b)); + ``` + + {{site.data.alerts.callout_info}}The Default Value and Not Null constraints cannot be applied to multiple columns.{{site.data.alerts.end}} + +- **Existing tables** can have the following constraints added: + - **Check**, **Foreign Key**, and **Unique** constraints can be added through [`ALTER TABLE...ADD CONSTRAINT`](add-constraint.html). For example, this statement adds the Unique constraint to `baz.id`: + + ~~~ sql + > ALTER TABLE baz ADD CONSTRAINT id_unique UNIQUE (id); + ~~~ + + - **Default Values** can be added through [`ALTER TABLE...ALTER COLUMN`](alter-column.html#set-or-change-a-default-value). For example, this statement adds the Default Value constraint to `baz.bool`: + + ~~~ sql + > ALTER TABLE baz ALTER COLUMN bool SET DEFAULT true; + ~~~ + + - **Primary Key** and **Not Null** constraints cannot be added or changed. However, you can go through [this process](#table-migrations-to-add-or-change-immutable-constraints) to migrate data from your current table to a new table with the constraints you want to apply. + +#### Order of Constraints + +The order in which you list constraints is not important because constraints are applied to every modification of their respective tables or columns. + +#### Name Constraints on New Tables + +You can name constraints applied to new tables using the `CONSTRAINT` clause before defining the constraint: + +``` sql +> CREATE TABLE foo (a INT CONSTRAINT another_name PRIMARY KEY); + +> CREATE TABLE bar (a INT, b INT, CONSTRAINT yet_another_name PRIMARY KEY (a,b)); +``` + +### View Constraints + +To view a table's constraints, use [`SHOW CONSTRAINTS`](show-constraints.html) or [`SHOW CREATE TABLE`](show-create-table.html). + +### Remove Constraints + +The procedure for removing a constraint depends on its type: + +| Constraint Type | Procedure | +|-----------------|-----------| +| [Check](check.html) | Use [`DROP CONSTRAINT`](drop-constraint.html) | +| [Default Value](default-value.html) | Use [`ALTER COLUMN`](alter-column.html#remove-default-constraint) | +| [Foreign Keys](foreign-key.html) | Use [`DROP CONSTRAINT`](drop-constraint.html) | +| [Not Null](not-null.html) | Use [`ALTER COLUMN`](alter-column.html#remove-not-null-constraint) | +| [Primary Key](primary-key.html) | Primary Keys cannot be removed. However, you can move the table's data to a new table with [this process](#table-migrations-to-add-or-change-immutable-constraints). | +| [Unique](unique.html) | The Unique constraint cannot be dropped directly. However, you can use [`DROP INDEX`](drop-index.html) to remove the index automatically created by the Unique constraint (whose name ends in `_key`) to remove the constraint. | + +### Change Constraints + +The procedure for changing a constraint depends on its type: + +| Constraint Type | Procedure | +|-----------------|-----------| +| [Check](check.html) | [Issue a transaction](transactions.html#syntax) that adds a new Check constraint ([`ADD CONSTRAINT`](add-constraint.html)), and then remove the existing one ([`DROP CONSTRAINT`](drop-constraint.html)). | +| [Default Value](default-value.html) | The Default Value can be changed through [`ALTER COLUMN`](alter-column.html). | +| [Foreign Keys](foreign-key.html) | [Issue a transaction](transactions.html#syntax) that adds a new Foreign Key constraint ([`ADD CONSTRAINT`](add-constraint.html)), and then remove the existing one ([`DROP CONSTRAINT`](drop-constraint.html)). | +| [Not Null](not-null.html) | The Not Null constraint cannot be changed, only removed. However, you can move the table's data to a new table with [this process](#table-migrations-to-add-or-change-immutable-constraints). | +| [Primary Key](primary-key.html) | Primary Keys cannot be modified. However, you can move the table's data to a new table with [this process](#table-migrations-to-add-or-change-immutable-constraints). | +| [Unique](unique.html) | [Issue a transaction](transactions.html#syntax) that adds a new Unique constraint ([`ADD CONSTRAINT`](add-constraint.html)), and then remove the existing one ([`DROP CONSTRAINT`](drop-constraint.html)). | + +#### Table Migrations to Add or Change Immutable Constraints + +If you want to make a change to an immutable constraint, you can use the following process: + +1. [Create a new table](create-table.html) with the constraints you want to apply. +2. Move the data from the old table to the new one using [`INSERT` from a `SELECT` statement](insert.html#insert-from-a-select-statement). +3. [Issue a transaction](transactions.html#syntax) that [drops the old table](drop-table.html), and then [renames the new table to the old name](rename-table.html). ## See Also -- [`ALTER TABLE`](alter-table.html) -- [`SHOW CONSTRAINTS`](show-constraints.html) + - [`CREATE TABLE`](create-table.html) +- [`ADD CONSTRAINT`](add-constraint.html) +- [`DROP CONSTRAINT`](drop-constraint.html) +- [`SHOW CONSTRAINTS`](show-constraints.html) +- [`SHOW CREATE TABLE`](show-create-table.html) diff --git a/create-index.md b/create-index.md index 2afc8a34d96..3a383663acb 100755 --- a/create-index.md +++ b/create-index.md @@ -28,9 +28,9 @@ table td:first-child { | Parameter | Description | |-----------|-------------| -|`UNIQUE` | Apply the [`UNIQUE`](unique.html) constraint to the indexed columns.

This causes the system to check for existing duplicate values on index creation. It also applies the `UNIQUE` constraint at the table level, so the system checks for duplicate values when inserting or updating data.| +|`UNIQUE` | Apply the [Unique constraint](unique.html) to the indexed columns.

This causes the system to check for existing duplicate values on index creation. It also applies the Unique constraint at the table level, so the system checks for duplicate values when inserting or updating data.| |`IF NOT EXISTS` | Create a new index only if an index of the same name does not already exist; if one does exist, do not return an error.| -|`index_name` | The [`name`](sql-grammar.html#name) of the index to create, which must be unique to its table and follow these [identifier rules](keywords-and-identifiers.html#identifiers).

If you don't specify a name, CockroachDB uses the format `__key/idx`. `key` indicates the index applies the `UNIQUE` constraint; `idx` indicates it does not. Example: `accounts_balance_idx`| +|`index_name` | The [`name`](sql-grammar.html#name) of the index to create, which must be unique to its table and follow these [identifier rules](keywords-and-identifiers.html#identifiers).

If you don't specify a name, CockroachDB uses the format `
__key/idx`. `key` indicates the index applies the Unique constraint; `idx` indicates it does not. Example: `accounts_balance_idx`| |`table_name` | The [`qualified_name`](sql-grammar.html#qualified_name) of the table you want to create the index on. | |`column_name` | The name of the column you want to index.| |`ASC` or `DESC`| Sort the column in ascending (`ASC`) or descending (`DESC`) order in the index. How columns are sorted affects query results, particularly when using `LIMIT`.

__Default:__ `ASC`| @@ -73,7 +73,7 @@ Unique indexes do not allow duplicate values among their columns. > CREATE UNIQUE INDEX ON products (name, manufacturer_id); ~~~ -This also applies the [`UNIQUE`](unique.html) constraint at the table level, similarly to [`ALTER TABLE`](alter-table.html). The above example is equivalent to: +This also applies the [Unique constraint](unique.html) at the table level, similarly to [`ALTER TABLE`](alter-table.html). The above example is equivalent to: ~~~ sql > ALTER TABLE products ADD CONSTRAINT products_name_manufacturer_id_key UNIQUE (name, manufacturer_id); diff --git a/create-table.md b/create-table.md index 92e114528cf..09a968dde44 100644 --- a/create-table.md +++ b/create-table.md @@ -81,7 +81,7 @@ Parameter | Description ----------|------------ `IF NOT EXISTS` | Create a new table only if a table of the same name does not already exist in the database; if one does exist, do not return an error.

Note that `IF NOT EXISTS` checks the table name only; it does not check if an existing table has the same columns, indexes, constraints, etc., of the new table. `any_name` | The name of the table to create, which must be unique within its database and follow these [identifier rules](keywords-and-identifiers.html#identifiers). When the parent database is not set as the default, the name must be formatted as `database.name`.

The [`UPSERT`](upsert.html) and [`INSERT ON CONFLICT`](insert.html) statements use a temporary table called `excluded` to handle uniqueness conflicts during execution. It's therefore not recommended to use the name `excluded` for any of your tables. -`column_def` | A comma-separated list of column definitions. Each column requires a [name/identifier](keywords-and-identifiers.html#identifiers) and [data type](data-types.html); optionally, a [column-level constraint](constraints.html) can be specified. Column names must be unique within the table but can have the same name as indexes or constraints.

Any `PRIMARY KEY`, `UNIQUE`, and `CHECK` [constraints](constraints.html) defined at the column level are moved to the table level as part of the table's creation. Use the [`SHOW CREATE TABLE`](show-create-table.html) statement to view them at the table level. +`column_def` | A comma-separated list of column definitions. Each column requires a [name/identifier](keywords-and-identifiers.html#identifiers) and [data type](data-types.html); optionally, a [column-level constraint](constraints.html) can be specified. Column names must be unique within the table but can have the same name as indexes or constraints.

Any Primary Key, Unique, and Check [constraints](constraints.html) defined at the column level are moved to the table-level as part of the table's creation. Use the [`SHOW CREATE TABLE`](show-create-table.html) statement to view them at the table level. `index_def` | An optional, comma-separated list of [index definitions](indexes.html). For each index, the column(s) to index must be specified; optionally, a name can be specified. Index names must be unique within the table and follow these [identifier rules](keywords-and-identifiers.html#identifiers). See the [Create a Table with Secondary Indexes](#create-a-table-with-secondary-indexes) example below.

The [`CREATE INDEX`](create-index.html) statement can be used to create an index separate from table creation. `family_def` | An optional, comma-separated list of [column family definitions](column-families.html). Column family names must be unique within the table but can have the same name as columns, constraints, or indexes.

A column family is a group of columns that are stored as a single key-value pair in the underlying key-value store. CockroachDB automatically groups columns into families to ensure efficient storage and performance. However, there are cases when you may want to manually assign columns to families. For more details, see [Column Families](column-families.html). `table_constraint` | An optional, comma-separated list of [table-level constraints](constraints.html). Constraint names must be unique within the table but can have the same name as columns, column families, or indexes. @@ -91,7 +91,7 @@ Parameter | Description ### Create a Table (No Primary Key Defined) -In CockroachDB, every table requires a [`PRIMARY KEY`](primary-key.html). If one is not explicitly defined, a column called `rowid` of the type `INT` is added automatically as the primary key, with the `unique_rowid()` function used to ensure that new rows always default to unique `rowid` values. The primary key is automatically indexed. +In CockroachDB, every table requires a [primary key](primary-key.html). If one is not explicitly defined, a column called `rowid` of the type `INT` is added automatically as the primary key, with the `unique_rowid()` function used to ensure that new rows always default to unique `rowid` values. The primary key is automatically indexed. {{site.data.alerts.callout_info}}Strictly speaking, a primary key's unique index is not created; it is derived from the key(s) under which the data is stored, so it takes no additional space. However, it appears as a normal unique index when using commands like SHOW INDEX.{{site.data.alerts.end}} @@ -127,7 +127,7 @@ In CockroachDB, every table requires a [`PRIMARY KEY`](primary-key.html). If one ### Create a Table (Primary Key Defined) -In this example, we create a table with three columns. One column is the [`PRIMARY KEY`](primary-key.html), another is given the [`UNIQUE`](unique.html) constraint, and the third has no constraints. The primary key and column with the `UNIQUE` constraint are automatically indexed. +In this example, we create a table with three columns. One column is the [primary key](primary-key.html), another is given the [Unique constraint](unique.html), and the third has no constraints. The primary key and column with the Unique constraint are automatically indexed. By default, CockroachDB would assign the `user_id` and `logoff_date` columns to a single column family, since they're of a fixed size, and `user_email` to its own column family, since it's unbounded. We know that `user_email` will be relatively small, however, so we use the `FAMILY` keyword to group it with the other columns. As a result, each new row in the table would correspond to a single underlying key-value pair. For more deails about how columns are assigned to column families, see [Column Families](column-families.html). @@ -215,7 +215,8 @@ We also have other resources on indexes: There are a [number of rules](foreign-key.html#rules-for-creating-foreign-keys) that govern foreign keys, but the two most important are: - Foreign key columns must be [indexed](indexes.html) when creating the table using `INDEX`, `PRIMARY KEY`, or `UNIQUE`. -- Referenced columns must contain only unique values. This means the `REFERENCES` clause must use exactly the same columns as a [`PRIMARY KEY`](primary-key.html) or [`UNIQUE`](unique.html) constraint. + +- Referenced columns must contain only unique values. This means the `REFERENCES` clause must use exactly the same columns as a [Primary Key](primary-key.html) or [Unique](unique.html) constraint. In this example, we'll show a series of tables using different formats of foreign keys. diff --git a/default-value.md b/default-value.md index ebf58785faf..60b055bc338 100644 --- a/default-value.md +++ b/default-value.md @@ -4,17 +4,21 @@ summary: The Default Value constraint specifies a value to populate a column wit toc: false --- -The Default Value [constraints](constraints.html) specifies a value to populate a column with if none is provided. It supplies a value to a column if one is not provided on insert. The value may be a hard-coded literal or an expression that is evaluated at the time the row is inserted. +The Default Value [constraint](constraints.html) specifies a value to write into the constrained column if one is not defined in an `INSERT` statement. The value may be either a hard-coded literal or an expression that is evaluated at the time the row is created.
## Details -- The [data type](data-types.html) of the Default Value or expression should be the same as the data type of the column. -- The Default Value constraint only applies on insert if the column is not specified in the [`INSERT`](insert.html) statement. You can still insert a *NULL* into an optional (nullable) column by explicitly stating the column and the *NULL* value. +- The [data type](data-types.html) of the Default Value must be the same as the data type of the column. +- The Default Value constraint only applies if the column does not have a value specified in the [`INSERT`](insert.html) statement. You can still insert a *NULL* into an optional (nullable) column by explicitly inserting *NULL*. For example, `INSERT INTO foo VALUES (1, NULL);`. ## Syntax +You can only apply the Default Value constraint to individual columns. + +{{site.data.alerts.callout_info}}You can also add the Default Value constraint to an existing table through ALTER COLUMN. {{site.data.alerts.end}} + {% include sql/diagrams/default_value_column_level.html %} | Parameter | Description | @@ -23,23 +27,10 @@ The Default Value [constraints](constraints.html) specifies a value to populate | `column_name` | The name of the constrained column. | | `column_type` | The constrained column's [data type](data-types.html). | | `default_value` | The value you want to insert by default, which must evaluate to the same [data type](data-types.html) as the `column_type`.| -| `column_constraints` | Any other column-level [constraints](constraints.html) you want to apply. | +| `column_constraints` | Any other column-level [constraints](constraints.html) you want to apply to this column. | | `column_def` | Definitions for any other columns in the table. | | `table_constraints` | Any table-level [constraints](constraints.html) you want to apply. | -**Example** - -~~~ sql -> CREATE TABLE inventories ( - product_id INT, - warehouse_id INT, - quantity_on_hand INT DEFAULT 100, - PRIMARY KEY (product_id, warehouse_id) - ); -~~~ - -{{site.data.alerts.callout_info}}You cannot apply the Default constraint to multiple columns (i.e. at the table level).{{site.data.alerts.end}} - ## Usage Example ~~~ sql @@ -65,11 +56,12 @@ The Default Value [constraints](constraints.html) specifies a value to populate +------------+--------------+------------------+ ~~~ -If no `DEFAULT` constraint is specified and an explicit value is not given, a value of *NULL* is assigned to the column. This may cause an error if the column has a `NOT NULL` constraint. +If the Default Value constraint is not specified and an explicit value is not given, a value of *NULL* is assigned to the column. ## See Also - [Constraints](constraints.html) +- [`ALTER COLUMN`](alter-column.html) - [Check constraint](check.html) - [Foreign Key constraint](foreign-key.html) - [Not Null constraint](not-null.html) diff --git a/delete.md b/delete.md index 40eff71fa7c..0051e5245e4 100644 --- a/delete.md +++ b/delete.md @@ -69,13 +69,13 @@ As you can see, one difference is that `TRUNCATE` does not return the number of ### Delete Specific Rows -When deleting specific rows from a table, the most important decision you make is which columns to use in your `WHERE` clause. When making that choice, consider the potential impact of using [`PRIMARY KEY`](primary-key.html)/[`UNIQUE`](unique.html) columns versus non-unique ones. +When deleting specific rows from a table, the most important decision you make is which columns to use in your `WHERE` clause. When making that choice, consider the potential impact of using columns with the [Primary Key](primary-key.html)/[Unique](unique.html) constraints (both of which enforce uniqueness) versus those that are not unique. #### Delete Rows Using Primary Key/Unique Columns -Using your table's `PRIMARY KEY` or `UNIQUE` columns to delete rows ensures your statement is unambiguous—no two rows contain the same column value, so it's less likely to delete data unintentionally. +Using columns with the [Primary Key](primary-key.html) or [Unique](unique.html) constraints to delete rows ensures your statement is unambiguous—no two rows contain the same column value, so it's less likely to delete data unintentionally. -In this example, `account_id` is our `PRIMARY KEY` and we want to delete the row where it equals 1. Because we're positive no other rows have that value in the `account_id` column, there's no risk of accidentally removing another row. +In this example, `account_id` is our primary key and we want to delete the row where it equals 1. Because we're positive no other rows have that value in the `account_id` column, there's no risk of accidentally removing another row. ~~~ sql > DELETE FROM account_details WHERE account_id = 1 RETURNING *; diff --git a/drop-constraint.md b/drop-constraint.md index 42cc6362128..a521dab561c 100644 --- a/drop-constraint.md +++ b/drop-constraint.md @@ -4,7 +4,9 @@ summary: Use the ALTER CONSTRAINT statement to remove constraints from columns. toc: false --- -The `DROP CONSTRAINT` [statement](sql-statements.html) is part of `ALTER TABLE` and removes constraints from columns. +The `DROP CONSTRAINT` [statement](sql-statements.html) is part of `ALTER TABLE` and removes Check and Foreign Key constraints from columns. + +{{site.data.alerts.callout_info}}For information about removing other constraints, see Constraints: Remove Constraints.{{site.data.alerts.end}}
@@ -23,7 +25,6 @@ The user must have the `CREATE` [privilege](privileges.html) on the table. | `table_name` | The name of the table with the constraint you want to drop. | | `name` | The name of the constraint you want to drop. | - ## Example ~~~ sql diff --git a/foreign-key.md b/foreign-key.md index 21afbb80d08..6c409804be4 100644 --- a/foreign-key.md +++ b/foreign-key.md @@ -4,7 +4,7 @@ summary: The Foreign Key constraint specifies a column can contain only values e toc: false --- -The Foreign Key [constraints](constraints.html) specifies a column can contain only values exactly matching existing values from the column it references, enforcing referential integrity. +The Foreign Key [constraint](constraints.html) specifies that all of a column's values must exactly match existing values from the column it references, enforcing referential integrity. For example, if you create a foreign key on `orders.customer` that references `customers.id`: @@ -27,14 +27,14 @@ For example, if you create a foreign key on `orders.customer` that references `c - Foreign key columns must be [indexed](indexes.html) when the table is created. To meet this requirement, there are a few options: - Create indexes explicitly using the [`INDEX`](create-table.html#create-a-table-with-secondary-indexes) clause of `CREATE TABLE`. - - Rely on indexes created by [`PRIMARY KEY`](primary-key.html) or [`UNIQUE`](unique.html) constraints. + - Rely on indexes created by the [Primary Key](primary-key.html) or [Unique](unique.html) constraints. - Have CockroachDB automatically create an index of the foreign key columns for you. However, it's important to note that if you later remove the Foreign Key constraint, this automatically created index _is not_ removed. Using the foreign key columns as the prefix of an index's columns also satisfies the requirement for an index. For example, if you create foreign key columns `(A, B)`, an index of columns `(A, B, C)` satisfies the requirement for an index. **Referenced Columns** -- Referenced columns must contain only unique sets of values. This means the `REFERENCES` clause must use exactly the same columns as a [`UNIQUE`](unique.html) or [`PRIMARY KEY`](primary-key.html) constraint on the referenced table. For example, the clause `REFERENCES tbl (C, D)` requires `tbl` to have either the constraint `UNIQUE (C, D)` or `PRIMARY KEY (C, D)`. +- Referenced columns must contain only unique sets of values. This means the `REFERENCES` clause must use exactly the same columns as a [Unique](unique.html) or [Primary Key](primary-key.html) constraint on the referenced table. For example, the clause `REFERENCES tbl (C, D)` requires `tbl` to have either the constraint `UNIQUE (C, D)` or `PRIMARY KEY (C, D)`. - In the `REFERENCES` clause, if you specify a table but no columns, CockroachDB references the table's primary key. In these cases, the Foreign Key constraint and the referenced table's primary key must contain the same number of columns. ### _NULL_ Values @@ -48,7 +48,7 @@ Multiple-column foreign keys only accept _NULL_ values in these scenarios: For example, if you have a Foreign Key constraint on columns `(A, B)` and try to insert `(1, NULL)`, the write would fail unless the row with the value `1` for `(A)` contained a _NULL_ value for `(B)`. However, inserting `(NULL, NULL)` would succeed. -However, allowing _NULL_ values in either your foreign key or referenced columns can degrade their referential integrity. To avoid this, you can use [`NOT NULL`](not-null.html) on both sets of columns when [creating your tables](create-table.html). (`NOT NULL` cannot be added to existing tables.) +However, allowing _NULL_ values in either your foreign key or referenced columns can degrade their referential integrity. To avoid this, you can use the [Not Null constraint](not-null.html) on both sets of columns when [creating your tables](create-table.html). (The Not Null constraint cannot be added to existing tables.) ### Performance @@ -60,7 +60,11 @@ We're currently working to improve the performance of these statements, though. ## Syntax -### Single Column (Column Level) +Foreign Key constraints can be defined at the [table level](#table-level). However, if you only want the constraint to apply to a single column, it can be applied at the [column level](#column-level). + +{{site.data.alerts.callout_info}}You can also add the Foreign Key constraint to existing tables through ADD CONSTRAINT.{{site.data.alerts.end}} + +### Column Level {% include sql/diagrams/foreign_key_column_level.html %} @@ -71,7 +75,7 @@ We're currently working to improve the performance of these statements, though. | `column_type` | The foreign key column's [data type](data-types.html). | | `parent_table` | The name of the table the foreign key references. | | `ref_column_name` | The name of the column the foreign key references.

If you do not include the `ref_column_name` you want to reference from the `parent_table`, CockroachDB uses the first column of `parent_table`'s primary key. -| `column_constraints` | Any other column-level [constraints](constraints.html) you want to apply. | +| `column_constraints` | Any other column-level [constraints](constraints.html) you want to apply to this column. | | `column_def` | Definitions for any other columns in the table. | | `table_constraints` | Any table-level [constraints](constraints.html) you want to apply. | @@ -86,7 +90,7 @@ We're currently working to improve the performance of these statements, though. ); ~~~ -### Multiple Column (Table Level) +### Table Level {% include sql/diagrams/foreign_key_table_level.html %} @@ -98,7 +102,7 @@ We're currently working to improve the performance of these statements, though. | `fk_column_name` | The name of the foreign key column. | | `parent_table` | The name of the table the foreign key references. | | `ref_column_name` | The name of the column the foreign key references.

If you do not include the `column_name` you want to reference from the `parent_table`, CockroachDB uses the first column of `parent_table`'s primary key. -| `table_constraints` | Any table-level [constraints](constraints.html) you want to apply. | +| `table_constraints` | Any other table-level [constraints](constraints.html) you want to apply. | **Example** @@ -153,6 +157,7 @@ pq: foreign key violation: value(s) [1001] in columns [id] referenced in table " ## See Also - [Constraints](constraints.html) +- [`DROP CONSTRAINT`](drop-constraint.html) - [Check constraint](check.html) - [Default Value constraint](default-value.html) - [Not Null constraint](not-null.html) diff --git a/frequently-asked-questions.md b/frequently-asked-questions.md index c7339fc7bc2..4b894b92e75 100644 --- a/frequently-asked-questions.md +++ b/frequently-asked-questions.md @@ -120,7 +120,7 @@ See [Install Client Drivers](install-client-drivers.html) for more details. You can run a secure or insecure CockroachDB cluster. When secure, client/node and inter-node communication is encrypted, and SSL certificates authenticate the identity of both clients and nodes. When insecure, there's no encryption or authentication. -Also, CockroachDB supports common SQL privileges on databases and tables. The `root` user has privileges for all databases, while unique users can be granted privileges for specific statements at the database and table levels. +Also, CockroachDB supports common SQL privileges on databases and tables. The `root` user has privileges for all databases, while unique users can be granted privileges for specific statements at the database and table-levels. For more details, see our documentation on [privileges](privileges.html) and the [`GRANT`](grant.html) statement. diff --git a/indexes.md b/indexes.md index db9a0fe14c9..0f0f8bd3cd3 100755 --- a/indexes.md +++ b/indexes.md @@ -19,13 +19,13 @@ For example, if you index an `INT` column and then filter it WHERE <ind ### Creation -Each table automatically has an index created called `primary`, which indexes either its [`PRIMARY KEY`](primary-key.html) or—if there is no primary key—a unique value for each row known as `rowid`. We recommend always defining a primary key because the index it creates provides much better performance than letting CockroachDB use `rowid`. +Each table automatically has an index created called `primary`, which indexes either its [primary key](primary-key.html) or—if there is no primary key—a unique value for each row known as `rowid`. We recommend always defining a primary key because the index it creates provides much better performance than letting CockroachDB use `rowid`. The `primary` index helps filter a table's primary key but doesn't help SQL find values in any other columns. However, you can improve the performance of queries using columns besides the primary key with secondary indexes. You can create them: -- At the same time as the table with the `INDEX` clause of [`CREATE TABLE`](create-table.html#create-a-table-with-secondary-indexes). In addition to explicitly defined indexes, CockroachDB automatically creates secondary indexes for `UNIQUE` columns. +- At the same time as the table with the `INDEX` clause of [`CREATE TABLE`](create-table.html#create-a-table-with-secondary-indexes). In addition to explicitly defined indexes, CockroachDB automatically creates secondary indexes for columns with the [Unique constraint](unique.html). - For existing tables with [`CREATE INDEX`](create-index.html). -- By applying the [`UNIQUE`](unique.html) constraint to columns with [`ALTER TABLE`](alter-table.html), which automatically creates an index of the constrained columns. +- By applying the Unique constraint to columns with [`ALTER TABLE`](alter-table.html), which automatically creates an index of the constrained columns. To create the most useful secondary indexes, you should also check out our [best practices](#best-practices). @@ -60,7 +60,7 @@ We recommend creating indexes for all of your common queries. To design the most When designing indexes, it's important to consider which columns you index and the order you list them. Here are a few guidelines to help you make the best choices: -- Each table's `PRIMARY KEY` (which we recommend always [defining](create-table.html#create-a-table-primary-key-defined)) is automatically indexed. The index it creates (called `primary`) cannot be changed, nor can you change the `PRIMARY KEY` of a table after it's been created, so this is a critical decision for every table. +- Each table's [primary key](primary-key.html) (which we recommend always [defining](create-table.html#create-a-table-primary-key-defined)) is automatically indexed. The index it creates (called `primary`) cannot be changed, nor can you change the primary key of a table after it's been created, so this is a critical decision for every table. - Queries can benefit from an index even if they only filter a prefix of its columns. For example, if you create an index of columns `(A, B, C)`, queries filtering `(A)` or `(A, B)` can still use the index. However, queries that don't filter `(A)` won't benefit from the index.

This feature also lets you avoid using single-column indexes. Instead, use the column as the first column in a multiple-column index, which is useful to more queries. - Columns filtered in the `WHERE` clause with the equality operators (`=` or `IN`) should come first in the index, before those referenced with inequality operators (`<`, `>`). - Indexes of the same columns in different orders can produce different results for each query. For more information, see [our blog post on index selection](https://www.cockroachlabs.com/blog/index-selection-cockroachdb-2/)—specifically the section "Restricting the search space." diff --git a/information-schema.md b/information-schema.md index e147923d0b8..eb358bc6220 100644 --- a/information-schema.md +++ b/information-schema.md @@ -41,8 +41,8 @@ Column | Description `TABLE_NAME` | Name of the table. `COLUMN_NAME` | Name of the column. `ORDINAL_POSITION` | Ordinal position of the column in the table (begins at 1). -`COLUMN_DEFAULT` | Default value for the column. -`IS_NULLABLE` | `YES` if the column accepts *NULL* values; `NO` if it doesn't (e.g. it has the [`NOT NULL` constraint](not-null.html)). +`COLUMN_DEFAULT` | Default Value for the column. +`IS_NULLABLE` | `YES` if the column accepts *NULL* values; `NO` if it doesn't (e.g. it has the [Not Null constraint](not-null.html)). `DATA_TYPE` | [Data type](data-types.html) of the column. `CHARACTER_MAXIMUM_LENGTH` | If `DATA_TYPE` is `STRING`, the maximum length in characters of a value; otherwise *NULL*. `CHARACTER_OCTET_LENGTH` | If `DATA_TYPE` is `STRING`, the maximum length in octets (bytes) of a value; otherwise *NULL*. @@ -52,7 +52,7 @@ Column | Description ### key_column_usage -The `key_column_usage` view identifies columns with [`PRIMARY KEY`](primary-key.html), [`UNIQUE`](unique.html), or [`FOREIGN KEY`](foreign-key.html) constraints. +The `key_column_usage` view identifies columns with [Primary Key](primary-key.html), [Unique](unique.html), or [Foreign Key](foreign-key.html) constraints. Column | Description -------|----------- @@ -64,7 +64,7 @@ Column | Description `TABLE_NAME` | Name of the constrained table. `COLUMN_NAME` | Name of the constrained column. `ORDINAL_POSITION` | Ordinal position of the column within the constraint (begins at 1). -`POSITION_IN_UNIQUE_CONSTRAINT` | For Foreign Key constraints, ordinal position of the referenced column within its `UNIQUE` constraint (begins at 1). +`POSITION_IN_UNIQUE_CONSTRAINT` | For Foreign Key constraints, ordinal position of the referenced column within its Unique constraint (begins at 1). ### schema_privileges @@ -98,7 +98,7 @@ Column | Description `TABLE_CATALOG` | Always equal to `def` (CockroachDB does not support the notion of catalogs). `TABLE_SCHEMA` | Name of the database that contains the constrained table. `TABLE_NAME` | Name of the table . -`NON_UNIQUE` | `false` if the index was created by a `UNIQUE` constraint; `true` if the index was not created by a `UNIQUE` constraint. +`NON_UNIQUE` | `false` if the index was created by a Unique constraint; `true` if the index was not created by a Unique constraint. `INDEX_SCHEMA` | Name of the database that contains the index. `INDEX_NAME` | Name of the index. `SEQ_IN_INDEX` | Ordinal position of the column within the index (begins at 1). diff --git a/insert.md b/insert.md index 841d0729f05..7edd3155286 100644 --- a/insert.md +++ b/insert.md @@ -32,7 +32,7 @@ Parameter | Description `select_stmt` | A comma-separated list of column values for a single row, in parentheses. To insert values into multiple rows, use a comma-separated list of parentheses. Alternately, you can use [`SELECT`](select.html) statements to retrieve values from other tables and insert them as new rows. See the [Insert a Single Row](#insert-a-single-row), [Insert Multiple Rows](#insert-multiple-rows), [Insert from a `SELECT` Statement](#insert-from-a-select-statement) examples below.

Each value must match the [data type](data-types.html) of its column. Also, if column names are listed (`qualified_name_list`), values must be in corresponding order; otherwise, they must follow the declared order of the columns in the table. `DEFAULT VALUES` | To fill all columns with their [default values](default-value.html), use `DEFAULT VALUES` in place of `select_stmt`. To fill a specific column with its default value, leave the value out of the `select_stmt` or use `DEFAULT` at the appropriate position. See the [Insert Default Values](#insert-default-values) examples below. `RETURNING target_list` | Return values based on rows inserted, where `target_list` can be specific column names from the table, `*` for all columns, or a computation on specific columns. See the [Insert and Return Values](#insert-and-return-values) example below.

Note that `RETURNING` is not supported for `INSERT` statements with `ON CONFLICT` clauses. -`on_conflict` | Normally, when inserted values conflict with a `UNIQUE` constraint on one or more columns, CockroachDB returns an error. To update the affected rows instead, use an `ON CONFLICT` clause containing the column(s) with the unique constraint and the `DO UPDATE SET` expression set to the column(s) to be updated (any `SET` expression supported by the [`UPDATE`](update.html) statement is also supported here). To prevent the affected rows from updating while allowing new rows to be inserted, set `ON CONFLICT` to `DO NOTHING`. See the [Update Values `ON CONFLICT`](#update-values-on-conflict) and [Do Not Update Values `ON CONFLICT`](#do-not-update-values-on-conflict) examples below.

Note that it's not possible to update the same row twice with a single `INSERT ON CONFLICT` statement. Also, if the values in the `SET` expression cause uniqueness conflicts, CockroachDB will return an error.

As a short-hand alternative to the `ON CONFLICT` clause, you can use the [`UPSERT`](upsert.html) statement. However, `UPSERT` does not let you specify the column with the unique constraint; it assumes that the column is the primary key. Using `ON CONFLICT` is therefore more flexible. +`on_conflict` | Normally, when inserted values conflict with a Unique constraint on one or more columns, CockroachDB returns an error. To update the affected rows instead, use an `ON CONFLICT` clause containing the column(s) with the unique constraint and the `DO UPDATE SET` expression set to the column(s) to be updated (any `SET` expression supported by the [`UPDATE`](update.html) statement is also supported here). To prevent the affected rows from updating while allowing new rows to be inserted, set `ON CONFLICT` to `DO NOTHING`. See the [Update Values `ON CONFLICT`](#update-values-on-conflict) and [Do Not Update Values `ON CONFLICT`](#do-not-update-values-on-conflict) examples below.

Note that it's not possible to update the same row twice with a single `INSERT ON CONFLICT` statement. Also, if the values in the `SET` expression cause uniqueness conflicts, CockroachDB will return an error.

As a short-hand alternative to the `ON CONFLICT` clause, you can use the [`UPSERT`](upsert.html) statement. However, `UPSERT` does not let you specify the column with the unique constraint; it assumes that the column is the primary key. Using `ON CONFLICT` is therefore more flexible. ## Examples diff --git a/learn-cockroachdb-sql.md b/learn-cockroachdb-sql.md index 8f9b9260557..683a14a4838 100644 --- a/learn-cockroachdb-sql.md +++ b/learn-cockroachdb-sql.md @@ -78,7 +78,7 @@ To create a table, use [`CREATE TABLE`](create-table.html) followed by a table n ); ~~~ -Table and column names must follow [these rules](keywords-and-identifiers.html#identifiers). Also, when you don't explicitly define a `PRIMARY KEY`, CockroachDB will automatically add a hidden `rowid` column as the primary key. +Table and column names must follow [these rules](keywords-and-identifiers.html#identifiers). Also, when you don't explicitly define a [primary key](primary-key.html), CockroachDB will automatically add a hidden `rowid` column as the primary key. To avoid an error in case the table already exists, you can include `IF NOT EXISTS`: @@ -187,7 +187,7 @@ To insert multiple rows into a table, use a comma-separated list of parentheses, ~~~ ## Create an Index -[Indexes](indexes.html) help locate data without having to look through every row of a table. They're automatically created for the [`PRIMARY KEY`](primary-key.html) of a table and any columns with a [`UNIQUE`](unique.html) constraint. +[Indexes](indexes.html) help locate data without having to look through every row of a table. They're automatically created for the [primary key](primary-key.html) of a table and any columns with a [Unique constraint](unique.html). To create an index for non-unique columns, use [`CREATE INDEX`](create-index.html) followed by an optional index name and an `ON` clause identifying the table and column(s) to index. For each column, you can choose whether to sort ascending (`ASC`) or descending (`DESC`). diff --git a/not-null.md b/not-null.md index 5c716a20aed..ac111d32e04 100644 --- a/not-null.md +++ b/not-null.md @@ -4,16 +4,31 @@ summary: The NOT NULL constraint specifies the column may not contain NULL value toc: false --- -The Not Null [constraint](constraints.html) specifies the column may not contain *NULL* values. +The Not Null [constraint](constraints.html) specifies a column may not contain *NULL* values.
## Details -For more information about *NULL*, see [Null Handling](null-handling.html). +- `INSERT` or `UPDATE` statements containing *NULL* values are rejected. This includes `INSERT` statements that do not include values for any columns that do not have a [Default Value constraint](default-value.html). + + For example, if the table `foo` has columns `a` and `b` (and `b` *does not* have a Default Value), when you run the following command: + + ~~~ sql + > INSERT INTO foo (a) VALUES (1); + ~~~ + + CockroachDB tries to write a *NULL* value into column `b`. If that column has the Not Null constraint, the `INSERT` statement is rejected. + +- You can only define the Not Null constraint when [creating a table](#syntax); you cannot add it to an existing table. However, you can [migrate data](constraints.html#table-migrations-to-add-or-change-immutable-constraints) from your current table to a new table with the constraint you want to use. + {{site.data.alerts.callout_info}}In the future we plan to support adding the Not Null constraint to existing tables.{{site.data.alerts.end}} + +- For more information about *NULL*, see [Null Handling](null-handling.html). ## Syntax +You can only apply the Not Null constraint to individual columns. + {% include sql/diagrams/not_null_column_level.html %} | Parameter | Description | @@ -21,22 +36,10 @@ For more information about *NULL*, see [Null Handling](null-handling.html). | `table_name` | The name of the table you're creating. | | `column_name` | The name of the constrained column. | | `column_type` | The constrained column's [data type](data-types.html). | -| `column_constraints` | Any other column-level [constraints](constraints.html) you want to apply. | +| `column_constraints` | Any other column-level [constraints](constraints.html) you want to apply to this column. | | `column_def` | Definitions for any other columns in the table. | | `table_constraints` | Any table-level [constraints](constraints.html) you want to apply. | -**Example** - -~~~ sql -> CREATE TABLE customers ( - customer_id INT PRIMARY KEY, - cust_name STRING(30) NULL, - cust_email STRING(100) NOT NULL - ); -~~~ - -{{site.data.alerts.callout_info}}You cannot apply the Not Null constraint to multiple columns (i.e. at the table level).{{site.data.alerts.end}} - ## Usage Example ~~~ sql @@ -51,10 +54,17 @@ For more information about *NULL*, see [Null Handling](null-handling.html). ~~~ pq: null value in column "cust_email" violates not-null constraint ~~~ +~~~ sql +> INSERT INTO customers (customer_id, cust_name) VALUES (1, 'Smith'); +~~~ +~~~ +pq: null value in column "cust_email" violates not-null constraint +~~~ ## See Also - [Constraints](constraints.html) +- [`DROP CONSTRAINT`](drop-constraint.html) - [Check constraint](check.html) - [Default Value constraint](default-value.html) - [Foreign Key constraint](foreign-key.html) diff --git a/null-handling.md b/null-handling.md index 63877ca9165..6c6bf8234ea 100644 --- a/null-handling.md +++ b/null-handling.md @@ -300,7 +300,7 @@ Note that the `NULLS FIRST` and `NULLS LAST` options of the `ORDER BY` clause ar ## NULLs and Unique Constraints -`NULL` values are not considered unique. Therefore, if a table has a `UNIQUE` constraint on one or more columns that are optional (nullable), it is possible to insert multiple rows with `NULL` values in those columns, as shown in the example below. +`NULL` values are not considered unique. Therefore, if a table has a Unique constraint on one or more columns that are optional (nullable), it is possible to insert multiple rows with `NULL` values in those columns, as shown in the example below. ~~~ sql > CREATE TABLE t2(a INT, b INT UNIQUE); @@ -323,9 +323,7 @@ Note that the `NULLS FIRST` and `NULLS LAST` options of the `ORDER BY` clause ar ## NULLs and CHECK Constraints -A [`CHECK`](check.html) constraint expression that evaluates to `NULL` is considered to pass, allowing for concise expressions like `discount < price` without worrying about adding `OR discount IS NULL` clauses. When non-null validation is desired, the usual `NOT NULL` constraint can be -used along side a `CHECK` expression. - +A [Check constraint](check.html) expression that evaluates to `NULL` is considered to pass, allowing for concise expressions like `discount < price` without worrying about adding `OR discount IS NULL` clauses. When non-null validation is desired, the usual Not Null constraint can be used along side a Check constraint. ~~~ sql > CREATE TABLE products (id STRING PRIMARY KEY, price INT NOT NULL CHECK (price > 0), discount INT, CHECK (discount <= price)); diff --git a/primary-key.md b/primary-key.md index 4e827f42547..fd13be5c33d 100644 --- a/primary-key.md +++ b/primary-key.md @@ -4,21 +4,36 @@ summary: The Primary Key constraint specifies that the columns can be used to un toc: false --- -The Primary Key [constraints](constraints.html) specifies that the columns can be used to uniquely identify rows in a table; this means it combines both the Unique and Not Null constraints. +The Primary Key [constraint](constraints.html) specifies that the constrained columns' values must uniquely identify each row. -{{site.data.alerts.callout_info}}The Primary Key for a table can only be specified in the CREATE TABLE statement. It can't be changed later using ALTER TABLE.{{site.data.alerts.end}} +Unlike other constraints which have very specific uses, the Primary Key constraint *should be used for every table* because it provides an intrinsic structure to the table's data. This both makes it easier to understand, as well as improving query performance. + +{{site.data.alerts.callout_info}}A table's primary key can only be specified in the CREATE TABLE statement. It can't be changed later using ALTER TABLE, though it is possible to go through a process to create a new table with the new primary key you want and then migrate the data.{{site.data.alerts.end}}
## Details -- A Primary Key constraint requires that the column values are unique and **do not** contain *NULL* values. You can optionally give the constraint a name using the `CONSTRAINT name` syntax, otherwise the constraint and its associated unique index are called **primary**. - {{site.data.alerts.callout_info}}Strictly speaking, a primary key's unique index is not created, it's derived from the keys under which the data is stored so it takes no additional space. However, it appears as a normal unique index when using commands like SHOW INDEXES.{{site.data.alerts.end}} -- Columns that are part of a Primary Key are mandatory (NOT NULL). If an optional (nullable) column is made part of a Primary Key, it is made mandatory (NOT NULL). +- Tables can only have one primary key. +- To ensure each row has a unique identifier, the Primary Key constraint combines the properties of both the [Unique](unique.html) and [Not Null](not-null.html) constraints. The properties of both constraints are necessary to make sure each row's primary key columns contain distinct sets of values. + + - The properties of the Unique constraint ensure that each value is distinct from all other values. + + - However, because *NULL* values never equal other *NULL* values, the Unique constraint is not enough (two rows can appear the same if one of the values is *NULL*). To prevent the appearance of duplicated values, the Primary Key constraint also enforces the properties of the Not Null constraint. + +- The columns in the Primary Key constraint are used to create its `primary` [index](indexes.html), which CockroachDB uses by default to access the table's data. + + This index does not take up additional disk space (unlike secondary indexes, which do) because CockroachDB uses the `primary` index to structure the table's data in the key-value layer. For more information, see our blog post [SQL in CockroachDB: Mapping Table Data to Key-Value Storage](https://www.cockroachlabs.com/blog/sql-in-cockroachdb-mapping-table-data-to-key-value-storage/). + +- For optimal performance, we recommend defining a primary key for *every* table. + + If you create a table without defining a primary key, CockroachDB uses a unique identifier for each row, which it then uses for the `primary` index. Because you cannot meaningfully use this unique row identifier column to filter table data, it does not offer any performance optimization. This means you will always have improved performance by defining a primary key for a table. For more information, see our blog post [Index Selection in CockroachDB](https://www.cockroachlabs.com/blog/index-selection-cockroachdb-2/). ## Syntax -### Single Column (Column Level) +Primary Key constraints can be defined at the [table level](#table-level). However, if you only want the constraint to apply to a single column, it can be applied at the [column level](#column-level). + +### Column Level {% include sql/diagrams/primary_key_column_level.html %} @@ -27,7 +42,7 @@ The Primary Key [constraints](constraints.html) specifies that the columns can b | `table_name` | The name of the table you're creating. | | `column_name` | The name of the Primary Key column. | | `column_type` | The Primary Key column's [data type](data-types.html). | -| `column_constraints` | Any other column-level [constraints](constraints.html) you want to apply. | +| `column_constraints` | Any other column-level [constraints](constraints.html) you want to apply to this column. | | `column_def` | Definitions for any other columns in the table. | | `table_constraints` | Any table-level [constraints](constraints.html) you want to apply. | @@ -43,7 +58,7 @@ The Primary Key [constraints](constraints.html) specifies that the columns can b ); ~~~ -### Multiple Column (Table Level) +### Table Level {% include sql/diagrams/primary_key_table_level.html %} @@ -53,7 +68,7 @@ The Primary Key [constraints](constraints.html) specifies that the columns can b | `column_def` | Definitions for any other columns in the table. | | `name` | The name you want to use for the constraint, which must be unique to its table and follow these [identifier rules](keywords-and-identifiers.html#identifiers). | | `column_name` | The name of the column you want to use as the Primary Key.

The order in which you list columns here affects the structure of the `primary` index.| -| `table_constraints` | Any table-level [constraints](constraints.html) you want to apply. | +| `table_constraints` | Any other table-level [constraints](constraints.html) you want to apply. | **Example** @@ -77,6 +92,7 @@ The Primary Key [constraints](constraints.html) specifies that the columns can b ); > INSERT INTO inventories VALUES (1, 1, 100); + > INSERT INTO inventories VALUES (1, 1, 200); ~~~ ~~~ @@ -89,10 +105,6 @@ pq: duplicate key value (product_id,warehouse_id)=(1,1) violates unique constrai pq: null value in column "warehouse_id" violates not-null constraint ~~~ - - - - ## See Also - [Constraints](constraints.html) @@ -102,3 +114,4 @@ pq: null value in column "warehouse_id" violates not-null constraint - [Not Null constraint](not-null.html) - [Unique constraint](unique.html) - [`SHOW CONSTRAINTS`](show-constraints.html) + diff --git a/select.md b/select.md index 5e4cc0be6ac..e172a5128df 100644 --- a/select.md +++ b/select.md @@ -122,7 +122,7 @@ WHERE balance > 2500 AND NOT type = 'checking'; #### Select Distinct Rows -Columns without the [`UNIQUE`](unique.html) constraint can have multiple instances of the same value. +Columns without the [Primary Key](primary-key.html) or [Unique](unique.html) constraints can have multiple instances of the same value. ~~~ sql > SELECT name diff --git a/serial.md b/serial.md index 2e46a53d3e3..efea4a37a72 100644 --- a/serial.md +++ b/serial.md @@ -31,7 +31,7 @@ A `SERIAL` column supports values up to 8 bytes in width, but the total storage ### Use `SERIAL` to Auto-Generate Primary Keys -In this example, we create a table with the `SERIAL` column as the `PRIMARY KEY` so we can auto-generate unique IDs on insert. +In this example, we create a table with the `SERIAL` column as the primary key so we can auto-generate unique IDs on insert. ~~~ sql > CREATE TABLE serial (a SERIAL PRIMARY KEY, b STRING(30), c BOOL); diff --git a/show-constraints.md b/show-constraints.md index d83ed7c70d8..4e7f6bd89d3 100644 --- a/show-constraints.md +++ b/show-constraints.md @@ -4,7 +4,7 @@ summary: The SHOW CONSTRAINTS statement lists the constraints on a table. toc: false --- -The `SHOW CONSTRAINTS` [statement](sql-statements.html) lists all named [constraints](constraints.html) as well as any unnamed `CHECK` constraints on a table. +The `SHOW CONSTRAINTS` [statement](sql-statements.html) lists all named [constraints](constraints.html) as well as any unnamed Check constraints on a table. {{site.data.alerts.callout_danger}}The SHOW CONSTRAINTS statement is under development; the exact output will continue to change.{{site.data.alerts.end}} @@ -39,8 +39,8 @@ Field | Description `Table` | The name of the table. `Name` | The name of the constraint. `Type` | The type of constraint. -`Column(s)` | The column(s) to which the constraint applies. For `CHECK` constraints, column information will be in `Details` and this field will be `NULL`. -`Details` | The conditions for a `CHECK` constraint. +`Column(s)` | The columns to which the constraint applies. For [Check constraints](check.html), column information will be in `Details` and this field will be `NULL`. +`Details` | The conditions for a Check constraint. ## Example diff --git a/sql-feature-support.md b/sql-feature-support.md index e115b56a531..26ce602f582 100644 --- a/sql-feature-support.md +++ b/sql-feature-support.md @@ -46,12 +46,12 @@ table tr td:nth-child(2) { | Component | Supported | Type | Details | |-----------|-----------|------|---------| -| `NOT NULL` | ✓ | Standard | [`NOT NULL` documentation](not-null.html) | -| `UNIQUE` | ✓ | Standard | [`UNIQUE` documentation](unique.html) | -| `PRIMARY KEY` | ✓ | Standard | [`PRIMARY KEY` documentation](primary-key.html) | -| `CHECK` | ✓ | Standard | [`CHECK` documentation](check.html) | -| `FOREIGN KEY` | ✓ | Standard | [`FOREIGN KEY` documentation](foreign-key.html) | -| `DEFAULT VALUE` | ✓ | Standard | [`DEFAULT VALUE` documentation](default-value.html) | +| Not Null | ✓ | Standard | [Not Null documentation](not-null.html) | +| Unique | ✓ | Standard | [Unique documentation](unique.html) | +| Primary Key | ✓ | Standard | [Primary Key documentation](primary-key.html) | +| Check | ✓ | Standard | [Check documentation](check.html) | +| Foreign Key | ✓ | Standard | [Foreign Key documentation](foreign-key.html) | +| Default Value | ✓ | Standard | [Default Value documentation](default-value.html) | ### Transactions diff --git a/transactions.md b/transactions.md index 25f815b599e..81d27639185 100644 --- a/transactions.md +++ b/transactions.md @@ -57,7 +57,7 @@ To handle errors in transactions, you should listen for the following types of s For example, you might want to read values from the database to see if the transaction successfully wrote values before attempting to write the values again or, alternatively, you might write the data again without seeing if the first write attempt succeeded. -- **SQL Errors**: All other errors, which indicate that a statement in the transaction failed. For example, violating the `UNIQUE` constraint generates an `23505` error. After encountering these errors, you can either issue a `COMMIT` or `ROLLBACK` to abort the transaction and revert the database to its state before the transaction began. +- **SQL Errors**: All other errors, which indicate that a statement in the transaction failed. For example, violating the Unique constraint generates an `23505` error. After encountering these errors, you can either issue a `COMMIT` or `ROLLBACK` to abort the transaction and revert the database to its state before the transaction began. If you want to attempt the same set of statements again, you must begin a completely new transaction. diff --git a/unique.md b/unique.md index 78f9aef71b7..5d1ce0a0a81 100644 --- a/unique.md +++ b/unique.md @@ -1,20 +1,28 @@ --- title: Unique Constraint -summary: The Unique constraint specifies that the columns values are unique, though they may contain NULL values. +summary: The Unique constraint specifies that each non-NULL value in the constrained column must be unique. toc: false --- -The Unique [constraints](constraints.html) specifies that the columns values are unique, though they may contain *NULL* values. +The Unique [constraint](constraints.html) specifies that each non-*NULL* value in the constrained column must be unique.
## Details -- Be aware that if a table has a `UNIQUE` constraint on column(s) that are optional (nullable), it is still possible to insert duplicate rows that appear to violate the constraint if they contain a *NULL* value in at least one of the columns. This is because *NULL*s are never considered equal and hence don't violate the uniqueness constraint. +- You can insert *NULL* values into columns with the Unique constraint because *NULL* is the absence of a value, so it is never equal to other *NULL* values and not considered a duplicate value. This means that it's possible to insert rows that appear to be duplicates if one of the values is *NULL*. + + If you need to strictly enforce uniqueness, use the [Not Null constraint](not-null.html) in addition to the Unique constraint. You can also achieve the same behavior through the table's [Primary Key](primary-key.html). + +- Columns with the Unique constraint automatically have an [index](indexes.html) created with the name `
__key`. To avoid having two identical indexes, you should not create indexes that exactly match the Unique constraint's columns and order.

The Unique constraint depends on the automatically created index, so dropping the index also drops the Unique constraint. +- When using the Unique constraint on multiple columns, the collective values of the columns must be unique. This *does not* mean that each value in each column must be unique, as if you had applied the Unique constraint to each column individually. +- You can define the Unique constraint when [creating a table](#syntax), or you can add it to existing tables through [`ADD CONSTRAINT`](add-constraint.html#add-the-unique-constraint). ## Syntax -### Single Column (Column Level) +Unique constraints can be defined at the [table level](#table-level). However, if you only want the constraint to apply to a single column, it can be applied at the [column level](#column-level). + +### Column Level {% include sql/diagrams/unique_column_level.html %} @@ -23,7 +31,7 @@ The Unique [constraints](constraints.html) specifies that the columns values are | `table_name` | The name of the table you're creating. | | `column_name` | The name of the constrained column. | | `column_type` | The constrained column's [data type](data-types.html). | -| `column_constraints` | Any other column-level [constraints](constraints.html) you want to apply. | +| `column_constraints` | Any other column-level [constraints](constraints.html) you want to apply to this column. | | `column_def` | Definitions for any other columns in the table. | | `table_constraints` | Any table-level [constraints](constraints.html) you want to apply. | @@ -37,7 +45,7 @@ The Unique [constraints](constraints.html) specifies that the columns values are ); ~~~ -### Multiple Column (Table Level) +### Table Level {% include sql/diagrams/unique_table_level.html %} @@ -47,7 +55,7 @@ The Unique [constraints](constraints.html) specifies that the columns values are | `column_def` | Definitions for any other columns in the table. | | `name` | The name you want to use for the constraint, which must be unique to its table and follow these [identifier rules](keywords-and-identifiers.html#identifiers). | | `column_name` | The name of the column you want to constrain.| -| `table_constraints` | Any table-level [constraints](constraints.html) you want to apply. | +| `table_constraints` | Any other table-level [constraints](constraints.html) you want to apply. | **Example** @@ -62,8 +70,6 @@ The Unique [constraints](constraints.html) specifies that the columns values are ## Usage Example -Be aware that if a table has a `UNIQUE` constraint on column(s) that are optional (nullable), it is still possible to insert duplicate rows that appear to violate the constraint if they contain a *NULL* value in at least one of the columns. This is because *NULL*s are never considered equal and hence don't violate the uniqueness constraint. - ~~~ sql > CREATE TABLE IF NOT EXISTS logon ( login_id INT PRIMARY KEY, @@ -72,22 +78,37 @@ Be aware that if a table has a `UNIQUE` constraint on column(s) that are optiona UNIQUE (customer_id, sales_id) ); -> INSERT INTO logon (login_id, customer_id, sales_id) VALUES (1, 2, NULL); -> INSERT INTO logon (login_id, customer_id, sales_id) VALUES (2, 2, NULL); -> SELECT * FROM logon; +> INSERT INTO logon (login_id, customer_id, sales_id) VALUES (1, 2, 1); + +> INSERT INTO logon (login_id, customer_id, sales_id) VALUES (2, 2, 1); +~~~ +~~~ +duplicate key value (customer_id,sales_id)=(2,1) violates unique constraint "logon_customer_id_sales_id_key" +~~~ + +As mentioned in the [details](#details) above, it is possible when using the Unique constraint alone to insert *NULL* values in a way that causes rows to appear to have rows with duplicate values. + +~~~ sql +> INSERT INTO logon (login_id, customer_id, sales_id) VALUES (3, 2, NULL); + +> INSERT INTO logon (login_id, customer_id, sales_id) VALUES (4, 2, NULL); + +> SELECT customer_id, sales_id FROM logon; ~~~ ~~~ -+----------+-------------+----------+ -| login_id | customer_id | sales_id | -+----------+-------------+----------+ -| 1 | 2 | NULL | -| 2 | 2 | NULL | -+----------+-------------+----------+ ++-------------+----------+ +| customer_id | sales_id | ++-------------+----------+ +| 2 | 1 | +| 2 | NULL | +| 2 | NULL | ++-------------+----------+ ~~~ ## See Also - [Constraints](constraints.html) +- [`DROP CONSTRAINT`](drop-constraint.html) - [Check constraint](check.html) - [Default Value constraint](default-value.html) - [Foreign Key constraint](foreign-key.html) diff --git a/upsert.md b/upsert.md index 5165cf38ee6..2fe0f70f9d7 100644 --- a/upsert.md +++ b/upsert.md @@ -6,7 +6,7 @@ toc: false The `UPSERT` [statement](sql-statements.html) is short-hand for [`INSERT ON CONFLICT`](insert.html). It inserts rows in cases where specified values do not violate uniqueness constraints, and it updates rows in cases where values do violate uniqueness constraints. -Note that `UPSERT` considers uniqueness only for [`PRIMARY KEY`](primary-key.html) columns. `INSERT ON CONFLICT` is more flexible and can be used to consider uniqueness for other columns. For more details, see [How `UPSERT` Transforms into `INSERT ON CONFLICT`](#how-upsert-transforms-into-insert-on-conflict) below. +Note that `UPSERT` considers uniqueness only for [primary key](primary-key.html) columns. `INSERT ON CONFLICT` is more flexible and can be used to consider uniqueness for other columns. For more details, see [How `UPSERT` Transforms into `INSERT ON CONFLICT`](#how-upsert-transforms-into-insert-on-conflict) below.
@@ -30,7 +30,7 @@ Parameter | Description ## How `UPSERT` Transforms into `INSERT ON CONFLICT` -`UPSERT` considers uniqueness only for [`PRIMARY KEY`](primary-key.html) columns. For example, assuming that columns `a` and `b` are the primary key, the following `UPSERT` and `INSERT ON CONFLICT` statements are equivalent: +`UPSERT` considers uniqueness only for [primary key](primary-key.html) columns. For example, assuming that columns `a` and `b` are the primary key, the following `UPSERT` and `INSERT ON CONFLICT` statements are equivalent: ~~~ sql > UPSERT INTO t (a, b, c) VALUES (1, 2, 3); @@ -108,7 +108,7 @@ In this example, the `id` column is the primary key. Because the inserted `id` v ### Upsert that Fails (Conflict on Non-Primay Key) -`UPSERT` will not update rows when the uniquness conflict is on columns not in the primary key. In this example, the `a` column is the primary key, but the `b` column also has the [`UNIQUE`](unique.html) constraint. Because the inserted `b` value is not unique, the `UPSERT` fails. +`UPSERT` will not update rows when the uniquness conflict is on columns not in the primary key. In this example, the `a` column is the primary key, but the `b` column also has the [Unique constraint](unique.html). Because the inserted `b` value is not unique, the `UPSERT` fails. ~~~ sql > SELECT * FROM unique_test; @@ -129,7 +129,7 @@ In this example, the `id` column is the primary key. Because the inserted `id` v pq: duplicate key value (b)=(1) violates unique constraint "unique_test_b_key" ~~~ -In such a case, you would need to use the [`INSERT ON CONFLICT`](insert.html) statement to specify the `b` column as the column with the `UNIQUE` constraint. +In such a case, you would need to use the [`INSERT ON CONFLICT`](insert.html) statement to specify the `b` column as the column with the Unique constraint. ~~~ sql > INSERT INTO unique_test VALUES (4, 1) ON CONFLICT (b) DO UPDATE SET a = excluded.a;