Skip to main content
The ALTER TABLE changes the definition of a table. For information on using ALTER TABLE, see the pages for its subcommands. This schema change statement is registered as a job. You can view long-running jobs with .

Required privileges

Refer to the respective subcommands.

Synopsis

alter_table syntax diagram alter_table_cmds syntax diagram where alter_table_cmd is:

Parameters

ParameterDescription
IF EXISTSChange the table only if a table with the current name exists; if one does not exist, do not return an error.
table_nameThe name of the table you want to change.
Additional parameters are documented for the respective subcommands.

Subcommands

Some subcommands can be used in combination in a single ALTER TABLE statement. For example, you can atomically rename a column and add a new column with the old name of the existing column.
SubcommandDescriptionCan combine with other subcommands?
ADD COLUMNAdd columns to tables.Yes
ADD CONSTRAINTAdd constraints to columns.Yes
ALTER COLUMNChange an existing column.Yes
ALTER PRIMARY KEYChange the of a table.Yes
CONFIGURE ZONE for a table.No
DROP COLUMNRemove columns from tables.Yes
DROP CONSTRAINTRemove constraints from columns.Yes
EXPERIMENTAL_AUDITEnable per-table audit logs, for security purposes.Yes
OWNER TOChange the owner of the table.No
PARTITION BYPartition, re-partition, or un-partition a table.Yes
RENAME COLUMNChange the names of columns.Yes
RENAME CONSTRAINTChange constraints columns.Yes
RENAME TOChange the names of tables.No
RESET {storage parameter}Reset a storage parameter on a table to its default value.Yes
SET {storage parameter}Set a storage parameter on a table.Yes
SET LOCALITYSet the table locality for a table in a .No
SET SCHEMAChange the of a table.No
SPLIT ATForce a at the specified row in the table.No
UNSPLIT ATRemove a range split enforcement in the table.No
VALIDATE CONSTRAINTCheck whether values in a column match a on the column.Yes

ADD COLUMN

Use ALTER TABLE ... ADD COLUMN to add columns to existing tables. For examples, see Add columns.

Required privileges

The user must have the CREATE on the table.

Parameters

ParameterDescription
IF NOT EXISTSAdd a column only if a column of the same name does not already exist; if one does exist, do not return an error.
column_nameThe name of the column you want to add. The column name must follow these and must be unique within the table but can have the same name as indexes or constraints.
typenameThe of the new column.
col_qualificationAn optional list of .
For usage, see Synopsis.

ADD CONSTRAINT

Use ALTER TABLE ... ADD CONSTRAINT to add the following to columns: To add a primary key constraint to a table, you should explicitly define the primary key at . To replace an existing primary key, you can use ADD CONSTRAINT ... PRIMARY KEY. For details, see Changing primary keys with ADD CONSTRAINT ... PRIMARY KEY. The and constraints are managed through . For examples, see Add constraints.

Required privileges

The user must have the CREATE on the table.

Parameters

ParameterDescription
IF NOT EXISTSAdd a constraint only if a constraint of the same name does not already exist; if one does exist, do not return an error.
constraint_nameThe name of the constraint, which must be unique to its table and follow these .
constraint_elemThe , , or constraint you want to add.

Adding/changing a DEFAULT constraint is done through ALTER COLUMN.

Adding/changing the table’s PRIMARY KEY is not supported through ALTER TABLE; it can only be specified during .
NOT VALIDCreate unvalidated constraints. When creating an unvalidated constraint, the system does not check that existing table data satisfies the constraint. The constraint is still enforced when table data is modified. An unvalidated constraint can later be validated using VALIDATE CONSTRAINT.
For usage, see Synopsis.

Changing primary keys with ADD CONSTRAINT ... PRIMARY KEY

When you change a primary key with ALTER TABLE ... ALTER PRIMARY KEY, the existing primary key index becomes a secondary index. The secondary index created by ALTER PRIMARY KEY takes up node memory and can slow down write performance to a cluster. If you do not have queries that filter on the primary key that you are replacing, you can use ADD CONSTRAINT to replace the existing primary index without creating a secondary index. You can use ADD CONSTRAINT ... PRIMARY KEY to add a primary key to an existing table if one of the following is true:
  • No primary key was explicitly defined at . In this case, the table is created with a default . Using ADD CONSTRAINT ... PRIMARY KEY drops the default primary key and replaces it with a new primary key.
  • A statement precedes the ADD CONSTRAINT ... PRIMARY KEY statement, in the same transaction. For an example, see Drop and add the primary key constraint.

Aliases

In CockroachDB, the following are aliases for ALTER TABLE ... ADD CONSTRAINT ... PRIMARY KEY:
  • ALTER TABLE ... ADD PRIMARY KEY

ALTER COLUMN

Use ALTER TABLE ... ALTER COLUMN to do the following:
  • Set, change, or drop a column’s .
  • Set or drop a column’s .
  • Set, change, or drop an .
  • Change a column’s .
  • Set the visibility of a column.
For details about altering column data types, see Altering column data types. For examples, see Alter columns.

Required privileges

The user must have the CREATE on the table.

Parameters

ParameterDescription
column_nameThe name of the column to modify.
a_exprThe new to set.
b_exprThe to set.
[NOT] VISIBLEThe visibility of a column when using * in a .
typenameThe new you want to use. For details, see Alter column data types.
USING a_exprHow to compute a new column value from the old column value.
For usage, see Synopsis.

