From 3a0f3cf0d706409f345c2d9123e985bc4d4bc7f1 Mon Sep 17 00:00:00 2001 From: Christian Winter Date: Fri, 29 May 2026 10:13:16 +0200 Subject: [PATCH] Update table docs We were lagging behind with features already implemented but not yet documented. Bring the documentation up to date and format it according to our new guidelines. --- content/compatibility/sql_features.md | 103 +++++---- content/references/objects/tables.md | 315 +++++++++++++++++++++----- 2 files changed, 318 insertions(+), 100 deletions(-) diff --git a/content/compatibility/sql_features.md b/content/compatibility/sql_features.md index 6e6f2eca..d3db35c2 100644 --- a/content/compatibility/sql_features.md +++ b/content/compatibility/sql_features.md @@ -17,50 +17,75 @@ the [system table compatibility](../system_table) page. ### Table Creation & Deletion -| **Feature** | **Support State** | **Details** | -|-----------------------|-------------------|------------------------------------------------------------------------| -| CREATE TABLE | Yes | [Documentation](/docs/references/objects/tables/) | -| DROP TABLE | Yes | | -| Default Values | Yes | | -| GENERATED | Yes | only AS IDENTITY | -| Check Constraints | No | | -| Not-Null Constraints | Yes | [Documentation](/docs/references/objects/tables/) | -| Unique Constraints | Yes | [Documentation](/docs/references/objects/tables/) | -| Primary Keys | Yes | [Documentation](/docs/references/objects/tables/) | -| Foreign Keys | Yes | Without ON DELETE
[Documentation](/docs/references/objects/tables/) | -| Named Constraints | No | | -| Exclusion Constraints | No | | -| System Columns | Yes | Only meaningful for tableoid and ctid | +| **Feature** | **Support State** | **Details** | +|--------------------------------|-------------------|----------------------------------------------------------------------------------------------------------------| +| CREATE TABLE | Yes | [Documentation](/docs/references/objects/tables/) | +| DROP TABLE | Yes | | +| Default Values | Yes | | +| GENERATED AS IDENTITY | Yes | Both `ALWAYS` and `BY DEFAULT` variants | +| GENERATED ALWAYS AS (computed) | No | | +| Check Constraints | Yes | Only at CREATE TABLE time. [Documentation](/docs/references/objects/tables/#constraints) | +| Not-Null Constraints | Yes | [Documentation](/docs/references/objects/tables/) | +| Unique Constraints | Yes | [Documentation](/docs/references/objects/tables/) | +| Primary Keys | Yes | [Documentation](/docs/references/objects/tables/) | +| Foreign Keys | Yes | [Documentation](/docs/references/objects/tables/) | +| FK ON DELETE CASCADE | Yes | | +| FK ON DELETE RESTRICT | Yes | | +| FK ON DELETE NO ACTION | Yes | | +| FK ON UPDATE CASCADE | Yes | | +| FK ON DELETE SET NULL | No | | +| FK ON DELETE SET DEFAULT | No | | +| Named Constraints | Yes | For PRIMARY KEY, UNIQUE, FOREIGN KEY, and CHECK. [Documentation](/docs/references/objects/tables/#constraints) | +| Exclusion Constraints | No | | +| System Columns | Yes | Only meaningful for tableoid and ctid | +| UNLOGGED TABLE | No | | +| CREATE TABLE LIKE | Partial | Copies column names and types. `INCLUDING` options not supported | +| DROP TABLE CASCADE | No | | ### Table Modification (ALTER TABLE) -| **Feature** | **Support State** | **Details** | -|-----------------|-------------------|-------------| -| ADD COLUMN | Yes | | -| DROP COLUMN | Yes | | -| ADD CHECK | No | | -| ADD CONSTRAINT | Yes | | -| ADD FOREIGN KEY | Yes | | -| DROP CONSTRAINT | No | | -| ALTER COLUMN | No | | -| SET DEFAULT | No | | -| DROP DEFAULT | No | | -| COLUMN TYPE | No | | -| RENAME COLUMN | Yes | | -| RENAME TO | Yes | | +| **Feature** | **Support State** | **Details** | +|-----------------------------------|-------------------|---------------------------------------------------| +| ADD COLUMN | Yes | | +| ADD COLUMN IF NOT EXISTS | Yes | | +| DROP COLUMN | Yes | | +| DROP COLUMN IF EXISTS | Yes | | +| DROP COLUMN CASCADE | Yes | | +| RENAME COLUMN | Yes | | +| RENAME TO | Yes | | +| ADD CHECK | No | Only at CREATE TABLE time | +| ADD CONSTRAINT (PRIMARY KEY) | Yes | [Documentation](/docs/references/objects/tables/) | +| ADD CONSTRAINT (UNIQUE) | Yes | [Documentation](/docs/references/objects/tables/) | +| ADD CONSTRAINT (FOREIGN KEY) | Yes | [Documentation](/docs/references/objects/tables/) | +| DROP CONSTRAINT | Yes | [Documentation](/docs/references/objects/tables/) | +| DROP CONSTRAINT IF EXISTS | Yes | | +| DROP CONSTRAINT CASCADE | Yes | | +| RENAME CONSTRAINT | No | | +| ALTER COLUMN SET/DROP DEFAULT | No | | +| ALTER COLUMN SET/DROP NOT NULL | No | | +| ALTER COLUMN TYPE | No | | +| SET SCHEMA | No | | +| OWNER TO | Yes | | +| ENABLE/DISABLE ROW LEVEL SECURITY | Yes | CREATE POLICY requires an enterprise license | +| FORCE/NO FORCE ROW LEVEL SECURITY | Yes | | +| SET TABLESPACE | No | | +| CLUSTER ON / SET WITHOUT CLUSTER | No | | +| ATTACH / DETACH PARTITION | No | | +| ENABLE/DISABLE TRIGGER | No | Triggers are not implemented | +| VALIDATE CONSTRAINT | No | | ### Privileges -| **Feature** | **Support State** | **Details** | -|-----------------------|-------------------|--------------------------------------------------| -| CREATE ROLE | Yes | [Documentation](/docs/references/objects/roles) | -| OWNER TO | Yes | | -| ALTER ROLE | Yes | [Documentation](/docs/references/objects/roles) | -| GRANT | Yes | Only GRANT role to other_role | -| REVOKE | No | | -| SET ROLE | No | | -| INHERIT | Yes | [Documentation](/docs/references/objects/roles/) | -| Row Security Policies | No | | +| **Feature** | **Support State** | **Details** | +|-----------------------|-------------------|------------------------------------------------------------| +| CREATE ROLE | Yes | [Documentation](/docs/references/objects/roles) | +| OWNER TO | Yes | | +| ALTER ROLE | Yes | [Documentation](/docs/references/objects/roles) | +| GRANT | Yes | Requires an enterprise license | +| REVOKE | Yes | Requires an enterprise license | +| SET ROLE | Yes | Requires an enterprise license | +| INHERIT | Yes | [Documentation](/docs/references/objects/roles/) | +| Row Security Policies | Yes | Requires an enterprise license | ### Indexes @@ -83,7 +108,7 @@ the [system table compatibility](../system_table) page. | DROP SCHEMA | Yes | Only if the schema is empty | | search_path | Yes | [Documentation](/docs/references/objects/schemas/#using-schemas) | | Table Inheritance | No | | -| Table Partitioning | Yes | Only at creation, only by hash | +| Table Partitioning | Partial | Only hash partitioning. Only at CREATE TABLE time | | Foreign Data Wrappers | No | | | Views | Yes | [Documentation](/docs/references/objects/views/) | | Databases | Yes | [Documentation](/docs/references/objects/databases/) | diff --git a/content/references/objects/tables.md b/content/references/objects/tables.md index 491f8b34..eab9a5e1 100644 --- a/content/references/objects/tables.md +++ b/content/references/objects/tables.md @@ -6,16 +6,16 @@ weight: 10 ## CREATE TABLE -Create table creates a new relation with the specified columns. +CREATE TABLE creates a new relation with the specified columns. Usage example: ```sql -create table species ( - id int primary key, - common_name text, - botanical_name text not null, - genus_id int foreign key references genus +CREATE TABLE species ( + id int PRIMARY KEY, + common_name text, + botanical_name text NOT NULL, + genus_id int REFERENCES genus(id) ); ``` @@ -25,141 +25,334 @@ After executing this statement, you can find the created table in the `pg_tables Column definitions are specified as: `name type constraint`. Column names can be any identifier; however, for arbitrary character sequences, you need to enclose them in double -quotes: `"complex name""`. +quotes: `"complex name"`. You can find a list of supported types in the [data types reference](/docs/references/datatypes). -CedarDB supports the following constraints, which can either be specified per-column, or separately when referencing -multiple columns: +CedarDB supports the following column-level constraints: -* `unique(...)` -* `primary key(...)` -* `foreign key(...) references other_table(...)` -* `not null` +* `DEFAULT expression`: default value used when no value is supplied on INSERT. +* `GENERATED ALWAYS AS IDENTITY` and `GENERATED BY DEFAULT AS IDENTITY`: sequence / serial column. +* `NOT NULL`: rejects null values. +* `UNIQUE`: enforces uniqueness for this column. +* `PRIMARY KEY`: equivalent to UNIQUE and NOT NULL. Only one is allowed per table. +* `REFERENCES other_table(col)`: foreign key into another table. +* `CHECK (condition)`: rejects rows that do not satisfy the condition. -The `unique`, `primary key`, `foreign key`, and `check` constraints can optionally be given a name using the `constraint` keyword: +### Constraints + +The `UNIQUE`, `PRIMARY KEY`, `FOREIGN KEY`, and `CHECK` constraints can be specified per-column or at the table level (after all column definitions), and can optionally be given a name using the `CONSTRAINT` keyword: ```sql -create table orders ( - id int, - customer int, - item int, - constraint orders_pk primary key (id), - constraint orders_customer_fk foreign key (customer) references customers (id), - constraint orders_item_fk foreign key (item) references items (id), - constraint orders_unique unique (customer, item), - constraint orders_id_positive check (id > 0) +CREATE TABLE observations ( + id int, + species int, + site int, + observed_at date, + CONSTRAINT observations_pk PRIMARY KEY (id), + CONSTRAINT observations_species_fk FOREIGN KEY (species) REFERENCES species (id), + CONSTRAINT observations_site_fk FOREIGN KEY (site) REFERENCES sites (id), + CONSTRAINT observations_unique UNIQUE (species, site, observed_at), + CONSTRAINT observations_id_positive CHECK (id > 0) ); ``` -The `constraint ` part can be omitted entirely, in which case CedarDB automatically assigns a default name using the same conventions as PostgreSQL: +The `CONSTRAINT ` part can be omitted entirely, in which case CedarDB automatically assigns a default name using the same conventions as PostgreSQL: * Primary key: `tablename_pkey` * Unique: `tablename_colname_key` * Foreign key: `tablename_colname_fkey` * Check: `tablename_colname_check` -These default names can be used just like explicit names, e.g., to drop a constraint with `alter table ... drop constraint `. -Naming is not supported for `not null`. +These default names can be used just like explicit names, e.g., to drop a constraint with `ALTER TABLE ... DROP CONSTRAINT `. +Naming is not supported for `NOT NULL`. + +### Foreign Key Actions + +CedarDB supports the following referential actions on foreign keys: + +* `ON DELETE CASCADE`: deletes child rows when the referenced row is deleted. +* `ON DELETE RESTRICT`: prevents deletion if child rows exist. +* `ON DELETE NO ACTION`: same as RESTRICT, and the default. +* `ON UPDATE CASCADE`: updates child rows when the referenced key value changes. + +`ON DELETE SET NULL` and `ON DELETE SET DEFAULT` are not yet implemented. ### Options -Create a temporary table that will be dropped when the current client disconnects: +Create a temporary table that exists only for the current session: ```sql -create temp table table_name (...); +CREATE TEMP TABLE temp_results (id int, score numeric); ``` Do not throw an error if a table with the same name already exists: ```sql -create table table_name if not exists (...); +CREATE TABLE IF NOT EXISTS species (id int PRIMARY KEY, common_name text); +``` + +Create a table using the column layout of an existing table. +This copies the column names and types, but not constraints or defaults: + +```sql +CREATE TABLE species_archive (LIKE species); +``` + +Create a table partitioned by a hash of a column: + +```sql +CREATE TABLE observations ( + id int, + species int, + site text +) PARTITION BY HASH (id); ``` -Create a table that stores all compressed data on remote server, which was created with name `remote_storage` (see [create server](/docs/references/advanced/createserver) for more infos): +Create a table that stores all compressed data on a remote server previously created with name `remote_storage` +(see [CREATE SERVER](/docs/references/advanced/createserver) for more information): ```sql -create table table_name (...) with (server = remote_storage); +CREATE TABLE remote_species (...) WITH (server = remote_storage); ``` +### Identity Columns + +Identity columns automatically generate unique integer values: + +```sql +CREATE TABLE specimens ( + id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + accession text NOT NULL, + collected date +); + +-- id is assigned automatically +INSERT INTO specimens (accession, collected) VALUES ('HRB-00142', '2024-03-15'); +``` + +With `GENERATED BY DEFAULT AS IDENTITY`, you can supply a value explicitly on INSERT. +With `GENERATED ALWAYS AS IDENTITY`, you need to use `OVERRIDING SYSTEM VALUE` to override the generated value. + ### Permissions -To create a role, you need to have superuser or `createrole` permissions. +To create a table, you need the `CREATE` privilege on the target schema. +By default, every role has the `CREATE` privilege on the `public` schema. ## CREATE TABLE AS -`Create table as` allows creating tables with an inferred schema from the output of a query. +`CREATE TABLE AS` creates a table with a schema inferred from the output of a query, and optionally populates it with the query result. Usage example: ```sql -create table recent_movies as - select * - from movies - where release_date >= now()::date - interval '2' year; +CREATE TABLE recent_observations AS + SELECT * + FROM observations + WHERE observed_at >= now()::date - INTERVAL '1' year; ``` -This statement creates a table which resembles the output schema (names and data types) of the query. -Then, the output of the `select` query is stored in this newly created table. +Create the table structure without copying any rows: -### Select into +```sql +CREATE TABLE observations_archive AS + SELECT * FROM observations + WITH NO DATA; +``` -CedarDB also supports the alternative `select into` syntax for compatibility with PostgreSQL: +Override the output column names: ```sql -select * -into recent_movies -from movies -where release_date >= now()::date - interval '2' year; +CREATE TABLE taxon_counts (taxon, cnt) AS + SELECT family, count(*) FROM species GROUP BY family; +``` + +Create a temporary table that is automatically dropped at the end of the transaction: + +```sql +BEGIN; +CREATE TEMP TABLE session_results ON COMMIT DROP AS + SELECT id, score FROM compute_scores(); +COMMIT; +``` + +### SELECT INTO + +CedarDB also supports the alternative `SELECT INTO` syntax for compatibility with PostgreSQL: + +```sql +SELECT * +INTO recent_observations +FROM observations +WHERE observed_at >= now()::date - INTERVAL '1' year; ``` ### Caveats The data types and names of the created columns can be surprising for queries with multiple expressions. E.g., CedarDB promotes the precision of numeric types to avoid overflows, -or infers that columns are guaranteed not-null, e.g., `release_date` in the example above (due to the `>=` predicate). +or infers that columns are guaranteed not-null from query predicates. For more control over the schema, consider using the regular -[create table](/docs/references/objects/tables) statement. +[CREATE TABLE](/docs/references/objects/tables) statement. + +## DROP TABLE + +DROP TABLE removes a table and all its data. + +```sql +DROP TABLE observations; +``` + +Do not throw an error if the table does not exist: + +```sql +DROP TABLE IF EXISTS staging_data; +``` + +Drop multiple tables in one statement: + +```sql +DROP TABLE staging_data, temp_results; +``` + +If another table has a foreign key referencing the table being dropped, the DROP fails with an error. +Drop the dependent table first. +`DROP TABLE CASCADE` is not yet supported. + +### Permissions + +To drop a table you must own it, own its schema, or be a database superuser. ## ALTER TABLE -Alter table allows modifying the definition of a table. -See [PostgreSQL: ALTER TABLE](https://www.postgresql.org/docs/current/sql-altertable.html) for the PostgreSQL documentation. +ALTER TABLE modifies the definition of an existing table. ### Column statements -#### `RENAME COLUMN` +#### ADD COLUMN + +```sql +ALTER TABLE species ADD COLUMN iucn_status text; +``` + +Add a column only if it does not already exist: + +```sql +ALTER TABLE species ADD COLUMN IF NOT EXISTS iucn_status text; +``` + +#### DROP COLUMN + +```sql +ALTER TABLE species DROP COLUMN iucn_status; +``` + +Drop a column, silently ignoring if it does not exist: ```sql -ALTER TABLE IF EXISTS movies RENAME COLUMN runlength TO duration; +ALTER TABLE species DROP COLUMN IF EXISTS iucn_status; ``` -Rename column of table with `table_name` and `current_column_name` to the `new_column_name`. -If exists checks if the table exists and only tries to rename in the case of existence. +Drop a column and cascade to any dependent objects, like other columns that reference it: + +```sql +ALTER TABLE observations DROP COLUMN raw_notes CASCADE; +``` + +#### RENAME COLUMN + +```sql +ALTER TABLE species RENAME COLUMN botanical_name TO scientific_name; +``` + +Renaming a column does not rename any constraints whose default name was derived from the old column name. +For example, a unique constraint with the default name `species_botanical_name_key` keeps that name after the column is renamed. + +#### RENAME TABLE + +```sql +ALTER TABLE species RENAME TO plant_species; +``` ### Constraint statements -#### `ADD CONSTRAINT` +#### ADD CONSTRAINT Adds a constraint to an existing table. -CedarDB supports named `primary key`, `foreign key`, and `unique` constraints: +CedarDB supports adding named `PRIMARY KEY`, `FOREIGN KEY`, and `UNIQUE` constraints: ```sql -ALTER TABLE orders ADD CONSTRAINT orders_pk primary key (id); -ALTER TABLE orders ADD CONSTRAINT orders_customer_fk foreign key (customer) references customers (id); -ALTER TABLE orders ADD CONSTRAINT orders_unique unique (customer, item); +ALTER TABLE orders ADD CONSTRAINT orders_pk PRIMARY KEY (id); +ALTER TABLE orders ADD CONSTRAINT orders_customer_fk FOREIGN KEY (customer) REFERENCES customers (id); +ALTER TABLE orders ADD CONSTRAINT orders_unique UNIQUE (customer, item); ``` -The `CONSTRAINT ` part can be omitted entirely, in which case CedarDB automatically assigns a default name using the same conventions as PostgreSQL: +Foreign key actions like `ON DELETE CASCADE` are also supported when adding a constraint: + +```sql +ALTER TABLE observations ADD CONSTRAINT obs_species_fk + FOREIGN KEY (species_id) REFERENCES species (id) ON DELETE CASCADE; +``` + +The `CONSTRAINT ` part can be omitted, in which case CedarDB automatically assigns a default name: * Primary key: `tablename_pkey` * Unique: `tablename_colname_key` * Foreign key: `tablename_colname_fkey` -#### `DROP CONSTRAINT` +When adding a `FOREIGN KEY` constraint to an existing table, CedarDB validates all existing rows. +If any row would violate the constraint, the statement fails. + +Adding a `CHECK` constraint to an existing table is not yet supported. +`CHECK` constraints can only be specified at `CREATE TABLE` time. -Removes a constraint by name, using either an explicit name or the default name: +#### DROP CONSTRAINT + +Removes a constraint by name: ```sql ALTER TABLE orders DROP CONSTRAINT orders_unique; ALTER TABLE orders DROP CONSTRAINT orders_pkey; ``` + +Silently ignore if the constraint does not exist: + +```sql +ALTER TABLE orders DROP CONSTRAINT IF EXISTS orders_unique; +``` + +Drop a constraint and cascade to dependent constraints: + +```sql +ALTER TABLE child_table DROP CONSTRAINT fk_constraint CASCADE; +``` + +### Ownership + +```sql +ALTER TABLE species OWNER TO botanist_role; +``` + +### Row Level Security + +Enable row-level security on a table. +Policies must be created separately to actually filter rows: + +```sql +ALTER TABLE observations ENABLE ROW LEVEL SECURITY; +ALTER TABLE observations DISABLE ROW LEVEL SECURITY; +``` + +Force row-level security to apply even to the table owner: + +```sql +ALTER TABLE observations FORCE ROW LEVEL SECURITY; +ALTER TABLE observations NO FORCE ROW LEVEL SECURITY; +``` + +Row-level security policies are created with `CREATE POLICY`. +This feature requires an enterprise license. + +### Permissions + +To alter a table you must be its owner. +Superusers can alter any table.