From e2555ccf91e6a307b182fb5cc8b2d89a711da0d4 Mon Sep 17 00:00:00 2001 From: Sean Loiselle Date: Mon, 28 Nov 2016 11:21:00 -0500 Subject: [PATCH] constraint pages --- .gitignore | 1 + _data/sidebar_doc.yml | 27 +- .../sql/diagrams/check_column_level.html | 70 +++++ _includes/sql/diagrams/check_table_level.html | 60 ++++ .../diagrams/default_value_column_level.html | 64 ++++ .../diagrams/foreign_key_column_level.html | 75 +++++ .../sql/diagrams/foreign_key_table_level.html | 85 ++++++ .../sql/diagrams/not_null_column_level.html | 59 ++++ .../diagrams/primary_key_column_level.html | 59 ++++ .../diagrams/primary_key_columns_level.html | 54 ++++ .../sql/diagrams/primary_key_table_level.html | 63 ++++ .../sql/diagrams/unique_column_level.html | 59 ++++ .../sql/diagrams/unique_table_level.html | 63 ++++ beta-20160519.md | 6 +- beta-20160829.md | 4 +- beta-20161013.md | 4 +- beta-20161110.md | 72 +++++ beta-20161201.md | 4 +- check.md | 106 +++++++ constraints.md | 283 +----------------- create-index.md | 6 +- create-table-as.md | 2 +- create-table.md | 10 +- default-value.md | 78 +++++ delete.md | 2 +- foreign-key.md | 162 ++++++++++ generate/main.go | 60 ++++ indexes.md | 4 +- information-schema.md | 4 +- insert.md | 2 +- interleave-in-parent.md | 8 +- learn-cockroachdb-sql.md | 4 +- not-null.md | 63 ++++ null-handling.md | 2 +- primary-key.md | 104 +++++++ select.md | 2 +- sql-feature-support.md | 12 +- unique.md | 96 ++++++ upsert.md | 8 +- 39 files changed, 1528 insertions(+), 319 deletions(-) create mode 100644 _includes/sql/diagrams/check_column_level.html create mode 100644 _includes/sql/diagrams/check_table_level.html create mode 100644 _includes/sql/diagrams/default_value_column_level.html create mode 100644 _includes/sql/diagrams/foreign_key_column_level.html create mode 100644 _includes/sql/diagrams/foreign_key_table_level.html create mode 100644 _includes/sql/diagrams/not_null_column_level.html create mode 100644 _includes/sql/diagrams/primary_key_column_level.html create mode 100644 _includes/sql/diagrams/primary_key_columns_level.html create mode 100644 _includes/sql/diagrams/primary_key_table_level.html create mode 100644 _includes/sql/diagrams/unique_column_level.html create mode 100644 _includes/sql/diagrams/unique_table_level.html create mode 100644 check.md create mode 100644 default-value.md create mode 100644 foreign-key.md create mode 100644 not-null.md create mode 100644 primary-key.md create mode 100644 unique.md diff --git a/.gitignore b/.gitignore index 2b6ecf3bfec..3994cff53eb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ generate/generate Railroad.jar .sass-cache _site +.jekyll-metadata \ No newline at end of file diff --git a/_data/sidebar_doc.yml b/_data/sidebar_doc.yml index 3b309359941..c53bec3ae14 100644 --- a/_data/sidebar_doc.yml +++ b/_data/sidebar_doc.yml @@ -205,15 +205,36 @@ entries: url: /sql-grammar.html thirdlevel: + - title: Constraints + thirdlevelitems: + + - title: Overview + url: /constraints.html + + - title: Check + url: /check.html + + - title: Default Value + url: /default-value.html + + - title: Foreign Keys + url: /foreign-key.html + + - title: Not Null + url: /not-null.html + + - title: Primary Key + url: /primary-key.html + + - title: Unique + url: /unique.html + - title: Data Definition thirdlevelitems: - title: Keywords & Identifiers url: /keywords-and-identifiers.html - - title: Constraints - url: /constraints.html - - title: Indexes url: /indexes.html diff --git a/_includes/sql/diagrams/check_column_level.html b/_includes/sql/diagrams/check_column_level.html new file mode 100644 index 00000000000..2c7f2fb7e4f --- /dev/null +++ b/_includes/sql/diagrams/check_column_level.html @@ -0,0 +1,70 @@ + + + + + + + CREATE + + + TABLE + + + + table_name + + + + ( + + + + column_name + + + + + column_type + + + + CHECK + + + ( + + + + check_expr + + + + ) + + + + column_constraints + + + + , + + + + column_def + + + + + table_constraints + + + + ) + + + ) + + + + \ No newline at end of file diff --git a/_includes/sql/diagrams/check_table_level.html b/_includes/sql/diagrams/check_table_level.html new file mode 100644 index 00000000000..c1e4432a209 --- /dev/null +++ b/_includes/sql/diagrams/check_table_level.html @@ -0,0 +1,60 @@ + + + + + + + CREATE + + + TABLE + + + + table_name + + + + ( + + + + column_def + + + + , + + + CONSTRAINT + + + + name + + + + CHECK + + + ( + + + + check_expr + + + + ) + + + + table_constraints + + + + ) + + + + \ No newline at end of file diff --git a/_includes/sql/diagrams/default_value_column_level.html b/_includes/sql/diagrams/default_value_column_level.html new file mode 100644 index 00000000000..879dfde256f --- /dev/null +++ b/_includes/sql/diagrams/default_value_column_level.html @@ -0,0 +1,64 @@ + + + + + + + CREATE + + + TABLE + + + + table_name + + + + ( + + + + column_name + + + + + column_type + + + + DEFAULT + + + + default_value + + + + + column_constraints + + + + , + + + + column_def + + + + + table_constraints + + + + ) + + + ) + + + + \ No newline at end of file diff --git a/_includes/sql/diagrams/foreign_key_column_level.html b/_includes/sql/diagrams/foreign_key_column_level.html new file mode 100644 index 00000000000..597fd829431 --- /dev/null +++ b/_includes/sql/diagrams/foreign_key_column_level.html @@ -0,0 +1,75 @@ + + + + + + + CREATE + + + TABLE + + + + table_name + + + + ( + + + + column_name + + + + + column_type + + + + REFERENCES + + + + parent_table + + + + ( + + + + ref_column_name + + + + ) + + + + column_constraints + + + + , + + + + column_def + + + + + table_constraints + + + + ) + + + ) + + + + \ No newline at end of file diff --git a/_includes/sql/diagrams/foreign_key_table_level.html b/_includes/sql/diagrams/foreign_key_table_level.html new file mode 100644 index 00000000000..6b68e492f92 --- /dev/null +++ b/_includes/sql/diagrams/foreign_key_table_level.html @@ -0,0 +1,85 @@ + + + + + + + CREATE + + + TABLE + + + + table_name + + + + ( + + + + column_def + + + + , + + + CONSTRAINT + + + + name + + + + FOREIGN KEY + + + ( + + + + fk_column_name + + + + , + + + ) + + + REFERENCES + + + + parent_table + + + + ( + + + + ref_column_name + + + + , + + + ) + + + + table_constraints + + + + ) + + + + \ No newline at end of file diff --git a/_includes/sql/diagrams/not_null_column_level.html b/_includes/sql/diagrams/not_null_column_level.html new file mode 100644 index 00000000000..69e7f49abad --- /dev/null +++ b/_includes/sql/diagrams/not_null_column_level.html @@ -0,0 +1,59 @@ + + + + + + + CREATE + + + TABLE + + + + table_name + + + + ( + + + + column_name + + + + + column_type + + + + NOT NULL + + + + column_constraints + + + + , + + + + column_def + + + + + table_constraints + + + + ) + + + ) + + + + \ No newline at end of file diff --git a/_includes/sql/diagrams/primary_key_column_level.html b/_includes/sql/diagrams/primary_key_column_level.html new file mode 100644 index 00000000000..f3ff991c8a0 --- /dev/null +++ b/_includes/sql/diagrams/primary_key_column_level.html @@ -0,0 +1,59 @@ + + + + + + + CREATE + + + TABLE + + + + table_name + + + + ( + + + + column_name + + + + + column_type + + + + PRIMARY KEY + + + + column_constraints + + + + , + + + + column_def + + + + + table_constraints + + + + ) + + + ) + + + + \ No newline at end of file diff --git a/_includes/sql/diagrams/primary_key_columns_level.html b/_includes/sql/diagrams/primary_key_columns_level.html new file mode 100644 index 00000000000..4e04a8b61ee --- /dev/null +++ b/_includes/sql/diagrams/primary_key_columns_level.html @@ -0,0 +1,54 @@ + + + + + + + CREATE + + + TABLE + + + + any_name + + + + ( + + + + name + + + + + typename + + + + PRIMARY KEY + + + , + + + + column_def + + + + + other_constraints + + + + ) + + + ) + + + + \ No newline at end of file diff --git a/_includes/sql/diagrams/primary_key_table_level.html b/_includes/sql/diagrams/primary_key_table_level.html new file mode 100644 index 00000000000..9f88b49ad97 --- /dev/null +++ b/_includes/sql/diagrams/primary_key_table_level.html @@ -0,0 +1,63 @@ + + + + + + + CREATE + + + TABLE + + + + table_name + + + + ( + + + + column_def + + + + , + + + CONSTRAINT + + + + name + + + + PRIMARY KEY + + + ( + + + + column_name + + + + , + + + ) + + + + table_constraints + + + + ) + + + + \ No newline at end of file diff --git a/_includes/sql/diagrams/unique_column_level.html b/_includes/sql/diagrams/unique_column_level.html new file mode 100644 index 00000000000..99b57ffe92d --- /dev/null +++ b/_includes/sql/diagrams/unique_column_level.html @@ -0,0 +1,59 @@ + + + + + + + CREATE + + + TABLE + + + + table_name + + + + ( + + + + column_name + + + + + column_type + + + + UNIQUE + + + + column_constraints + + + + , + + + + column_def + + + + + table_constraints + + + + ) + + + ) + + + + \ No newline at end of file diff --git a/_includes/sql/diagrams/unique_table_level.html b/_includes/sql/diagrams/unique_table_level.html new file mode 100644 index 00000000000..65cf9cd21b7 --- /dev/null +++ b/_includes/sql/diagrams/unique_table_level.html @@ -0,0 +1,63 @@ + + + + + + + CREATE + + + TABLE + + + + table_name + + + + ( + + + + column_def + + + + , + + + CONSTRAINT + + + + name + + + + UNIQUE + + + ( + + + + column_name + + + + , + + + ) + + + + table_constraints + + + + ) + + + + \ No newline at end of file diff --git a/beta-20160519.md b/beta-20160519.md index 72b0539b825..4a07f4bc9b8 100644 --- a/beta-20160519.md +++ b/beta-20160519.md @@ -20,15 +20,15 @@ summary: Additions and changes in CockroachDB version beta-20160519. ### New Features - `DO NOTHING` is now supported in [`INSERT ... ON CONFLICT`](insert.html) statements. [#6633](https://github.com/cockroachdb/cockroach/pull/6633) -- [`CHECK`](constraints.html#check) constraints can now be specified at the table level. [#6625](https://github.com/cockroachdb/cockroach/pull/6625) +- [`CHECK`](check.html) constraints can now be specified at the table level. [#6625](https://github.com/cockroachdb/cockroach/pull/6625) - Binary encoding is now supported in the network protocol for `BOOL`, `FLOAT`, `DECIMAL`, and `STRING` types, improving compatiblity with some PostgreSQL drivers. [#6661](https://github.com/cockroachdb/cockroach/pull/6661) - The new `cockroach freeze-cluster` [command](cockroach-commands.html) has been added to the command-line interface; it will be used in the upgrade process for a future beta release. [#6675](https://github.com/cockroachdb/cockroach/pull/6675) ### Bug Fixes - [`EXPLAIN DELETE`](explain.html) no longer executes the `DELETE` statement. [#6622](https://github.com/cockroachdb/cockroach/pull/6622) -- [`CHECK`](constraints.html#check) constraints are now enforced during [`UPDATE`](update.html) statments. [#6753](https://github.com/cockroachdb/cockroach/pull/6753) -- [`CHECK`](constraints.html#check) constraints now work correctly when columns have been dropped. [#6730](https://github.com/cockroachdb/cockroach/pull/6730) +- [`CHECK`](check.html) constraints are now enforced during [`UPDATE`](update.html) statements. [#6753](https://github.com/cockroachdb/cockroach/pull/6753) +- [`CHECK`](check.html) constraints now work correctly when columns have been dropped. [#6730](https://github.com/cockroachdb/cockroach/pull/6730) - Tuples and the `DEFAULT` keyword now work in [`INSERT ... ON CONFLICT DO UPDATE`](insert.html) statements. [#6636](https://github.com/cockroachdb/cockroach/pull/6636) - Errors are now reported with standard PostgreSQL error codes in more places. [#6652](https://github.com/cockroachdb/cockroach/pull/6652), [#6554](https://github.com/cockroachdb/cockroach/pull/6554) - Fixed a panic while a node is attempting a clean shutdown. [#6677](https://github.com/cockroachdb/cockroach/pull/6677) diff --git a/beta-20160829.md b/beta-20160829.md index 15e88ea168b..c7a8ef97a0f 100644 --- a/beta-20160829.md +++ b/beta-20160829.md @@ -27,7 +27,7 @@ summary: Additions and changes in CockroachDB version beta-20160829. - `AS OF SYSTEM TIME` can now be used with `JOIN` queries. [#8198](https://github.com/cockroachdb/cockroach/pull/8198) - The type `BIT` now works correctly (as a shorthand for `BIT(1)`). The length limit is now enforced. [#8326](https://github.com/cockroachdb/cockroach/pull/8326) - The `SHOW` commands now only show tables that the current user has permission to access. [#8070](https://github.com/cockroachdb/cockroach/pull/8070) -- [Foreign keys](constraints.html#foreign-keys) can now use a prefix of an index. [#8059](https://github.com/cockroachdb/cockroach/pull/8059) +- [Foreign keys](foreign-key.html) can now use a prefix of an index. [#8059](https://github.com/cockroachdb/cockroach/pull/8059) - The standard `information_schema` database is now partially supported. New tables will be added to this database in future beta releases. [#7965](https://github.com/cockroachdb/cockroach/pull/7965), [#8119](https://github.com/cockroachdb/cockroach/pull/8119) ### Bug Fixes @@ -71,7 +71,7 @@ summary: Additions and changes in CockroachDB version beta-20160829. - The new [SQL Feature Support](sql-feature-support.html) page explains which standard SQL features are supported by CockroachDB. [#550](https://github.com/cockroachdb/docs/pull/550) - The new Features on Develop Branch page tracks features that are available on the `develop` branch but not yet on `master`. [#552](https://github.com/cockroachdb/docs/pull/552) (Page no longer available.) -- Added docs on [foreign key constraints](constraints.html#foreign-keys). [#528](https://github.com/cockroachdb/docs/pull/528) +- Added docs on [foreign key constraints](foreign-key.html). [#528](https://github.com/cockroachdb/docs/pull/528) - Added docs on the [`TRUNCATE`](truncate.html) statement. [#542](https://github.com/cockroachdb/docs/pull/542) - Updated [Recommended Production Settings](recommended-production-settings.html) to include cache size recommendations for machines running multiple applications and `systemd`-specific instructions for increasing the file descriptors limit. [#532](https://github.com/cockroachdb/docs/pull/532), [#554](https://github.com/cockroachdb/docs/pull/554) - Fixed errors in the commands for [starting CockroachDB in Docker](start-a-local-cluster-in-docker.html). [#567](https://github.com/cockroachdb/docs/pull/567) diff --git a/beta-20161013.md b/beta-20161013.md index 1ae54efd16f..39800420f4e 100644 --- a/beta-20161013.md +++ b/beta-20161013.md @@ -27,8 +27,8 @@ This week's release includes many user-visible changes and features that have be - The [`CREATE TABLE AS`](create-table-as.html) statement can now be used to create a table based on the results of a `SELECT` statement. [#8802](https://github.com/cockroachdb/cockroach/pull/8802), [#9278](https://github.com/cockroachdb/cockroach/pull/9278) - The [`ALTER TABLE ... SPLIT AT`](alter-table.html) command can now be used to force a range split at a specified key. [#8938](https://github.com/cockroachdb/cockroach/pull/8938) - Added new `information_schema` metatables as well as initial support for the `pg_catalog` database. This work is part of our ongoing effort to provide standard database introspection required by popular ORMs. [#8433](https://github.com/cockroachdb/cockroach/pull/8433), [#8498](https://github.com/cockroachdb/cockroach/pull/8498), [#9565](https://github.com/cockroachdb/cockroach/pull/9565), [#9114](https://github.com/cockroachdb/cockroach/pull/9114), [#9104](https://github.com/cockroachdb/cockroach/pull/9104) -- [`CHECK`](constraints.html#check) constraints can now be added with the [`ALTER TABLE ADD CHECK`](alter-table.html) and `ALTER TABLE VALIDATE` statements. [#9127](https://github.com/cockroachdb/cockroach/pull/9127) [#9152](https://github.com/cockroachdb/cockroach/pull/9152) -- The [`ALTER TABLE DROP CONSTRAINT`](alter-table.html) statement can now drop [`CHECK`](constraints.html#check) and [`FOREIGN KEY`](constraints.html#foreign-keys) constraints. [#8747](https://github.com/cockroachdb/cockroach/pull/8747) +- [`CHECK`](check.html) constraints can now be added with the [`ALTER TABLE ADD CHECK`](alter-table.html) and `ALTER TABLE VALIDATE` statements. [#9127](https://github.com/cockroachdb/cockroach/pull/9127) [#9152](https://github.com/cockroachdb/cockroach/pull/9152) +- The [`ALTER TABLE DROP CONSTRAINT`](alter-table.html) statement can now drop [`CHECK`](check.html) and [`FOREIGN KEY`](foreign-key.html) constraints. [#8747](https://github.com/cockroachdb/cockroach/pull/8747) - The [`SHOW CONSTRAINTS`](show-constraints.html) statement now requires the user to have privileges for the requested table. [#8658](https://github.com/cockroachdb/cockroach/pull/8658) - The [`EXPLAIN`](explain.html) statement now works correctly for `VALUES` statements containing subqueries. [#8970](https://github.com/cockroachdb/cockroach/pull/8970) - The [`TRUNCATE`](truncate.html) statement now implements the `CASCADE` modifier. [#9240](https://github.com/cockroachdb/cockroach/pull/9240) diff --git a/beta-20161110.md b/beta-20161110.md index 7eb0209e8c0..ec74a7b4fb8 100644 --- a/beta-20161110.md +++ b/beta-20161110.md @@ -10,3 +10,75 @@ feedback: false {{site.data.alerts.callout_danger}} Data corruption has been observed when upgrading to this release from prior versions, so it has been withdrawn. {{site.data.alerts.end}} + +### Upgrade Notes + +Due to changes in the on-disk format of internal range leases, this release cannot be run concurrently with any prior release. All servers running older versions must be stopped before starting any node with this version. [#10420](https://github.com/cockroachdb/cockroach/pull/10420) + +We realize that "stop the world" upgrades are overly interruptive and are actively working on infrastructure improvements to drastically reduce the need for such upgrades in the future. + +### SQL Language Changes + +- Adding a [`FOREIGN KEY`](foreign-key.html) constraint now automatically creates any necessary index. [#9572](https://github.com/cockroachdb/cockroach/pull/9572) +- The `pg_catalog.pg_roles`, `pg_catalog.pg_description`, and `pg_catalog.pg_settings` tables are now supported. [#10377](https://github.com/cockroachdb/cockroach/pull/10377) [#10381](https://github.com/cockroachdb/cockroach/pull/10381) [#10293](https://github.com/cockroachdb/cockroach/pull/10293) +- New [functions](functions-and-operators.html) `from_ip()` and `to_ip()` convert between binary and textual IP address formats. [#10349](https://github.com/cockroachdb/cockroach/pull/10349) +- Tuple types can now be returned by queries. [#10380](https://github.com/cockroachdb/cockroach/pull/10380) + +### Command-Line Interface Changes + +- `cockroach debug compact` now always rewrites all data, allowing it to pick up configuration changes. [#10532](https://github.com/cockroachdb/cockroach/pull/10532) + +### Performance Improvements + +- Adding new replicas is now prioritized over removing dead ones. [#10492](https://github.com/cockroachdb/cockroach/pull/10492) +- Replicating ranges on to a new node is now more reliably performed back-to-back. [#10440](https://github.com/cockroachdb/cockroach/pull/10440) +- Raft log truncation is now aware of pending snapshots. [#10482](https://github.com/cockroachdb/cockroach/pull/10482) +- Replica garbage collection is now triggered more reliably by replication changes. [#10500](https://github.com/cockroachdb/cockroach/pull/10500) +- Old replicas that are blocking other operations are now prioritized for garbage collection. [#10426](https://github.com/cockroachdb/cockroach/pull/10426) +- Small clusters now run their replica scanners more frequently by default. [#10433](https://github.com/cockroachdb/cockroach/pull/10433) +- Reduced contention in the command queue for multi-range operations. [#10470](https://github.com/cockroachdb/cockroach/pull/10470) +- Operations that have already expired are no longer added to the command queue. [#10487](https://github.com/cockroachdb/cockroach/pull/10487) +- Reduced allocations for SQL row data. [#10534](https://github.com/cockroachdb/cockroach/pull/10534) + +### Bug Fixes + +- A node that is stopped and restarted quickly can no longer produce inconsistent results. [#10420](https://github.com/cockroachdb/cockroach/pull/10420) +- Replication snapshots now release their resources earlier, preventing deadlocks. [#10491](https://github.com/cockroachdb/cockroach/pull/10491) +- Fixed a bug with time series garbage collection when the time series data spans multiple ranges. [#10400](https://github.com/cockroachdb/cockroach/pull/10400) +- Fixed a bug with very large [`DECIMAL`](decimal.html) values or very small fractions. [#10446](https://github.com/cockroachdb/cockroach/pull/10446) +- The `pow()` [function](functions-and-operators.html) now returns an error when its arguments are too large. [#10525](https://github.com/cockroachdb/cockroach/pull/10525) +- Fixed a crash when the number of placeholders in a query doesn't match the number of arguments. [#10474](https://github.com/cockroachdb/cockroach/pull/10474) +- Improved error handling when a SQL [transaction](transactions.html) exceeds an internal deadline. [#9906](https://github.com/cockroachdb/cockroach/pull/9906) +- Fixed a panic in raft leadership transfers. [#10530](https://github.com/cockroachdb/cockroach/pull/10530) +- Fixed a leak in [`CREATE TABLE AS`](create-table-as.html) and [`CREATE VIEW`](create-view.html). [#10527](https://github.com/cockroachdb/cockroach/pull/10527) + +### Doc Updates + +- Expanded the [cloud deployment](cloud-deployment.html) tutorials to cover secure clusters: + - [GCE](deploy-cockroachdb-on-google-cloud-platform.html) + - [AWS](deploy-cockroachdb-on-aws.html) + - [Digital Ocean](deploy-cockroachdb-on-digital-ocean.html) + +### Contributors + +This release includes 64 merged PRs by 21 authors. We would like to thank the following contributors from the CockroachDB community, including first-time contributor Nathan Johnson. + +- Nathan Johnson +- songhao + +### Stay Up-to-Date + +Get future release notes emailed to you: +
+ +
+>>>>>>> constraint pages diff --git a/beta-20161201.md b/beta-20161201.md index 5fa76d4f4af..78e5caca963 100644 --- a/beta-20161201.md +++ b/beta-20161201.md @@ -25,7 +25,7 @@ We realize that "stop the world" upgrades are overly interruptive and are active ### SQL Language Changes -- Adding a [`FOREIGN KEY`](constraints.html#foreign-keys) constraint now automatically creates necessary indexes. [#9572](https://github.com/cockroachdb/cockroach/pull/9572) +- Adding a [`FOREIGN KEY`](foreign-key.html) constraint now automatically creates necessary indexes. [#9572](https://github.com/cockroachdb/cockroach/pull/9572) - The `pg_catalog.pg_roles`, `pg_catalog.pg_description`, `pg_catalog.pg_settings`, and `pg_catalog.pg_index` tables are now supported. [#10377](https://github.com/cockroachdb/cockroach/pull/10377) [#10381](https://github.com/cockroachdb/cockroach/pull/10381) [#10293](https://github.com/cockroachdb/cockroach/pull/10293) [#10548](https://github.com/cockroachdb/cockroach/pull/10548) [#10592](https://github.com/cockroachdb/cockroach/pull/10592) - The `pg_catalog.pg_depend` table is now partially supported (just enough to support `pgjdbc`). [#10696](https://github.com/cockroachdb/cockroach/pull/10696) - `pg_catalog` tables now report databases as belonging to PostgreSQL-compatible namespaces. This is for compatibility only; CockroachDB does not have a notion of namespaces. [#11603](https://github.com/cockroachdb/cockroach/pull/11603) @@ -131,7 +131,7 @@ We realize that "stop the world" upgrades are overly interruptive and are active - [`cockroach user`](create-and-manage-users.html) command - Added documentation on the [`information_schema`](information-schema.html) built-in database, which provides introspection into database tables, columns, indexes, and views, and which is required for ORM compatibility. [#859](https://github.com/cockroachdb/docs/pull/859) - Updated [`SELECT`](select.html) statement documentation to cover using "index hints". [#894](https://github.com/cockroachdb/docs/pull/894) -- Updated [`FOREIGN KEY`](constraints.html#foreign-keys) constraint documentation to clarify that creating a table with a foreign key now automatically creates an index for you. [#895](https://github.com/cockroachdb/docs/pull/895) +- Updated [`FOREIGN KEY`](foreign-key.html) constraint documentation to clarify that creating a table with a foreign key now automatically creates an index for you. [#895](https://github.com/cockroachdb/docs/pull/895) - Updated `RENAME` statement documentation to clarify that you can't rename a [database](rename-database.html), [table](rename-table.html), [column](rename-column.html), or [index](rename-index.html) reference by a [view](views.html). [#873](https://github.com/cockroachdb/docs/pull/873) - Updated the [`cockroach start`](start-a-node.html) command documentation to cover the `--max-sql-memory` flag. [#868](https://github.com/cockroachdb/docs/pull/868) - Updated the [`cockroach zone`](configure-replication-zones.html) command documentation to reflect the correct YAML structure. [#902](https://github.com/cockroachdb/docs/pull/902) diff --git a/check.md b/check.md new file mode 100644 index 00000000000..98d4335e2de --- /dev/null +++ b/check.md @@ -0,0 +1,106 @@ +--- +title: Check Constraint +summary: The Check constraint specifies that the column value must satisfy a Boolean expression. +toc: false +--- + +The Check [constraints](constraints.html) specifies that the column value must satisfy a Boolean expression. + +
+ +## 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, + + ~~~ sql + warranty_period INT CHECK (warranty_period >= 0) CHECK (warranty_period <= 24) + ~~~ + + should be specified as + + ~~~ sql + warranty_period INT CHECK (warranty_period BETWEEN 0 AND 24) + ~~~ + +## 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). + +### Single Column (Column Level) + +{% include sql/diagrams/check_column_level.html %} + +| Parameter | Description | +|-----------|-------------| +| `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). | +| `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_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 NOT NULL, + warehouse_id INT NOT NULL, + quantity_on_hand INT NOT NULL CHECK (quantity_on_hand > 0), + PRIMARY KEY (product_id, warehouse_id) + ); +~~~ + +### Multiple Column (Table Level) + +{% include sql/diagrams/check_table_level.html %} + +| Parameter | Description | +|-----------|-------------| +| `table_name` | The name of the table you're creating. | +| `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. | + +**Example** + +~~~ sql +> CREATE TABLE inventories( + product_id INT NOT NULL, + warehouse_id INT NOT NULL, + quantity_on_hand INT NOT NULL, + PRIMARY KEY (product_id, warehouse_id), + CONSTRAINT ok_to_supply CHECK (quantity_on_hand > 0 AND warehouse_id BETWEEN 100 AND 200) + ); +~~~ + +## 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. + +~~~ sql +> CREATE TABLE inventories ( + product_id INT NOT NULL, + warehouse_id INT NOT NULL, + quantity_on_hand INT NOT NULL CHECK (quantity_on_hand > 0), + PRIMARY KEY (product_id, warehouse_id) + ); + +> INSERT INTO inventories (product_id, warehouse_id, quantity_on_hand) VALUES (1, 2, -20); +~~~ +~~~ +pq: failed to satisfy CHECK constraint (quantity_on_hand > 0) +~~~ + +## See Also + +- [Constraints](constraints.html) +- [Default Value constraint](default-value.html) +- [Foreign Key constraint](foreign-key.html) +- [Not Null constraint](not-null.html) +- [Primary Key constraint](primary-key.html) +- [Unique constraint](unique.html) +- [`SHOW CONSTRAINTS`](show-constraints.html) diff --git a/constraints.md b/constraints.md index 320132a652b..71b9aa6b2f6 100644 --- a/constraints.md +++ b/constraints.md @@ -6,287 +6,22 @@ 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. -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. +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. 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. -**column_level_constraint ::=** -{% include sql/diagrams/col_qual_list.html %} - -**table_level_constraint ::=** -{% include sql/diagrams/table_constraint.html %} - The different types of constraints are: | Constraint Type | Description | |-----------------|-------------| -| NOT NULL | Specifies the column **may not** contain *NULL* values. See [NOT NULL](#not-null) Constraint. | -| Primary Key | Specifies that the column(s) values are unique and that the column(s) **may not** contain *NULL* values. See [Primary Key](#primary-key) Constraint. | -| Unique | Specifies that the column(s) values are unique and that the column(s) **may** contain *NULL* values. See [Unique](#unique) Constraint. | -| Check | Specifies that the column value must satisfy a Boolean expression. See [Check](#check) Constraint. | -| Default Value | Specifies a value to populate a column with if none is provided. See [Default Value](#default-value) Constraint. | -| Foreign Keys | Specifies a column can only contain values exactly matching existing values from the column it references. See [Foreign Keys](#foreign-keys) Constraint. | - -### NOT NULL - -A NOT NULL constraint is specified using `NOT NULL` at the column level. It requires that the column's value is mandatory and must contain a value that is not *NULL*. You can also explicitly just say `NULL` which means the column's value is optional and the column may contain a *NULL* value. If nothing is specified, the default is `NULL`. - -~~~ sql -> CREATE TABLE customers ( - customer_id INT PRIMARY KEY, - cust_name STRING(30) NULL, - cust_email STRING(100) NOT NULL - ); - -> INSERT INTO customers (customer_id, cust_name, cust_email) VALUES (1, 'Smith', NULL); -~~~ -~~~ -pq: null value in column "cust_email" violates not-null constraint -~~~ - -### Primary Key - -A Primary Key constraint is specified using `PRIMARY KEY` at either the column or table level. It requires that the column(s) values are unique and that the column(s) **may not** contain *NULL* values. You can optionally give the constraint a name using the `CONSTRAINT name` syntax, otherwise the constraint and it's 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 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 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). - -The Primary Key for a table can only be specified in the [`CREATE TABLE`](create-table.html) statement. It can't be changed latter using statements like `ALTER TABLE` or `DROP INDEX`. - -A Primary Key constraint can be specified at the column level if it has only one column. - -~~~ sql -> CREATE TABLE orders ( - order_id INT PRIMARY KEY NOT NULL, - order_date TIMESTAMP NOT NULL, - order_mode STRING(8), - customer_id INT, - order_status INT - ); -~~~ - -It needs to be specified at the table level if it has more than one column. - -~~~ sql -> CREATE TABLE inventories ( - product_id INT NOT NULL, - warehouse_id INT NOT NULL, - quantity_on_hand INT NOT NULL, - PRIMARY KEY (product_id, warehouse_id) - ); -~~~ - -### Unique - -A Unique constraint is specified using `UNIQUE` at either the column or table level. It requires that the column(s) values are unique and that the column(s) **may** contain *NULL* values. You can optionally give the constraint a name using the `CONSTRAINT name` syntax, otherwise the constraint and it's associated index are called ***\*_*\*_key**. - -A Unique constraint can be specified at the column level if it has only one column. - -~~~ sql -> CREATE TABLE warehouses ( - warehouse_id INT PRIMARY KEY NOT NULL, - warehouse_name STRING(35) UNIQUE, - location_id INT - ); -~~~ - -It needs to be specified at the table level if it has more than one column. - -~~~ sql -> CREATE TABLE logon ( - login_id INT PRIMARY KEY, - customer_id INT, - logon_date TIMESTAMP, - UNIQUE (customer_id, logon_date) - ); -~~~ - -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 logon ( - login_id INT PRIMARY KEY, - customer_id INT NOT NULL, - sales_id INT, - 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; -~~~ -~~~ -+----------+-------------+----------+ -| login_id | customer_id | sales_id | -+----------+-------------+----------+ -| 1 | 2 | NULL | -| 2 | 2 | NULL | -+----------+-------------+----------+ -~~~ - -### Check - -A Check constraint is specified using `CHECK` at the column or table level. It requires that the column(s) value satisfies 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. - -You can have multiple Check constraints on a single column but ideally these should be combined using the logical operators. So, for example, - -~~~ sql -warranty_period INT CHECK (warranty_period >= 0) CHECK (warranty_period <= 24) -~~~ -should be specified as - -~~~ sql -warranty_period INT CHECK (warranty_period BETWEEN 0 AND 24) -~~~ - -Check constraints that refer to multiple columns should be specified at the table level. - -~~~ sql -> CREATE TABLE inventories( - product_id INT NOT NULL, - warehouse_id INT NOT NULL, - quantity_on_hand INT NOT NULL, - PRIMARY KEY (product_id, warehouse_id), - CONSTRAINT ok_to_supply CHECK (quantity_on_hand > 0 AND warehouse_id BETWEEN 100 AND 200) - ); -~~~ - -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. - -~~~ sql -> CREATE TABLE inventories ( - product_id INT NOT NULL, - warehouse_id INT NOT NULL, - quantity_on_hand INT NOT NULL CHECK (quantity_on_hand > 0), - PRIMARY KEY (product_id, warehouse_id) - ); - -> INSERT INTO inventories (product_id, warehouse_id, quantity_on_hand) VALUES (1, 2, -20); -~~~ -~~~ -pq: failed to satisfy CHECK constraint (quantity_on_hand > 0) -~~~ - -### Default Value - -A Default Value constraint is specified using `DEFAULT` at the column level. 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 Datatype of the DEFAULT value or expression should be the same as the Datatype of the column. -The DEFAULT constraint only applies on insert if the column is not specified in the INSERT statement. You can still insert a *NULL* into an optional (nullable) column by explicitly stating the column and the *NULL* value. - -~~~ sql -> CREATE TABLE inventories ( - product_id INT NOT NULL, - warehouse_id INT NOT NULL, - quantity_on_hand INT DEFAULT 100, - PRIMARY KEY (product_id, warehouse_id) - ); - -> INSERT INTO inventories (product_id, warehouse_id) VALUES (1,20); - -> INSERT INTO inventories (product_id, warehouse_id, quantity_on_hand) VALUES (2,30, NULL); - -> SELECT * FROM inventories; -~~~ -~~~ -+------------+--------------+------------------+ -| product_id | warehouse_id | quantity_on_hand | -+------------+--------------+------------------+ -| 1 | 20 | 100 | -| 2 | 30 | NULL | -+------------+--------------+------------------+ -~~~ - -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. - -### Foreign Keys - -The Foreign Key constraint is specified using `REFERENCES` at the column level or `FOREIGN KEY` and `REFERENCES` at the table level. It helps enforce referential integrity between two tables by guaranteeing that all values in a table's foreign key columns exist in the referenced columns of another table, as well as preventing referenced values from being updated or deleted. - -For example, if you create a foreign key on `orders.customer` that references `customers.id`: - -- Each value inserted or updated in `orders.customer` must exactly match a value in `customers.id`. -- Values in `customers.id` that are referenced by `orders.customer` cannot be deleted or updated. However, `customers.id` values that _aren't_ present in `orders.customer` can be. - -{{site.data.alerts.callout_success}}If you plan to use Foreign Keys in your schema, consider using interleaved tables, which can dramatically improve query performance.{{site.data.alerts.end}} - -#### Rules for Creating Foreign Keys - -**Foreign Key Columns** - -- Only new tables created via [`CREATE TABLE`](create-table.html#create-a-table-with-foreign-keys) can use foreign keys. In a future release, we plan to add support for existing tables through `ALTER TABLE`. -- Foreign key columns must use their referenced column's [type](data-types.html). -- Each column cannot belong to more than 1 Foreign Key constraint. -- 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) or [`UNIQUE`](#unique) 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) or [`PRIMARY KEY`](#primary-key) 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 - -Single-column foreign keys accept _NULL_ values. - -Multiple-column foreign keys only accept _NULL_ values in these scenarios: - -- The row you're ultimately referencing—determined by the statement's other values—contains _NULL_ as the value of the referenced column (i.e., _NULL_ is valid from the perspective of referential integrity) -- The write contains _NULL_ values for all foreign key columns - -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) on both sets of columns when [creating your tables](create-table.html). (`NOT NULL` cannot be added to existing tables.) - -#### Performance - -Because the Foreign Key constraint requires per-row checks on two tables, statements involving foreign key or referenced columns can take longer to execute. You're most likely to notice this with operations like bulk inserts into the table with the foreign keys. - -We're currently working to improve the performance of these statements, though. - -{{site.data.alerts.callout_success}}You can improve the performance of some statements that use Foreign Keys by also using INTERLEAVE IN PARENT.{{site.data.alerts.end}} - -#### Example - -~~~ sql -> CREATE TABLE customers (id INT PRIMARY KEY, email STRING UNIQUE); - -> CREATE TABLE orders ( - id INT PRIMARY KEY, - customer INT NOT NULL REFERENCES customers (id), - orderTotal DECIMAL(9,2), - INDEX (customer) - ); - -> INSERT INTO customers VALUES (1001, 'a@co.tld'); - -> INSERT INTO orders VALUES (1, 1002, 29.99); -~~~ -~~~ -pq: foreign key violation: value [1002] not found in customers@primary [id] -~~~ -~~~ sql -> INSERT INTO orders VALUES (1, 1001, 29.99); - -> UPDATE customers SET id = 1002 WHERE id = 1001; -~~~ -~~~ -pq: foreign key violation: value(s) [1001] in columns [id] referenced in table "orders" -~~~ -~~~ sql -> DELETE FROM customers WHERE id = 1001; -~~~ -~~~ -pq: foreign key violation: value(s) [1001] in columns [id] referenced in table "orders" -~~~ +| [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. | ## See Also - -- [`CREATE TABLE`](create-table.html) +- [`ALTER TABLE`](alter-table.html) - [`SHOW CONSTRAINTS`](show-constraints.html) +- [`CREATE TABLE`](create-table.html) diff --git a/create-index.md b/create-index.md index 828a1dc42ea..fd9793c54c9 100755 --- a/create-index.md +++ b/create-index.md @@ -6,7 +6,7 @@ toc: false The `CREATE INDEX` [statement](sql-statements.html) creates an index for a table. [Indexes](indexes.html) improve your database's performance by helping SQL locate data without having to look through every row of a table. -{{site.data.alerts.callout_info}}Indexes are automatically created for a table's PRIMARY KEY and UNIQUE columns.