Alter column data types

The following are equivalent in CockroachDB:
  • ALTER TABLE ... ALTER ... TYPE
  • ALTER TABLE ... ALTER COLUMN TYPE
  • ALTER TABLE ... ALTER COLUMN SET DATA TYPE
For examples, see Alter columns.

Known limitations

You cannot alter the data type of a column if:
  • The column is part of an .
  • The column has .
  • The column owns a .
  • The ALTER COLUMN TYPE statement is part of a combined ALTER TABLE statement.
  • The ALTER COLUMN TYPE statement is inside an .
  • The column is part of a .
  • The column is used in a .
  • The column is part of a .
  • The column is referenced in a .

ALTER PRIMARY KEY

Use ALTER TABLE ... ALTER PRIMARY KEY to change the of a table. Note the following:
  • You cannot change the primary key of a table that is currently undergoing a primary key change, or any other .
  • ALTER PRIMARY KEY might need to rewrite multiple indexes, which can make it an expensive operation.
  • When you change a primary key with ALTER PRIMARY KEY, the old primary key index becomes a secondary index. This helps optimize the performance of queries that still filter on the old primary key column.
  • ALTER PRIMARY KEY does not alter the on a table or its indexes, even if a partition is defined on . If you alter the primary key of a partitioned table, you must update the table partition accordingly.
  • The secondary index created by ALTER PRIMARY KEY will not be partitioned, even if a partition is defined on . To ensure that the table is partitioned correctly, you must create a partition on the secondary index, or drop the secondary index.
  • Any new primary key column set by ALTER PRIMARY KEY must have an existing . To add a NOT NULL constraint to an existing column, use ALTER TABLE ... ALTER COLUMN ... SET NOT NULL.
To change an existing primary key without creating a secondary index from that primary key, use DROP CONSTRAINT ... PRIMARY KEY/ADD CONSTRAINT ... PRIMARY KEY. For examples, see Add constraints and Drop constraints.
For examples, see Alter a primary key.

Required privileges

The user must have the CREATE on a table to alter its primary key.

Parameters

ParameterDescription
index_paramsThe name of the column(s) that you want to use for the primary key. These columns replace the current primary key column(s).
USING HASHCreates a .
For usage, see Synopsis.

CONFIGURE ZONE

ALTER TABLE ... CONFIGURE ZONE is used to add, modify, reset, or remove replication zones for a table. To view details about existing replication zones, use . For more information about replication zones, see . You can use replication zones to control the number and location of replicas for specific sets of data, both when replicas are first added and when they are rebalanced to maintain cluster equilibrium. For examples, see Replication Controls. For instructions showing how to troubleshoot replication zones that may be misconfigured, see .

Required privileges

The user must be a member of the or have been granted or privileges. To configure , the user must be a member of the admin role.

Parameters

ParameterDescription
variableThe name of the to change.
valueThe value of the to change.
DISCARDRemove a replication zone.
For usage, see Synopsis.

DROP COLUMN

Use ALTER TABLE ... DROP COLUMN to remove columns from a table.
When used in an explicit transaction combined with other schema changes to the same table, DROP COLUMN can result in data loss if one of the other schema changes fails or is canceled. To work around this, move the DROP COLUMN statement to its own explicit transaction or run it in a single statement outside the existing transaction.
By default, DROP COLUMN drops any on the column being dropped, and any indexes that reference the column, including indexes with that reference the column. For examples, see Drop columns.

Known limitations

CockroachDB prevents a column from being dropped using if it is referenced by a partial index predicate. To drop such a column, the partial indexes need to be dropped first using ..

Required privileges

The user must have the CREATE on the table.

Parameters

ParameterDescription
column_nameThe name of the column you want to drop.

When a column with a constraint is dropped, the CHECK constraint is also dropped.
CASCADEDrop the column even if objects (such as ) depend on it; drop the dependent objects, as well. CASCADE will drop a column with a foreign key constraint if it is the only column in the reference.

CASCADE does not list the objects it drops, so should be used cautiously.

CASCADE is not required to drop an indexed column, or a column that is referenced by an index. By default, DROP COLUMN drops any on the column being dropped, and any indexes that reference the column, including with predicates that reference the column and indexes with that reference the column.
RESTRICT(Default) Do not drop the column if any objects (such as ) depend on it.
For usage, see Synopsis.

DROP CONSTRAINT

Use ALTER TABLE ... DROP CONSTRAINT to remove and constraints from columns. constraints can be dropped with DROP CONSTRAINT if an statement follows the DROP CONSTRAINT statement in the same transaction.
When you change a primary key with , the old primary key index becomes a secondary index. If you do not want the old primary key to become a secondary index, use DROP CONSTRAINT/ to change the primary key.
For information about removing other constraints, see .
For examples, see Drop constraints.

Required privileges

The user must have the CREATE on the table.

Parameters

ParameterDescription
constraint_nameThe name of the constraint you want to drop.
For usage, see Synopsis.

EXPERIMENTAL_AUDIT

ALTER TABLE ... EXPERIMENTAL_AUDIT enables or disables the recording of SQL audit events to the logging channel for a table. The SENSITIVE_ACCESS log output is also called the SQL audit log. For details on using SQL audit logs, see .
This feature is in and subject to change. To share feedback and/or issues, contact Support.
SQL audit logs contain detailed information about queries being executed against your system, including:
  • Full text of the query (which may include personally identifiable information (PII))
  • Date/Time
  • Client address
  • Application name
