Data Definition Language
DDL is a subset of SQL used for defining and modifying the database structure. Understanding DDL is fundamental to working with RDBMS. It allows you to define the structure of your data and make necessary changes as your requirements evolve.
CREATE
used to create new objects within a RDBMSALTER
used to modify existing objectsDROP
used to delete database objectsTRUNCATE
used to remove all records from a table
Create objects
Creating database roles
Note
SQLite is a small database in a single file and it doesn’t implement role based access to data. Any user who have access to DB file will have access to data within the database as well.
In RDBMS, roles are used to manage database permissions. They are an essential part of database security and user management.
In PostgreSQL a role is an entity that can own database objects and have database privileges; a role can be considered a user, a group, or both depending on how it is used.
CREATE ROLE
statement defines a new database role.
CREATE ROLE name;
This statement also can have options:
CREATE ROLE name WITH LOGIN SUPERUSER PASSWORD 'password';
Options clarify if a role can login to the database server, connect to specific databases, create other roles etc. The full list of options is available in the official postgres documentation.
Creating databases
CREATE DATABASE
statement creates a new PostgreSQL database. To create
a database, you must be a superuser or have CREATEDB
privilege.
CREATE DATABASE name;
Databases within a PostgreSQL server have owners. By default a user who creates a database is assigned as its owner. To specify another user as a database owner options may be used:
CREATE DATABASE name OWNER role_name;
There are lots of options for this statement available in the official postgres documentation.
Creating tables
To create a table, you use the aptly names CREATE TABLE
command.
In this command you specify at least a name for the new table, the names of
the columns and the data type of each column.
CREATE TABLE table_name
(
first_column INTEGER,
second_column NUMERIC,
third_column VARCHAR(32),
fourth_column TEXT
);
Default value
Constraints also can be applied for columns while creating a table. In this section, only most notable constraints will be described.
A column can be assigned a default value. When a new row is created and
no values are specified for some of the columns, those columns will be
filled with their respective default values. If no default value is declared
explicitly, the default value is the NULL
value. This usually makes sense
because a null value can be considered to represent unknown data.
In a table definition the default values are listed after the data type.
CREATE TABLE product
(
product_no INTEGER,
name TEXT
price NUMERIC DEFAULT 9.99
);
The default value can be an expression, which will be evaluated whenever the default value is inserted (not when the table is created). A common example are timestamps columns representing the time a record was created and a “serial number” generator.
CREATE TABLE product
(
product_no INTEGER DEFAULT nextval('product_no_seq'),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
There is a shorthand to generate serial numbers:
product_no SERIAL
Generated Columns
In case you need to calculate some column value based on other columns, you may use generated columns. A generated column is a special column that is always computed from other columns. Thus, it is for columns what a view is for tables. There are two kinds of generated columns: stored and virtual.
A stored generated column is computed when it is written (inserted or updated) and occupies storage as if it were a normal column. A virtual generated column occupies no storage and is computed when it is read.
CREATE TABLE person
(
height_cm NUMERIC,
height_in NUMERIC GENERATED ALWAYS AS (height_cm / 2.54) STORED
);
Note
There are several restrictions applied to the definitions of generated columns and tables involving generated columns (not all listed):
The generation expression can only use immutable functions and cannot use sub-queries or reference anything other than the current row.
The generation expression cannot reference another generated column.
A generated column cannot have column default.
Constraints
A check constraint is the most generic constraint type. It allows you to specify that the value in a certain column must satisfy a Boolean (truth-value) expression.
CREATE TABLE product
(
product_no INTEGER,
name TEXT,
price NUMERIC CONSTRAINT price_positive CHECK (price > 0),
discounted_price NUMERIC CHECK (discounted_price > 0),
CHECK (price > discounted_price)
);
A not-null constraint simply specifies that a column must not assume the null value.
CREATE TABLE product
(
product_no SERIAL NOT NULL,
name TEXT NOT NULL CHECK(length(name) > 0)
);
Unique constraints ensure that the data contained in a column, or a group of columns, is unique among all the rows in the table.
CREATE TABLE example
(
a INTEGER,
b INTEGER UNIQUE,
c INTEGER,
UNIQUE (a, c)
);
System columns
Every table has several system columns that are implicitly defined by
the system. Therefore, these names cannot be used as names of user-defined
columns. These columns cannot be used in the generated columns (except
tableoid
). Columns are:
tableoid
xmin
cmin
xmax
cmax
ctid
Modify objects
When you create a table and you realize that you made a mistake, or the requirements of the application change, you can drop the table and create it again. But this is not a convenient option if the table is already filled with data, or if the table is referenced by other database objects.
PostgreSQL provides a family of commands to make modifications to existing tables. You can:
add columns
remove columns
add constraints
remove constraints
change default values
change column data types
rename columns
rename tables
All these actions are performed using the ALTER TABLE
command.
Adding a column
To add a column, use a command like:
ALTER TABLE tbl_name ADD COLUMN cln_name cln_type
CREATE TABLE book
(
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
synopsis TEXT,
isbn VARCHAR(16),
publisher_id INTEGER NOT NULL REFERENCES publisher ON DELETE RESTRICT,
publication_date DATE,
language VARCHAR(64),
page_count INTEGER,
keywords TEXT
);
ALTER TABLE book
ADD COLUMN genre book_genre;
Note
Constraints can be also defined on the column at the same time, using general syntax.
In fact all the options that can be applied to a column description in
CREATE TABLE
can be used here. Keep in mind however that the default
value must satisfy the given constraints, or the ADD
will fail.
Adding a constraint
To add a constraint, the table constraint syntax is used.
CREATE TABLE borrow_request
(
book_id INTEGER REFERENCES book ON DELETE CASCADE,
member_id INTEGER REFERENCES member ON DELETE SET NULL,
borrow_date DATE DEFAULT NOW(),
due_date DATE NOT NULL DEFAULT NOW() + INTERVAL '2 weeks',
complete_date DATE,
PRIMARY KEY (book_id, member_id, borrow_date)
);
COMMENT
ON TABLE borrow_request IS 'book borrow requests';
COMMENT
ON COLUMN borrow_request.book_id IS 'book reference, composite pk';
COMMENT
ON COLUMN borrow_request.member_id IS 'member reference, composite pk';
COMMENT
ON COLUMN borrow_request.borrow_date IS 'composite pk';
ALTER TABLE borrow_request
ADD CONSTRAINT
check_complete_date CHECK (complete_date >= borrow_date);
ALTER TABLE borrow_request
OWNER TO libms;
Other examples:
ALTER TABLE tbl_name
ADD CONSTRAINT cst_name UNIQUE (cln_name);
ALTER TABLE tbl_name
ADD FOREIGN KEY (cln_name) REFERENCES tbl_another;
To add a non-null constraint, which cannot be written as a table constraint, use this syntax:
ALTER TABLE tbl_name
ALTER COLUMN cln_name SET NOT NULL;
Changing a column’s default value
To set a new default for a column, use command like this:
ALTER TABLE tbl_name
ALTER COLUMN cln_name SET DEFAULT 0.0;
To remove any default value, use:
ALTER TABLE tbl_name
ALTER COLUMN cln_name DROP DEFAULT;
This is effectively the same as settings the default to NULL
.
Changing a column’s data type
To convert a column to a different data type, use a command like this:
ALTER TABLE tbl_name
ALTER COLUMN cln_name TYPE NUMERIC(10, 2);
This will succeed only if each existing entry in the column can be converted
to the new type by an implicit cast. If a more complex conversion is needed,
you can add a USING
clause that specifies how to compute the new values
from old ones.
PostgreSQL will attempt to convert the column’s default value (if any) to the new type, as well as any constraint that involve the column. But these conversions might fail, or might produce surprising results. It’s often best to drop any constraints on the column before altering its type, and then add back suitably modified constraints afterwards.
Renaming objects
To rename objects use RENAME
command, like this:
ALTER TABLE tbl_name
RENAME COLUMN cln_name TO new_cln_name;
ALTER TABLE tbl_name
RENAME CONSTRAINT cst_name TO new_cst_name;
To rename a table:
ALTER TABLE tbl_name
RENAME TO new_tbl_name;
Remove objects
Removing tables
DROP
command is used to remove objects.
DROP TABLE tbl_name;
Remember, attempting to remove a table that does not exist is an error.
Nevertheless, it is common in SQL script files to unconditionally try to
drop each table before creating it, ignoring any error message, so that
the script works whether or not the table exists. IF EXISTS
variant
can be used to avoid the error message, but this is not standard SQL.
DROP TABLE IF EXISTS book_author;
DROP TABLE IF EXISTS borrow_request;
DROP TABLE IF EXISTS book;
DROP TABLE IF EXISTS publisher;
DROP TABLE IF EXISTS author;
DROP TABLE IF EXISTS revenue;
DROP TABLE IF EXISTS member;
DROP TABLE IF EXISTS contact;
In case there are other objects referencing the object to drop CASCADE
may
be used to also remove any referencing objects.
Removing a column
To remove a column, use DROP
command like this:
ALTER TABLE book
DROP COLUMN genre;
Whatever data was in the column disappears. Table constraints involving
the column are dropped, too. However, if the column is referenced by a
foreign key constraint of another table, PostgreSQL will not silently drop
that constraint. You can authorize dropping everything that depends on
the column by adding CASCADE
:
ALTER TABLE tbl_name
DROP COLUMN cln_name CASCADE;
Removing a constraint
To remove a constraint you need to know its name. The psql command
\d table_name
can be helpful to get the detailed information on
a specific table, including all constraints’ names assigned to it.
ALTER TABLE tbl_name
DROP CONSTRAINT cst_name;