When querying a table, CockroachDB uses the fastest index. For more information about that process, see Index Selection in CockroachDB.{{site.data.alerts.end}} +{{site.data.alerts.callout_info}}Indexes are automatically created for a table's PRIMARY KEY and UNIQUE columns.

When querying a table, CockroachDB uses the fastest index. For more information about that process, see Index Selection in CockroachDB.{{site.data.alerts.end}}
@@ -28,7 +28,7 @@ table td:first-child { | Parameter | Description | |-----------|-------------| -|`UNIQUE` | Apply the [`UNIQUE`](constraints.html#unique) 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`](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.| |`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`| |`table_name` | The [`qualified_name`](sql-grammar.html#qualified_name) of the table you want to create the index on. | @@ -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`](constraints.html#unique) constraint at the table level, similarly to [`ALTER TABLE`](alter-table.html). The above example is equivalent to: +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: ~~~ sql > ALTER TABLE products ADD CONSTRAINT products_name_manufacturer_id_key UNIQUE (name, manufacturer_id); diff --git a/create-table-as.md b/create-table-as.md index 71793029031..964bbb48e90 100644 --- a/create-table-as.md +++ b/create-table-as.md @@ -6,7 +6,7 @@ toc: false The `CREATE TABLE AS` statement creates a new table from the results of a [`SELECT`](select.html) statement. -These tables are not designed for long-term use, as they do not support some common table features like [Primary Keys](constraints.html#primary-key) and [interleaving](interleave-in-parent.html). For similar functionality with more robust feature support, [create a table](create-table.html) and then use [`INSERT INTO SELECT`](insert.html#insert-from-a-select-statement). +These tables are not designed for long-term use, as they do not support some common table features like [Primary Keys](primary-key.html) and [interleaving](interleave-in-parent.html). For similar functionality with more robust feature support, [create a table](create-table.html) and then use [`INSERT INTO SELECT`](insert.html#insert-from-a-select-statement).
diff --git a/create-table.md b/create-table.md index 5037158ed4a..92e114528cf 100644 --- a/create-table.md +++ b/create-table.md @@ -91,7 +91,7 @@ Parameter | Description ### Create a Table (No Primary Key Defined) -In CockroachDB, every table requires a [`PRIMARY KEY`](constraints.html#primary-key). 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`](constraints.html#primary- ### Create a Table (Primary Key Defined) -In this example, we create a table with three columns. One column is the [`PRIMARY KEY`](constraints.html#primary-key), another is given the [`UNIQUE`](constraints.html#unique) 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`](unique.html) constraint, 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). @@ -210,12 +210,12 @@ We also have other resources on indexes: ### Create a Table with Foreign Keys -[Foreign keys](constraints.html#foreign-keys) guarantee a column uses only values that already exist in the column it references, which must be from another table. This constraint enforces referential integrity between the two tables. +[Foreign keys](foreign-key.html) guarantee a column uses only values that already exist in the column it references, which must be from another table. This constraint enforces referential integrity between the two tables. -There are a [number of rules](constraints.html#rules-for-creating-foreign-keys) that govern foreign keys, but the two most important are: +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`](constraints.html#primary-key) or [`UNIQUE`](constraints.html#unique) 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 new file mode 100644 index 00000000000..ebf58785faf --- /dev/null +++ b/default-value.md @@ -0,0 +1,78 @@ +--- +title: Default Value Constraint +summary: The Default Value constraint specifies a value to populate a column with if none is provided. +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. + +
+ +## 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. + +## Syntax + +{% include sql/diagrams/default_value_column_level.html %} + +| Parameter | Description | +|-----------|-------------| +| `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). | +| `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_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 +> CREATE TABLE inventories ( + product_id INT, + warehouse_id INT, + quantity_on_hand INT DEFAULT 100, + PRIMARY KEY (product_id, warehouse_id) + ); + +> INSERT INTO inventories (product_id, warehouse_id) VALUES (1,20); + +> INSERT INTO inventories (product_id, warehouse_id, quantity_on_hand) VALUES (2,30, NULL); + +> SELECT * FROM inventories; +~~~ +~~~ ++------------+--------------+------------------+ +| product_id | warehouse_id | quantity_on_hand | ++------------+--------------+------------------+ +| 1 | 20 | 100 | +| 2 | 30 | NULL | ++------------+--------------+------------------+ +~~~ + +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. + +## See Also + +- [Constraints](constraints.html) +- [Check constraint](check.html) +- [Foreign Key constraint](foreign-key.html) +- [Not Null constraint](not-null.html) +- [Primary Key constraint](primary-key.html) +- [Unique constraint](unique.html) +- [`SHOW CONSTRAINTS`](show-constraints.html) diff --git a/delete.md b/delete.md index c9fb1a2809f..40eff71fa7c 100644 --- a/delete.md +++ b/delete.md @@ -69,7 +69,7 @@ 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`](constraints.html#primary-key)/[`UNIQUE`](constraints.html#unique) 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 [`PRIMARY KEY`](primary-key.html)/[`UNIQUE`](unique.html) columns versus non-unique ones. #### Delete Rows Using Primary Key/Unique Columns diff --git a/foreign-key.md b/foreign-key.md new file mode 100644 index 00000000000..84dcf7d3bb9 --- /dev/null +++ b/foreign-key.md @@ -0,0 +1,162 @@ +--- +title: Foreign Key Constraint +summary: The Foreign Key constraint specifies a column can only contain values exactly matching existing values from the column it references, enforcing referential integrity. +toc: false +--- + +The Foreign Key [constraints](constraints.html) specifies a column can only contain values exactly matching 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`: + +- Each value inserted or updated in `orders.customer` must exactly match a value in `customers.id`. +- Values in `customers.id` that are referenced by `orders.customer` cannot be deleted or updated. However, `customers.id` values that _aren't_ present in `orders.customer` can be. + +{{site.data.alerts.callout_success}}If you plan to use Foreign Keys in your schema, consider using interleaved tables, which can dramatically improve query performance.{{site.data.alerts.end}} + +
+ +## Details + +### Rules for Creating Foreign Keys + +**Foreign Key Columns** + +- Only new tables created via [`CREATE TABLE`](create-table.html#create-a-table-with-foreign-keys) can use foreign keys. In a future release, we plan to add support for existing tables through `ALTER TABLE`. +- Foreign key columns must use their referenced column's [type](data-types.html). +- Each column cannot belong to more than 1 Foreign Key constraint. +- 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. + - 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)`. +- 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 + +Single-column foreign keys accept _NULL_ values. + +Multiple-column foreign keys only accept _NULL_ values in these scenarios: + +- The row you're ultimately referencing—determined by the statement's other values—contains _NULL_ as the value of the referenced column (i.e., _NULL_ is valid from the perspective of referential integrity) +- The write contains _NULL_ values for all foreign key columns + +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.) + +### Performance + +Because the Foreign Key constraint requires per-row checks on two tables, statements involving foreign key or referenced columns can take longer to execute. You're most likely to notice this with operations like bulk inserts into the table with the foreign keys. + +We're currently working to improve the performance of these statements, though. + +{{site.data.alerts.callout_success}}You can improve the performance of some statements that use Foreign Keys by also using INTERLEAVE IN PARENT.{{site.data.alerts.end}} + +## Syntax + +### Single Column (Column Level) + +{% include sql/diagrams/foreign_key_column_level.html %} + +| Parameter | Description | +|-----------|-------------| +| `table_name` | The name of the table you're creating. | +| `column_name` | The name of the foreign key column. | +| `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_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 IF NOT EXISTS orders ( + id INT PRIMARY KEY, + customer INT NOT NULL REFERENCES customers (id), + orderTotal DECIMAL(9,2), + INDEX (customer) + ); +~~~ + +### Multiple Column (Table Level) + +{% include sql/diagrams/foreign_key_table_level.html %} + +| Parameter | Description | +|-----------|-------------| +| `table_name` | The name of the table you're creating. | +| `column_def` | Definitions for the table's columns. | +| `name` | The name of the constraint. | +| `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. | + +**Example** + +~~~ sql +CREATE TABLE packages ( + customer INT, + "order" INT, + id INT, + address STRING(50), + delivered BOOL, + delivery_date DATE, + PRIMARY KEY (customer, "order", id), + CONSTRAINT fk_order FOREIGN KEY (customer, "order") REFERENCES orders + ) INTERLEAVE IN PARENT orders (customer, "order") + ; +~~~ + +## Usage Example + +~~~ sql +> CREATE TABLE customers (id INT PRIMARY KEY, email STRING UNIQUE); + +> CREATE TABLE IF NOT EXISTS orders ( + id INT PRIMARY KEY, + customer INT NOT NULL REFERENCES customers (id), + orderTotal DECIMAL(9,2), + INDEX (customer) + ); + +> INSERT INTO customers VALUES (1001, 'a@co.tld'); + +> INSERT INTO orders VALUES (1, 1002, 29.99); +~~~ +~~~ +pq: foreign key violation: value [1002] not found in customers@primary [id] +~~~ +~~~ sql +> INSERT INTO orders VALUES (1, 1001, 29.99); + +> UPDATE customers SET id = 1002 WHERE id = 1001; +~~~ +~~~ +pq: foreign key violation: value(s) [1001] in columns [id] referenced in table "orders" +~~~ +~~~ sql +> DELETE FROM customers WHERE id = 1001; +~~~ +~~~ +pq: foreign key violation: value(s) [1001] in columns [id] referenced in table "orders" +~~~ + +## See Also + +- [Constraints](constraints.html) +- [Check constraint](check.html) +- [Default Value constraint](default-value.html) +- [Not Null constraint](not-null.html) +- [Primary Key constraint](primary-key.html) +- [Unique constraint](unique.html) +- [`SHOW CONSTRAINTS`](show-constraints.html) + diff --git a/generate/main.go b/generate/main.go index cecc5d7ada4..0d731f21ff7 100644 --- a/generate/main.go +++ b/generate/main.go @@ -199,6 +199,18 @@ func main() { exclude: []*regexp.Regexp{regexp.MustCompile("'READ'")}, replace: map[string]string{"'ISOLATION' 'LEVEL'": "'ISOLATION LEVEL'"}, }, + { + name: "check_column_level", + stmt: "stmt_block", + replace: map[string]string{"stmt_list" : "'CREATE' 'TABLE' table_name '(' column_name column_type 'CHECK' '(' check_expr ')' ( column_constraints | ) ( ',' ( column_def ( ',' column_def )* ) | ) ( table_constraints | ) ')' ')'"}, + unlink: []string{"table_name", "column_name", "column_type", "check_expr", "column_constraints", "table_constraints"}, + }, + { + name: "check_table_level", + stmt: "stmt_block", + replace: map[string]string{"stmt_list" : "'CREATE' 'TABLE' table_name '(' ( column_def ( ',' column_def )* ) ( 'CONSTRAINT' name | ) 'CHECK' '(' check_expr ')' ( table_constraints | ) ')'"}, + unlink: []string{"table_name", "check_expr", "table_constraints"}, + }, {name: "column_def"}, {name: "col_qual_list", stmt: "col_qual_list", inline: []string{"col_qualification", "col_qualification_elem"}, replace: map[string]string{"| 'REFERENCES' qualified_name opt_name_parens": ""}}, { @@ -230,6 +242,12 @@ func main() { relink: map[string]string{"view_name": "any_name", "column_list": "name_list"}, }, {name: "create_user_stmt", inline: []string{"opt_with", "opt_password"}, replace: map[string]string{"'SCONST'": "password"}, unlink: []string{"password"}}, + { + name: "default_value_column_level", + stmt: "stmt_block", + replace: map[string]string{"stmt_list" : "'CREATE' 'TABLE' table_name '(' column_name column_type 'DEFAULT' default_value ( column_constraints | ) ( ',' ( column_def ( ',' column_def )* ) | ) ( table_constraints | ) ')' ')'"}, + unlink: []string{"table_name", "column_name", "column_type", "default_value", "table_constraints"}, + }, {name: "delete_stmt", inline: []string{"relation_expr_opt_alias", "where_clause", "returning_clause", "target_list", "target_elem"}}, { name: "drop_database", @@ -269,6 +287,18 @@ func main() { unlink: []string{"table_name", "database_name", "user_name"}, nosplit: true, }, + { + name: "foreign_key_column_level", + stmt: "stmt_block", + replace: map[string]string{"stmt_list" : "'CREATE' 'TABLE' table_name '(' column_name column_type 'REFERENCES' parent_table ( '(' ref_column_name ')' | ) ( column_constraints | ) ( ',' ( column_def ( ',' column_def )* ) | ) ( table_constraints | ) ')' ')'"}, + unlink: []string{"table_name", "column_name", "column_type", "parent_table", "table_constraints"}, + }, + { + name: "foreign_key_table_level", + stmt: "stmt_block", + replace: map[string]string{"stmt_list" : "'CREATE' 'TABLE' table_name '(' ( column_def ( ',' column_def )* ) ( 'CONSTRAINT' name | ) 'FOREIGN KEY' '(' ( fk_column_name ( ',' fk_column_name )* ) ')' 'REFERENCES' parent_table ( '(' ( ref_column_name ( ',' ref_column_name )* ) ')' | ) ( table_constraints | ) ')'"}, + unlink: []string{"table_name", "column_name", "parent_table", "table_constraints"}, + }, {name: "index_def", inline: []string{"opt_storing", "storing", "index_params", "opt_name"}}, { name: "insert_stmt", @@ -277,7 +307,25 @@ func main() { }, {name: "iso_level"}, {name: "interleave", stmt: "create_table_stmt", inline: []string{"opt_interleave"}, replace: map[string]string{"any_name": "table_name", "opt_table_elem_list" : "table_definition", "name_list" : "interleave_prefix", " name" : " parent_table"}, unlink: []string{"table_name", "table_definition", "parent_table", "child_columns"}}, + { + name: "not_null_column_level", + stmt: "stmt_block", + replace: map[string]string{"stmt_list" : "'CREATE' 'TABLE' table_name '(' column_name column_type 'NOT NULL' ( column_constraints | ) ( ',' ( column_def ( ',' column_def )* ) | ) ( table_constraints | ) ')' ')'"}, + unlink: []string{"table_name", "column_name", "column_type", "table_constraints"}, + }, {name: "opt_interleave", replace: map[string]string{"name_list": "interleave_prefix"}, unlink: []string{"interleave_prefix"}}, + { + name: "primary_key_column_level", + stmt: "stmt_block", + replace: map[string]string{"stmt_list" : "'CREATE' 'TABLE' table_name '(' column_name column_type 'PRIMARY KEY' ( column_constraints | ) ( ',' ( column_def ( ',' column_def )* ) | ) ( table_constraints | ) ')' ')'"}, + unlink: []string{"table_name", "column_name", "column_type", "table_constraints"}, + }, + { + name: "primary_key_table_level", + stmt: "stmt_block", + replace: map[string]string{"stmt_list" : "'CREATE' 'TABLE' table_name '(' ( column_def ( ',' column_def )* ) ( 'CONSTRAINT' name | ) 'PRIMARY KEY' '(' ( column_name ( ',' column_name )* ) ')' ( table_constraints | ) ')'"}, + unlink: []string{"table_name", "column_name", "table_constraints"}, + }, {name: "release_savepoint", stmt: "release_stmt", inline: []string{"savepoint_name"}}, {name: "rename_column", stmt: "rename_stmt", inline: []string{"opt_column"}, match: []*regexp.Regexp{regexp.MustCompile("'ALTER' 'TABLE' .* 'RENAME' ('COLUMN'|name)")}, replace: map[string]string{"relation_expr": "table_name", "name 'TO'": "current_name 'TO'"}, unlink: []string{"table_name", "current_name"}}, {name: "rename_database", stmt: "rename_stmt", match: []*regexp.Regexp{regexp.MustCompile("'ALTER' 'DATABASE'")}}, @@ -352,6 +400,18 @@ func main() { replace: map[string]string{"'ONLY' '(' qualified_name ')'": "", "'ONLY' qualified_name": "", "qualified_name": "table_name", "'*'": "", "'CASCADE'": "", "'RESTRICT'": ""}, unlink: []string{"table_name"}, }, + { + name: "unique_column_level", + stmt: "stmt_block", + replace: map[string]string{"stmt_list" : "'CREATE' 'TABLE' table_name '(' column_name column_type 'UNIQUE' ( column_constraints | ) ( ',' ( column_def ( ',' column_def )* ) | ) ( table_constraints | ) ')' ')'"}, + unlink: []string{"table_name", "column_name", "column_type", "table_constraints"}, + }, + { + name: "unique_table_level", + stmt: "stmt_block", + replace: map[string]string{"stmt_list" : "'CREATE' 'TABLE' table_name '(' ( column_def ( ',' column_def )* ) ( 'CONSTRAINT' name | ) 'UNIQUE' '(' ( column_name ( ',' column_name )* ) ')' ( table_constraints | ) ')'"}, + unlink: []string{"table_name", "check_expr", "table_constraints"}, + }, {name: "update_stmt", inline: []string{"relation_expr_opt_alias", "set_clause_list", "set_clause", "single_set_clause", "multiple_set_clause", "ctext_row", "ctext_expr_list", "ctext_expr", "from_clause", "from_list", "where_clause", "returning_clause"}}, {name: "upsert_stmt", stmt: "insert_stmt", inline: []string{"insert_target", "insert_rest", "returning_clause"}, match: []*regexp.Regexp{regexp.MustCompile("'UPSERT'")}}, } diff --git a/indexes.md b/indexes.md index 4e1a6d20d52..db9a0fe14c9 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`](constraints.html#primary-key) 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. - For existing tables with [`CREATE INDEX`](create-index.html). -- By applying the [`UNIQUE`](constraints.html#unique) constraint to columns with [`ALTER TABLE`](alter-table.html), which automatically creates an index of the constrained columns. +- By applying the [`UNIQUE`](unique.html) 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). diff --git a/information-schema.md b/information-schema.md index e543583027c..eecb0beb797 100644 --- a/information-schema.md +++ b/information-schema.md @@ -42,7 +42,7 @@ Column | Description `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](constraints.html#not-null)). +`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`](constraints.html#primary-key), [`UNIQUE`](constraints.html#unique), or [`FOREIGN KEY`](constraints.html#foreign-keys) 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 -------|----------- diff --git a/insert.md b/insert.md index 9fb7ae19e46..841d0729f05 100644 --- a/insert.md +++ b/insert.md @@ -30,7 +30,7 @@ Parameter | Description `AS name` | An alias for the table name. When an alias is provided, it completely hides the actual table name. `qualified_name_list` | A comma-separated list of column names, in parentheses. `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](constraints.html#default-value), 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. +`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. diff --git a/interleave-in-parent.md b/interleave-in-parent.md index 4cbc14c93ab..1b4a6be832a 100644 --- a/interleave-in-parent.md +++ b/interleave-in-parent.md @@ -19,7 +19,7 @@ When tables are interleaved, data written to one table (known as the **child**) For interleaved tables to have Primary Keys that can be matched, the child table must use the parent table's entire Primary Key as a prefix of its own Primary Key––these matching columns are referred to as the **interleave prefix**. It's easiest to think of these columns as representing the same data, which is usually implemented with Foreign Keys. -{{site.data.alerts.callout_success}}To formally enforce the relationship between each table's interleave prefix columns, we recommend using Foreign Key constraints.{{site.data.alerts.end}} +{{site.data.alerts.callout_success}}To formally enforce the relationship between each table's interleave prefix columns, we recommend using Foreign Key constraints.{{site.data.alerts.end}} For example, if you want to interleave `orders` into `customers` and the Primary Key of customers is `id`, you need to create a column representing `customers.id` as the first column in the Primary Key of `orders`—e.g., with a column called `customer`. So the data representing `customers.id` is the interleave prefix, which exists in the `orders` table as the `customer` column. @@ -85,13 +85,13 @@ In general, reads, writes, and joins of values related through the interleave pr - You can only interleave tables when creating the child table. - Each child table's Primary Key must contain its parent table's Primary Key as a prefix (known as the **interleave prefix**).

For example, if the parent table's primary key is `(a INT, b STRING)`, the child table's primary key could be `(a INT, b STRING, c DECIMAL)`. - {{site.data.alerts.callout_info}}This requirement is enforced only by ensuring that the columns use the same data types. However, we recommend ensuring the columns refer to the same values by using the Foreign Key constraint.{{site.data.alerts.end}} + {{site.data.alerts.callout_info}}This requirement is enforced only by ensuring that the columns use the same data types. However, we recommend ensuring the columns refer to the same values by using the Foreign Key constraint.{{site.data.alerts.end}} - Interleaved tables cannot be the child of more than 1 parent table. However, each parent table can have many children tables. Children tables can also be parents of interleaved tables. ## Recommendations - Use interleaved tables when your schema forms a hierarchy, and the Primary Key of the root table (for example, a "user ID" or "account ID") is a parameter to most of your queries. -- To enforce the relationship between the parent and children table's Primary Keys, use [Foreign Key constraints](constraints.html#foreign-keys) on the child table. +- To enforce the relationship between the parent and children table's Primary Keys, use [Foreign Key constraints](foreign-key.html) on the child table. - In cases where you're uncertain if interleaving tables will improve your queries' performance, test how tables perform under load when they're interleaved and when they aren't. ## Examples @@ -166,6 +166,6 @@ To better understand how CockroachDB writes key-value data, see our blog post [M ## See Also - [`CREATE TABLE`](create-table.html) -- [Foreign Keys](constraints.html#foreign-keys) +- [Foreign Keys](foreign-key.html) - [Column Families](column-families.html) diff --git a/learn-cockroachdb-sql.md b/learn-cockroachdb-sql.md index 65f9e477ae9..8f9b9260557 100644 --- a/learn-cockroachdb-sql.md +++ b/learn-cockroachdb-sql.md @@ -166,7 +166,7 @@ To insert multiple rows into a table, use a comma-separated list of parentheses, (4, 9400.10); ~~~ -[Defaults values](constraints.html#default-value) are used when you leave specific columns out of your statement, or when you explicitly request default values. For example, both of the following statements would create a row with `balance` filled with its default value, in this case `NULL`: +[Defaults values](default-value.html) are used when you leave specific columns out of your statement, or when you explicitly request default values. For example, both of the following statements would create a row with `balance` filled with its default value, in this case `NULL`: ~~~ sql > INSERT INTO accounts (id, balance) VALUES @@ -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`](constraints.html#primary-key) of a table and any columns with a [`UNIQUE`](constraints.html#unique) 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`](unique.html) constraint. 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 new file mode 100644 index 00000000000..5c716a20aed --- /dev/null +++ b/not-null.md @@ -0,0 +1,63 @@ +--- +title: Not Null Constraint +summary: The NOT NULL constraint specifies the column may not contain NULL values. +toc: false +--- + +The Not Null [constraint](constraints.html) specifies the column may not contain *NULL* values. + +
+ +## Details + +For more information about *NULL*, see [Null Handling](null-handling.html). + +## Syntax + +{% include sql/diagrams/not_null_column_level.html %} + +| Parameter | Description | +|-----------|-------------| +| `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_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 +> CREATE TABLE IF NOT EXISTS customers ( + customer_id INT PRIMARY KEY, + cust_name STRING(30) NULL, + cust_email STRING(100) NOT NULL + ); + +> INSERT INTO customers (customer_id, cust_name, cust_email) VALUES (1, 'Smith', NULL); +~~~ +~~~ +pq: null value in column "cust_email" violates not-null constraint +~~~ + +## See Also + +- [Constraints](constraints.html) +- [Check constraint](check.html) +- [Default Value constraint](default-value.html) +- [Foreign Key constraint](foreign-key.html) +- [Primary Key constraint](primary-key.html) +- [Unique constraint](unique.html) +- [`SHOW CONSTRAINTS`](show-constraints.html) diff --git a/null-handling.md b/null-handling.md index 1e6c7b81dfb..63877ca9165 100644 --- a/null-handling.md +++ b/null-handling.md @@ -323,7 +323,7 @@ Note that the `NULLS FIRST` and `NULLS LAST` options of the `ORDER BY` clause ar ## NULLs and CHECK Constraints -A [`CHECK`](constraints.html#check) 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 +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. diff --git a/primary-key.md b/primary-key.md new file mode 100644 index 00000000000..ecb6ad07c6e --- /dev/null +++ b/primary-key.md @@ -0,0 +1,104 @@ +--- +title: Primary Key Constraint +summary: The Primary Key constraint specifics that the columns can be used to uniquely identify rows in a table; this means it combines both the Unique and Not Null constraints. +toc: false +--- + +The Primary Key [constraints](constraints.html) specifics that the columns can be used to uniquely identify rows in a table; this means it combines both the Unique and Not Null constraints. + +{{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}} + +
+ +## 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). + +## Syntax + +### Single Column (Column Level) + +{% include sql/diagrams/primary_key_column_level.html %} + +| Parameter | Description | +|-----------|-------------| +| `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_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 orders ( + order_id INT PRIMARY KEY, + order_date TIMESTAMP NOT NULL, + order_mode STRING(8), + customer_id INT, + order_status INT + ); +~~~ + +### Multiple Column (Table Level) + +{% include sql/diagrams/primary_key_table_level.html %} + +| Parameter | Description | +|-----------|-------------| +| `table_name` | The name of the table you're creating. | +| `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. | + +**Example** + +~~~ sql +> CREATE TABLE IF NOT EXISTS inventories ( + product_id INT, + warehouse_id INT, + quantity_on_hand INT NOT NULL, + PRIMARY KEY (product_id, warehouse_id) + ); +~~~ + +## Usage Example + +~~~ sql +> CREATE TABLE IF NOT EXISTS inventories ( + product_id INT, + warehouse_id INT, + quantity_on_hand INT NOT NULL, + PRIMARY KEY (product_id, warehouse_id) + ); + +> INSERT INTO inventories VALUES (1, 1, 100); +> INSERT INTO inventories VALUES (1, 1, 200); +~~~ +~~~ +pq: duplicate key value (product_id,warehouse_id)=(1,1) violates unique constraint "primary" +~~~ +~~~ sql +> INSERT INTO inventories VALUES (1, NULL, 100); +~~~ +~~~ +pq: null value in column "warehouse_id" violates not-null constraint +~~~ + + + + + +## See Also + +- [Constraints](constraints.html) +- [Check constraint](check.html) +- [Default Value constraint](default-value.html) +- [Foreign Key constraint](foreign-key.html) +- [Not Null constraint](not-null.html) +- [Unique constraint](unique.html) +- [`SHOW CONSTRAINTS`](show-constraints.html) diff --git a/select.md b/select.md index df7bf1077ad..5e4cc0be6ac 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`](constraints.html#unique) constraint can have multiple instances of the same value. +Columns without the [`UNIQUE`](unique.html) constraint can have multiple instances of the same value. ~~~ sql > SELECT name diff --git a/sql-feature-support.md b/sql-feature-support.md index bba86ed802a..e115b56a531 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](constraints.html#not-null) | -| `UNIQUE` | ✓ | Standard | [`UNIQUE` documentation](constraints.html#unique) | -| `PRIMARY KEY` | ✓ | Standard | [`PRIMARY KEY` documentation](constraints.html#primary-key) | -| `CHECK` | ✓ | Standard | [`CHECK` documentation](constraints.html#check) | -| `FOREIGN KEY` | ✓ | Standard | [`FOREIGN KEY` documentation](constraints.html#foreign-keys) | -| `DEFAULT VALUE` | ✓ | Standard | [`DEFAULT VALUE` documentation](constraints.html#default-value) | +| `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/unique.md b/unique.md new file mode 100644 index 00000000000..78f9aef71b7 --- /dev/null +++ b/unique.md @@ -0,0 +1,96 @@ +--- +title: Unique Constraint +summary: The Unique constraint specifies that the columns values are unique, though they may contain NULL values. +toc: false +--- + +The Unique [constraints](constraints.html) specifies that the columns values are unique, though they may contain *NULL* values. + +
+ +## 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. + +## Syntax + +### Single Column (Column Level) + +{% include sql/diagrams/unique_column_level.html %} + +| Parameter | Description | +|-----------|-------------| +| `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_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 warehouses ( + warehouse_id INT PRIMARY KEY NOT NULL, + warehouse_name STRING(35) UNIQUE, + location_id INT + ); +~~~ + +### Multiple Column (Table Level) + +{% include sql/diagrams/unique_table_level.html %} + +| Parameter | Description | +|-----------|-------------| +| `table_name` | The name of the table you're creating. | +| `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. | + +**Example** + +~~~ sql +> CREATE TABLE logon ( + login_id INT PRIMARY KEY, + customer_id INT, + logon_date TIMESTAMP, + UNIQUE (customer_id, logon_date) + ); +~~~ + +## 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, + customer_id INT NOT NULL, + sales_id INT, + 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; +~~~ +~~~ ++----------+-------------+----------+ +| login_id | customer_id | sales_id | ++----------+-------------+----------+ +| 1 | 2 | NULL | +| 2 | 2 | NULL | ++----------+-------------+----------+ +~~~ + +## See Also + +- [Constraints](constraints.html) +- [Check constraint](check.html) +- [Default Value constraint](default-value.html) +- [Foreign Key constraint](foreign-key.html) +- [Not Null constraint](not-null.html) +- [Primary Key constraint](primary-key.html) +- [`SHOW CONSTRAINTS`](show-constraints.html) diff --git a/upsert.md b/upsert.md index 0d981104259..5165cf38ee6 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`](constraints.html#primary-key) 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.
@@ -26,11 +26,11 @@ Parameter | Description `AS name` | An alias for the table name. When an alias is provided, it completely hides the actual table name. `qualified_name_list` | A comma-separated list of column names, in parentheses. `select_stmt` | A comma-separated list of column values for a single row, in parentheses. To upsert 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 upsert them.

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](constraints.html#default-value), 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. +`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. ## How `UPSERT` Transforms into `INSERT ON CONFLICT` -`UPSERT` considers uniqueness only for [`PRIMARY KEY`](constraints.html#primary-key) 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`](constraints.html#unique) 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`](unique.html) constraint. Because the inserted `b` value is not unique, the `UPSERT` fails. ~~~ sql > SELECT * FROM unique_test;