CockroachDB stores audit log information in a way that ensures durability, but negatively impacts performance. As a result, we recommend using SQL audit logs for security purposes only. For more information, see . For examples, see Configure audit logging.

Required privileges

Only members of the admin role can enable audit logs on a table. By default, the root user belongs to the admin role.

Parameters

ParameterDescription
READLog all table reads to the audit log file.
WRITELog all table writes to the audit log file.
OFFTurn off audit logging.
For usage, see Synopsis.
This command logs all reads and writes, and both the READ and WRITE parameters are required (as shown in the examples).

OWNER TO

ALTER TABLE ... OWNER TO is used to change the owner of a table. For examples, see Change table owner.

Required privileges

To change the owner of a table, the user must be an admin user, or the current owner of the table and a member of the new owner . The new owner role must also have the CREATE on the schema to which the table belongs.

Parameters

ParameterDescription
role_specThe role to set as the owner of the table.
For usage, see Synopsis.

PARTITION BY

Required privileges

ALTER TABLE ... PARTITION BY is used to partition, re-partition, or un-partition a table. After defining partitions, CONFIGURE ZONE is used to control the replication and placement of partitions. For examples, see Define partitions.

Parameters

ParameterDescription
name_listList of columns you want to define partitions on (in the order they are defined in the primary key).
list_partitionsName of list partition followed by the list of values to be included in the partition.
range_partitionsName of range partition followed by the range of values to be included in the partition.
For usage, see Synopsis.

RENAME COLUMN

ALTER TABLE ... RENAME COLUMN changes the name of a column in a table.
It is not possible to rename a column referenced by a view. For more details, see .
For examples, see Rename columns.

Required privileges

The user must have the CREATE on the table.

Parameters

ParameterDescription
IF EXISTSRename the column only if a table of table_name exists; if one does not exist, do not return an error.
column_nameThe current name of the column.
column_new_nameThe you want to use for the column, which must be unique to its table and follow these .
For usage, see Synopsis.

RENAME CONSTRAINT

ALTER TABLE ... RENAME CONSTRAINT changes the name of a constraint on a column.
It is not possible to rename a constraint for a column referenced by a view. For more details, see .
For examples, see Rename constraints.

Required privileges

The user must have the CREATE on the table.

Parameters

ParameterDescription
IF EXISTSRename the constraint only if a constraint of current_name exists; if one does not exist, do not return an error.
constraint_nameThe current name of the constraint.
constraint_new_nameThe new you want to use for the constraint, which must be unique to its table and follow these .
For usage, see Synopsis.

RENAME TO

ALTER TABLE ... RENAME TO changes the name of a table.
ALTER TABLE ... RENAME TO cannot be used to move a table from one schema to another. To change a table’s schema, use SET SCHEMA.ALTER TABLE ... RENAME TO cannot be used to move a table from one database to another. To change a table’s database, use and .
It is not possible to rename a table referenced by a view. For more details, see View Dependencies.
For examples, see Rename tables.

Required privileges

The user must have the DROP on the table and the CREATE on the parent database.

Parameters

ParameterDescription
table_new_nameThe new name of the table, which must be unique within its database and follow these . When the parent database is not set as the default, the name must be formatted as database.name.

The and statements use a temporary table called excluded to handle uniqueness conflicts during execution. It’s therefore not recommended to use the name excluded for any of your tables.
For usage, see Synopsis.

RESET {storage parameter}

ALTER TABLE ... RESET {storage parameter} reverts the value of a storage parameter on a table to its default value.
To reset a storage parameter on an existing index, you must drop and .
For examples, see Set and reset storage parameters.

Required privileges

The user must be a member of the or roles, or have the on the table.

Parameters

ParameterDescription
storage_parameter_keyThe name of the storage parameter you are changing. See Table storage parameters for a list of available parameters.
For usage, see Synopsis.

SET {storage parameter}

ALTER TABLE ... SET {storage parameter} sets a storage parameter on an existing table.
To set a storage parameter on an existing index, you must drop and .
For examples, see Set and reset storage parameters.

Required privileges

The user must be a member of the or roles, or have the on the table.

Parameters

ParameterDescription
storage_parameter_keyThe name of the storage parameter. See Table storage parameters for a list of available parameters.
valueThe value to assign the storage parameter.
For usage, see Synopsis.

Table storage parameters

Parameter nameDescriptionData typeDefault value
exclude_data_from_backupExclude the data in this table from any future backups.Booleanfalse
infer_rbr_region_col_using_constraintFor tables, automatically populate the hidden crdb_region column on INSERT, UPDATE, and UPSERT by looking up the region of the referenced parent row. Set this parameter to the name of a constraint on the table that includes the crdb_region column. The foreign key cannot be dropped while the parameter is set.StringNULL
schema_lockedIndicates that a is not currently ongoing on this table. CockroachDB automatically unsets this parameter before performing a schema change and reapplies it when done. Enabling schema_locked can help running on this table.Booleanfalse
sql_stats_automatic_collection_enabledEnable automatic collection of and statistics for this table.Booleantrue
sql_stats_automatic_collection_min_stale_rowsMinimum number of stale rows in this table that will trigger a full statistics refresh.Integer500
sql_stats_automatic_collection_fraction_stale_rowsFraction of stale rows in this table that will trigger a full statistics refresh.Float0.2
sql_stats_automatic_partial_collection_enabledNew in v25.1: Enable automatic collection of for this table.Booleantrue
sql_stats_automatic_partial_collection_min_stale_rowsNew in v25.1: Minimum number of stale rows that triggers for this table.Integer100
sql_stats_automatic_partial_collection_fraction_stale_rowsNew in v25.1: Target fraction of stale rows that triggers for this table.Float0.05
sql_stats_forecasts_enabledEnable collection for this table.Booleantrue
The following parameters are included for PostgreSQL compatibility and do not affect how CockroachDB runs:
  • autovacuum_enabled
  • fillfactor
For the list of storage parameters that affect how works, see the list of .

SET LOCALITY

ALTER TABLE .. SET LOCALITY changes the of a in a . While CockroachDB is processing an ALTER TABLE .. SET LOCALITY statement that enables or disables REGIONAL BY ROW on a table within a database, any and statements on that database will fail. For examples, see Set localities.

Required privileges

The user must be a member of the or roles, or have the on the table.

Parameters

ParameterDescription
localityThe LOCALITY clause, followed by the to apply to this table. Allowed values:
For usage, see Synopsis. For more information about which table locality is right for your use case, see .

SET SCHEMA

ALTER TABLE ... SET SCHEMA changes the of a table.
CockroachDB supports SET SCHEMA as an .
For examples, see Set table schema.

Required privileges

The user must have the DROP on the table, and the CREATE privilege on the schema.

Parameters

ParameterDescription
schema_nameThe name of the new schema for the table.
For usage, see Synopsis.

SPLIT AT

ALTER TABLE ... SPLIT AT forces a at a specified row in the table. CockroachDB breaks data into ranges. By default, CockroachDB attempts to keep ranges below . To do this, the system will automatically if it grows larger than this limit. For most use cases, this automatic range splitting is sufficient, and you should never need to worry about when or where the system decides to split ranges. However, there are reasons why you may want to perform manual splits on the ranges that store tables or indexes:
  • When a table only consists of a single range, all writes and reads to the table will be served by that range’s . If a table only holds a small amount of data but is serving a large amount of traffic, load distribution can become unbalanced and a can occur. Splitting the table’s ranges manually can allow the load on the table to be more evenly distributed across multiple nodes. For tables consisting of more than a few ranges, load will naturally be distributed across multiple nodes and this will not be a concern.
  • When a table is created, it will only consist of a single range. If you know that a new table will immediately receive significant write traffic, you may want to preemptively split the table based on the expected distribution of writes before applying the load. This can help avoid reduced workload performance that results when automatic splits are unable to keep up with write traffic and a occurs.
For examples, see Split and unsplit tables.

Required privileges

The user must have the INSERT on the table.

Parameters

ParameterDescription
select_stmtA that produces one or more rows at which to split the table.
a_exprThe expiration of the split enforcement on the table. This can be a , , , or .
For usage, see Synopsis.

UNSPLIT AT

ALTER TABLE ... UNSPLIT AT removes a split enforcement on a , at a specified row in the table. Removing a split enforcement from a table or index (“unsplitting”) allows CockroachDB to merge ranges as needed, to help improve your cluster’s performance. For more information, see . For examples, see Split and unsplit tables.

Required privileges

The user must have the INSERT on the table.

Parameters

ParameterDescription
select_stmtA that produces one or more rows at which to unsplit a table.
ALLRemove all split enforcements for a table.
For usage, see Synopsis.

VALIDATE CONSTRAINT

ALTER TABLE ... VALIDATE CONSTRAINT checks whether values in a column match a on the column. This statement is especially useful after applying a constraint to an existing column via ADD CONSTRAINT. In this case, VALIDATE CONSTRAINT can be used to find values already in the column that do not match the constraint. For examples, see Validate constraints.

Required privileges

The user must have the CREATE on the table.

Parameters

ParameterDescription
constraint_nameThe name of the constraint to validate.
For usage, see Synopsis.

View schema changes

This schema change statement is registered as a job. You can view long-running jobs with .

Examples

Add columns

The following examples use the . To follow along, run to start a temporary, in-memory cluster with the bank schema and dataset preloaded:

Add a single column

Add multiple columns

Add a column with a NOT NULL constraint and a DEFAULT value

Add a column with a UNIQUE constraint

Add a column with a FOREIGN KEY constraint

Add a column with collation

Add a column and assign it to a column family

Add a column and assign it to a new column family
Add a column and assign it to an existing column family
Add a column and create a new column family if column family does not exist
Move a column from one column family to another
Moving frequently updated columns to their own . To move a column from one column family to another column family, create a temporary, in the target column family, then rename the columns. Once this succeeds, you can drop the original, now renamed column. For example, to move the new_name column from f2 to f1:
  1. Create a temporary computed column in the target column family of the same data type as the column you want to move:
    This causes newer_name to have the same values as new_name.
  2. Rename the columns:
  3. Drop the old column:
You must set the to false to drop a column in a table that has data.
Moving a column to another column family executes writes to the underlying storage equal to two times the number of rows. For example, if the table has 10 million rows, there will be 20 million writes to the : 10 million writes when creating the temporary stored computed column, and 10 million writes when removing the original column.

Add a column with an ON UPDATE expression

ON UPDATE expressions set the value for a column when other values in a row are updated. For example, suppose you add a new column to the bank table:
When any value in any row of the bank table is updated, CockroachDB re-evaluates the ON UPDATE expression and updates the last_updated column with the result.

Add constraints

Setup

To follow along, run to start a temporary, in-memory cluster with the sample dataset preloaded:

Add the UNIQUE constraint

Adding the requires that all of a column’s values be distinct from one another (except for NULL values).

Add the CHECK constraint

Adding the requires that all of a column’s values evaluate to TRUE for a Boolean expression.
In the process of adding the constraint CockroachDB will run a background job to validate existing table data. If CockroachDB finds a row that violates the constraint during the validation step, the ADD CONSTRAINT statement will fail.
Add constraints to columns created during a transaction
You can add check constraints to columns that were created earlier in the transaction. For example:
The entire transaction will be rolled back, including any new columns that were added, in the following cases:
  • If an existing column is found containing values that violate the new constraint.
  • If a new column has a default value or is a that would have contained values that violate the new constraint.

Add the foreign key constraint with CASCADE

To add a foreign key constraint, use the following steps. Given two tables, users and vehicles, without foreign key constraints:
You can include a to specify what happens when a foreign key is updated or deleted. Using ON DELETE CASCADE will ensure that when the referenced row is deleted, all dependent objects are also deleted.
CASCADE does not list the objects it drops or updates, so it should be used with caution.
For an example of validating this constraint, see Validate a constraint.
By default, referenced columns must be in the same database as the referencing foreign key column. To enable cross-database foreign key references, set the sql.cross_db_fks.enabled to true.

Drop and add a primary key constraint

Suppose that you want to add creation_time to the composite primary key of the promo_codes table, without creating a secondary index of the existing primary key. To do so, use DROP CONSTRAINT and ADD CONSTRAINT in a single ALTER TABLE statement.
  1. View the details of the promo_codes table:
  2. Add a constraint to the creation_time column with ALTER COLUMN:
  3. To issue the schema change atomically, use single statements as an implicit transaction. DROP CONSTRAINT and ADD CONSTRAINT can be combined in a single ALTER TABLE statement:
You should not execute the schema change with multiple statements within an explicit transaction. Refer to .
  1. View the updated table structure:
Using would have created a UNIQUE secondary index called promo_codes_code_key. Instead, there is just one index for the primary key constraint.

Add a unique index to a REGIONAL BY ROW table

In , most users should use instead of explicit index . When you add an index to a REGIONAL BY ROW table, it is automatically partitioned on the . Explicit index partitioning is not required. While CockroachDB process an or statement on a particular database, creating or modifying an index will throw an error. Similarly, all and statements will be blocked while an index is being modified on a REGIONAL BY ROW table within the same database. This example assumes you have a simulated multi-region database running on your local machine following the steps described in . It shows how a UNIQUE index is partitioned, but it’s similar to how all indexes are partitioned on REGIONAL BY ROW tables. To show how the automatic partitioning of indexes on REGIONAL BY ROW tables works, we will:
  1. to the users table in the .
  2. Add a to that column.
  3. Verify that the index is automatically partitioned for better multi-region performance by using and .
First, add a column and its unique constraint. We’ll use email since that is something that should be unique per user.
Next, issue the statement. You will see that the implicit region column that was added when the table is now indexed:
Next, issue the statement. The following output (which is edited for length) will verify that the unique index was automatically for you. It shows that the user_email_unique index is now partitioned by the database regions europe-west1, us-east1, and us-west1.
To ensure that the uniqueness constraint is enforced properly across regions when rows are inserted, or the email column of an existing row is updated, the database needs to do the following additional work when indexes are partitioned:
  1. Run a one-time-only validation query to ensure that the existing data in the table satisfies the unique constraint.
  2. Thereafter, the will automatically add a “uniqueness check” when necessary to any , , or statement affecting the columns in the unique constraint.
Note that the will avoid sending requests to nodes in other regions when it can instead read a value from a unique column that is stored locally. This capability is known as .

Using DEFAULT gen_random_uuid() in REGIONAL BY ROW tables

To auto-generate unique row identifiers in REGIONAL BY ROW tables, use the column with the gen_random_uuid() as the :
When using DEFAULT gen_random_uuid() on columns in REGIONAL BY ROW tables, uniqueness checks on those columns are disabled by default for performance purposes. CockroachDB assumes uniqueness based on the way this column generates . To enable this check, you can modify the sql.optimizer.uniqueness_checks_for_gen_random_uuid.enabled . Note that while there is virtually no chance of a collision occurring when enabling this setting, it is not truly zero.

Using implicit vs. explicit index partitioning in REGIONAL BY ROW tables

In REGIONAL BY ROW tables, all indexes are partitioned on the region column (usually called ). These indexes can either include or exclude the partitioning key (crdb_region) as the first column in the index definition:
  • If crdb_region is included in the index definition, a will enforce uniqueness on the set of columns, just like it would in a non-partitioned table.
  • If crdb_region is excluded from the index definition, that serves as a signal that CockroachDB should enforce uniqueness on only the columns in the index definition.
In the latter case, the index alone cannot enforce uniqueness on columns that are not a prefix of the index columns, so any time rows are or in a REGIONAL BY ROW table that has an implicitly partitioned UNIQUE index, the must add uniqueness checks. Whether or not to explicitly include crdb_region in the index definition depends on the context:
  • If you only need to enforce uniqueness at the region level, then including crdb_region in the UNIQUE index definition will enforce these semantics and allow you to get better performance on s, s, and s, since there will not be any added latency from uniqueness checks.
  • If you need to enforce global uniqueness, you should not include crdb_region in the UNIQUE (or ) index definition, and the database will automatically ensure that the constraint is enforced.
To illustrate the different behavior of explicitly vs. implicitly partitioned indexes, we will perform the following tasks:
  • Create a schema that includes an explicitly partitioned index, and an implicitly partitioned index.
  • Check the output of several queries using EXPLAIN to show the differences in behavior between the two.
  1. Start as follows:
  2. Create a multi-region database and an employees table. There are three indexes in the table, all UNIQUE and all partitioned by the crdb_region column. The table schema guarantees that both id and email are globally unique, while desk_id is only unique per region. The indexes on id and email are implicitly partitioned, while the index on (crdb_region, desk_id) is explicitly partitioned. UNIQUE indexes can only directly enforce uniqueness on all columns in the index, including partitioning columns, so each of these indexes enforce uniqueness for id, email, and desk_id per region, respectively.
  3. In the following statement, we add a new user with the required id, email, and desk_id columns. CockroachDB needs to do additional work to enforce global uniqueness for the id and email columns, which are implicitly partitioned. This additional work is in the form of “uniqueness checks” that the optimizer adds as part of mutation queries.
    The following EXPLAIN output shows that the optimizer has added two constraint-check post queries to check the uniqueness of the implicitly partitioned indexes id and email. There is no check needed for desk_id (really (crdb_region, desk_id)), since that constraint is automatically enforced by the explicitly partitioned index we added in the preceding statement.
  4. The following statement updates the user’s email column. Because the unique index on the email column is implicitly partitioned, the optimizer must perform a uniqueness check.
    In the following EXPLAIN output, the optimizer performs a uniqueness check for email since we’re not updating any other columns (see the constraint-check section).
  5. If we only update the user’s desk_id, no uniqueness checks are needed, since the index on that column is explicitly partitioned (it’s really (crdb_region, desk_id)).
    Because no uniqueness check is needed, there is no constraint-check section in the EXPLAIN output.

Alter columns

Set or change a DEFAULT value

Setting the inserts the value when data’s written to the table without explicitly defining the value for the column. If the column already has a DEFAULT value set, you can use this statement to change it. The following example inserts the Boolean value true whenever you inserted data to the subscriptions table without defining a value for the newsletter column.

Remove DEFAULT constraint

If the column has a defined , you can remove the constraint, which means the column will no longer insert a value by default if one is not explicitly defined for the column.

Set NOT NULL constraint

To specify that the column cannot contain NULL values, set the .

Remove NOT NULL constraint

If the column has the applied to it, you can remove the constraint, which means the column becomes optional and can have NULL values written into it.

Convert a computed column into a regular column

You can convert a stored, computed column into a regular column by using ALTER TABLE. In this example, create a simple table with a computed column:
Then, insert a few rows of data:
The full_name column is computed from the first_name and last_name columns without the need to define a . You can view the column details with the statement:
Now, convert the computed column (full_name) to a regular column:
Check that the computed column was converted:
The computed column is now a regular column and can be updated as such:

Alter the formula for a computed column

To alter the formula for a computed column, you must and the column back with the new definition. Take the following table for instance:
Add a computed column d:
If you try to alter it, you’ll get an error:
However, you can drop it and then add it with the new definition:

Convert to a different data type

The database has a customer table with a column c_credit_lim of type DECIMAL(10,2):
To change the data type from DECIMAL to STRING:
  1. Alter the column type:
  2. Verify the type:

Change a column type’s precision

The customer table contains a column c_balance of type DECIMAL(12,2):
To increase the precision of the c_balance column from DECIMAL(12,2) to DECIMAL(14,2):

Change a column’s type using an expression

You can change the data type of a column and create a new, computed value from the old column values, with a USING clause. For example:

Set the visibility of a column

To specify that a column won’t be returned when using * in a , set the NOT VISIBLE property. You can set the NOT VISIBLE property only on individual columns. For example, the users table of the contains the credit_card column. If you don’t want users to see that column when running SELECT * FROM users;, you can hide it as follows:
When you run SELECT *, the column does not appear:
The column is still selectable if you name it directly in the target_elem parameter:
To unhide the column, run:

Alter a primary key

Alter a single-column primary key

Suppose that you are storing the data for users of your application in a table called users, defined by the following CREATE TABLE statement:
The primary key of this table is on the name column. This is a poor choice, as some users likely have the same name, and all primary keys enforce a UNIQUE constraint on row values of the primary key column. Per our , you should instead use a for single-column primary keys, and populate the rows of the table with generated, unique values. You can add a column and change the primary key with a couple of ALTER TABLE statements:

Alter an existing primary key to use hash sharding

Let’s assume the events table already exists:
You can change an existing primary key to use hash sharding by adding the USING HASH clause at the end of the key definition:
Note that the old primary key index becomes a secondary index, in this case, users_name_key. If you do not want the old primary key to become a secondary index when changing a primary key, you can use / instead.

Configure replication zones

Setup

The following examples use MovR, a fictional vehicle-sharing application, to demonstrate CockroachDB SQL statements. For more information about the MovR example application and dataset, see . To follow along, run with the --geo-partitioned-replicas flag. This command opens an interactive SQL shell to a temporary, 9-node in-memory cluster with the movr database.

Create a replication zone for a table

To control replication for a specific table, use the ALTER TABLE ... CONFIGURE ZONE statement to define the relevant values (other values will be inherited from the parent zone):

Edit a replication zone

Reset a replication zone

Remove a replication zone

When you discard a zone configuration, the objects it was applied to will then inherit a configuration from an object “the next level up”; e.g., if the object whose configuration is being discarded is a table, it will use its parent database’s configuration.You cannot DISCARD any zone configurations on multi-region tables, indexes, or partitions if the created the zone configuration.

Drop columns

Setup

To follow along, run to start a temporary, in-memory cluster with the sample dataset preloaded:

Drop a column

If you no longer want a column in a table, you can drop it.
If there is data in the table, the sql_safe_updates must be set to false.

Prevent dropping columns with dependent objects (RESTRICT)

If the column has dependent objects, such as , CockroachDB will not drop the column by default. However, if you want to be sure of the behavior you can include the RESTRICT clause.

Drop a column and its dependent objects (CASCADE)

If you want to drop the column and all of its dependent options, include the CASCADE clause.
CASCADE does not list objects it drops, so should be used cautiously.

Drop an indexed column

DROP COLUMN drops a column and any indexes on the column being dropped.

Drop constraints

Setup

To follow along, run to start a temporary, in-memory cluster with the sample dataset preloaded:

Drop a foreign key constraint

Configure audit logging

Turn on audit logging

Let’s say you have a customers table that contains personally identifiable information (PII). To turn on audit logs for that table, run the following command:
Now, every access of customer data is logged to the SENSITIVE_ACCESS channel in a event that looks like the following:
The preceding example shows the default log format. This can be changed to a different format (e.g., JSON). For details, see .
For descriptions of all SQL audit event types and their fields, see .
To turn on auditing for more than one table, issue a separate ALTER statement for each table.
For a more detailed example, see .

Turn off audit logging

To turn off logging, issue the following command:

Change table owner

Change a table’s owner

Suppose that the current owner of the rides table is root and you want to change the owner to a new user named max.
To verify that the owner is now max, query the pg_catalog.pg_tables table:
If the user running the command is not an admin user, they must own the table and be a member of the new owning role. Also, the new owner role must also have the CREATE on the schema to which the table belongs.

Define partitions

Define a list partition on a table

Suppose we have a table called students_by_list, and the primary key of the table is defined as (country, id). We can define partitions on the table by list:

Define a range partition on a table

Suppose we have a table called students_by_range, and the primary key of the table is defined as (expected_graduation_date, id). We can define partitions on the table by range:

Define subpartitions on a table

Suppose we have a table named students, and the primary key is defined as (country, expected_graduation_date, id). We can define partitions and subpartitions on the table:

Repartition a table

Unpartition a table

Rename columns

Rename a column

Add and rename columns atomically

Some subcommands can be used in combination in a single statement. For example, let’s say you create a users table with 2 columns, an id column for the primary key and a name column for each user’s last name:
Then you decide you want distinct columns for each user’s first name, last name, and full name, so you execute a single ALTER TABLE statement renaming name to last_name, adding first_name, and adding a called name that concatenates first_name and last_name:

Rename constraints

Rename a constraint

Rename tables

Setup

To follow along, run to start a temporary, in-memory cluster with the sample dataset preloaded:

Rename a table

To avoid an error in case the table does not exist, you can include IF EXISTS:

Set and reset storage parameters

Exclude a table’s data from backups

In some situations, you may want to exclude a table’s row data from a . For example, you have a table that contains high-churn data that you would like to more quickly than the schedule for the database or cluster holding the table. You can use the exclude_data_from_backup = true parameter with a or ALTER TABLE statement to mark a table’s row data for exclusion from a backup. For more detail and an example through the backup and process using this parameter, see . To set the exclude_data_from_backup parameter for a table, run the following:
The CREATE statement for this table will now show the parameter set:
Backups will no longer include the data within the user_promo_codes table. The table will still be present in the backup, but it will be empty. To remove this parameter from a table, run:
This will ensure that the table’s data is stored in subsequent backups that you take.

Reset a storage parameter

The following ttl_test table has three TTL-related storage parameters active on the table:
To remove these settings, run the following command:

Set localities

on REGIONAL BY TABLE, REGIONAL BY ROW, and GLOBAL tables is supported with some limitations — see for more detail.

Set the table locality to REGIONAL BY TABLE

To optimize read and write access to the data in a table from the primary region, use the following statement, which sets the table’s home region to the primary region:
To optimize read and write access to the data in a table from the us-east-1 region, use the following statement, which sets the table’s home region to us-east-1:
If no region is supplied, REGIONAL BY TABLE defaults the table’s home region to the primary region.
For more information about how this table locality works, see .

Set the table locality to REGIONAL BY ROW

Before setting the locality to REGIONAL BY ROW on a table targeted by a changefeed, read the considerations in .
To make an existing table a regional by row table, use the following statement:
Every row in a regional by row table has a column of type crdb_internal_region that represents the row’s . By default, this column is called crdb_region and is hidden. To see a row’s home region, issue a statement like the following:
To update an existing row’s home region, use an statement like the following:
To add a new row to a regional by row table, you must choose one of the following options.
  • Let CockroachDB set the row’s home region automatically. It will use the region of the from which the row is inserted.
  • Set the home region explicitly using an statement like the following:
This is necessary because every row in a regional by row table must have a home region. If you do not set a home region for a row in a regional by row table, it defaults to the value returned by the built-in function gateway_region(). If the value returned by gateway_region() does not belong to the multi-region database the table is a part of, the home region defaults to the database’s primary region. For more information about how this table locality works, see . Note that you can use a name other than crdb_region for the hidden column by using the following statements:
In fact, you can specify any column definition you like for the REGIONAL BY ROW AS column, as long as the column is of type crdb_internal_region and is not nullable. For example, you could modify the to have a region column generated as:
Note that the will avoid sending requests to nodes in other regions when it can instead read a value from a unique column that is stored locally. This capability is known as .

Turn on auto-rehoming for REGIONAL BY ROW tables

This feature is in and subject to change. To share feedback and/or issues, contact Support.
This feature is disabled by default. When auto-rehoming is enabled, the home regions of rows in REGIONAL BY ROW tables are automatically set to the gateway region of any or statements that write to those rows. This functionality is provided by adding an to the crdb_region column of newly created regional by row tables. To enable auto-rehoming using the , issue the following statement:
Once enabled, the auto-rehoming behavior described here has the following limitations:
  • It will only apply to newly created REGIONAL BY ROW tables, using an ON UPDATE expression that is added to the crdb_region column. Existing REGIONAL BY ROW tables will not be auto-rehomed.
  • The crdb_region column from a REGIONAL BY ROW table cannot be referenced as a from another table.
To enable auto-rehoming for an existing REGIONAL BY ROW table, manually update it using an ALTER TABLE ... ALTER COLUMN statement with an ON UPDATE expression:
Example
  1. Follow steps 1 and 2 from the tutorial. This will involve starting a cluster in a terminal window (call it terminal 1).
  2. From the running in terminal 1, set the setting that enables auto-rehoming. You must issue this setting before creating the REGIONAL BY ROW tables that you want auto-rehomed.
  3. In a second terminal window (call it terminal 2), onward to finish loading the cluster with data and applying the multi-region SQL configuration.
  4. Switch back to terminal 1, and check the gateway region of the node you are currently connected to:
  5. Open another terminal (call it terminal 3), and use to connect to a node in a different region in the demo cluster:
  6. From the SQL shell prompt that appears in terminal 3, switch to the movr database, and verify that the current gateway node is in a different region (us-west1):
  7. Still in terminal 3, update a row in the vehicles table that is homed in the us-east1 region. After the update, it should be homed in the current gateway node’s home region, us-west1.
    1. First, pick a row at random from the us-east1 region:
    2. Next, update that row’s city and current_location to addresses in Seattle, WA (USA). Note that this UUID is different than what you will see in your cluster, so you’ll have to update the query accordingly.
    3. Finally, verify that the row has been auto-rehomed in this gateway’s region by running the following statement and checking that the region column is now us-west1:

Set the table locality to GLOBAL

To optimize read access to the data in a table from any region (that is, globally), use the following statement:
For more information about how this table locality works, see .

Set table schema

Setup

To follow along, run to start a temporary, in-memory cluster with the sample dataset preloaded:

Change the schema of a table

Suppose you want to add the promo_codes table to a new schema called cockroach_labs. By default, created in the database belong to the public schema:
If the new schema does not already exist, :
Then, change the table’s schema:

Split and unsplit tables

Setup

The following examples use MovR, a fictional vehicle-sharing application, to demonstrate CockroachDB SQL statements. For more information about the MovR example application and dataset, see . To follow along, run with the --geo-partitioned-replicas flag. This command opens an interactive SQL shell to a temporary, 9-node in-memory cluster with the movr database.

Split a table

Split a table with a compound primary key

You may want to split a table with a compound primary key. Suppose that you want MovR to offer ride-sharing services, in addition to vehicle-sharing services. Some users need to sign up to be drivers, so you need a drivers table to store driver information.
The table’s compound primary key is on the city and dl columns. Note that the table automatically generates an id and a dl value if they are not provided. Because this table has several columns in common with the users table, you can populate the table with values from the users table with an INSERT statement:
Now you can split the table based on the compound primary key. Note that you do not have to specify the entire value for the primary key, just the prefix.

Set the expiration on a split enforcement

You can specify the time at which a split enforcement expires by adding a WITH EXPIRATION clause to your SPLIT statement. Supported expiration values include , , , and .
You can see the split’s expiration date in the split_enforced_until column. The table also contains information about ranges in your CockroachDB cluster, including the split_enforced_until column.

Unsplit a table

Create a drivers table and split the table based on the compound primary key as described in Split a table with a compound primary key. To remove the split enforcements, run the following:
You can see the split’s expiration date in the split_enforced_until column. The table also contains information about ranges in your CockroachDB cluster, including the split_enforced_until column.
The drivers table is still split into ranges at specific primary key column values, but the split_enforced_until column is now NULL for all ranges in the table. The split is no longer enforced, and CockroachDB can in the table as needed.

Validate constraints

Setup

To follow along, run to start a temporary, in-memory cluster with the sample dataset preloaded:

Validate a constraint

In the example Add the foreign key constraint with CASCADE, we add a foreign key constraint as follows:
To ensure that the data added to the vehicles table prior to the creation of the users_fk constraint conforms to that constraint, run the following:
If present in a statement, the table is considered validated because an empty table trivially meets its constraints.

See also