Skip to content
Laviyx Learn

Try

SQL course menu

SQL CREATE TABLE: Define a New Table Step by Step

Learn how to create tables with SQL CREATE TABLE: choose column names and data types, add primary keys, NOT NULL and DEFAULT values, auto-increment ids, IF NOT EXISTS, and CREATE TABLE AS SELECT.

Beginner8 min readUpdated
On this page

Every table you have queried so far had to be created first. CREATE TABLE defines a new table: its name, its columns, the type of data each column holds, and the rules the data must follow.

Syntax#

SQL
CREATE TABLE table_name (
  column1 data_type [constraints],
  column2 data_type [constraints],
  ...
);

Each column is defined on its own line with a name, a data type, and optional constraints (rules).

A first table#

Let's create a table of online courses:

SQLRun
CREATE TABLE courses (
  course_id    INTEGER PRIMARY KEY,
  title        VARCHAR(100) NOT NULL,
  level        VARCHAR(20) DEFAULT 'beginner',
  price        DECIMAL(8, 2),
  published_on DATE
);

Reading it line by line:

ColumnTypeRuleMeaning
course_idINTEGERPRIMARY KEYUnique id for every course; cannot be empty
titleVARCHAR(100)NOT NULLText up to 100 characters; required
levelVARCHAR(20)DEFAULT 'beginner'Uses "beginner" if no value is given
priceDECIMAL(8, 2)noneExact number with 2 decimal places
published_onDATEnoneOptional date

Now add two rows and look at the result:

SQL
INSERT INTO courses (course_id, title, price)
VALUES (1, 'SQL Basics', 0);

INSERT INTO courses (course_id, title, level, price, published_on)
VALUES (2, 'Advanced SQL', 'advanced', 999.00, '2026-10-01');

SELECT * FROM courses;
Output
course_id | title        | level    | price  | published_on
----------+--------------+----------+--------+-------------
1         | SQL Basics   | beginner | 0.00   | NULL
2         | Advanced SQL | advanced | 999.00 | 2026-10-01

The first course did not specify a level, so the DEFAULT filled in "beginner". It did not specify published_on either, and that column has no default, so it is NULL.

Rules are enforced#

Try inserting a course without a title:

SQL
INSERT INTO courses (course_id) VALUES (3);
Output
ERROR: NOT NULL constraint failed: courses.title

The table's definition protects the data from the very first row. You will learn all the rules in Constraints, and the available types in Data Types.

Auto-generated ids#

Usually you want the database to create ids for you. Each database has its own syntax:

SQL
-- PostgreSQL (and the SQL standard)
CREATE TABLE students (
  student_id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  name       VARCHAR(100) NOT NULL
);

-- MySQL
CREATE TABLE students (
  student_id INT AUTO_INCREMENT PRIMARY KEY,
  name       VARCHAR(100) NOT NULL
);

-- SQL Server
CREATE TABLE students (
  student_id INT IDENTITY(1,1) PRIMARY KEY,
  name       NVARCHAR(100) NOT NULL
);

-- SQLite
CREATE TABLE students (
  student_id INTEGER PRIMARY KEY,   -- automatically generated
  name       TEXT NOT NULL
);

Then insert without the id: INSERT INTO students (name) VALUES ('Asha');

A table with a foreign key#

Tables are linked with foreign keys. Here every enrollment must point to an existing student and course:

SQLRun
CREATE TABLE enrollments (
  student_id  INTEGER NOT NULL REFERENCES students(student_id),
  course_id   INTEGER NOT NULL REFERENCES courses(course_id),
  enrolled_on DATE NOT NULL,
  PRIMARY KEY (student_id, course_id)
);

PRIMARY KEY (student_id, course_id) is a composite key: the pair must be unique, so a student cannot enrol in the same course twice.

IF NOT EXISTS#

Creating a table that already exists is an error. IF NOT EXISTS makes the statement do nothing instead, which is useful in setup scripts:

SQLRun
CREATE TABLE IF NOT EXISTS courses (
  course_id INTEGER PRIMARY KEY,
  title     VARCHAR(100) NOT NULL
);

It does not compare definitions. If a courses table exists with different columns, it is left exactly as it is. Supported by PostgreSQL, MySQL, SQLite and Oracle 23c+. SQL Server has no such clause; there you write IF OBJECT_ID('courses') IS NULL CREATE TABLE courses (...).

CREATE TABLE AS SELECT#

You can create a table from a query's result, columns and data together:

SQLRun
CREATE TABLE expensive_products AS
SELECT name, price
FROM products
WHERE price > 10000;

SELECT * FROM expensive_products;
Output
name    | price
--------+------
Laptop  | 55000
Monitor | 12000

This is great for quick snapshots and reports. The new table copies column names and types, but not primary keys, defaults, or other constraints. SQL Server uses SELECT ... INTO new_table FROM ... instead.

Naming tips#

  • Use lowercase snake_case: order_items, not OrderItems or order items.
  • Plural table names (customers) and singular column names (name) are the most common convention.
  • Avoid reserved words (order, user, group) as names.
  • Name id columns clearly: customer_id is easier to join on than id everywhere.

Common mistakes#

Practice#

Practice exercise

Create a table books with these columns:

  • book_id: whole number, primary key
  • title: text up to 200 characters, required
  • author: text up to 100 characters, required
  • pages: whole number, optional
  • in_stock: whole number, defaults to 0

Then insert one book without specifying in_stock and confirm the default was used.

Show hint

Use INTEGER, VARCHAR(n), NOT NULL, and DEFAULT 0.

Show solution
SQLRun
CREATE TABLE books (
  book_id  INTEGER PRIMARY KEY,
  title    VARCHAR(200) NOT NULL,
  author   VARCHAR(100) NOT NULL,
  pages    INTEGER,
  in_stock INTEGER DEFAULT 0
);

INSERT INTO books (book_id, title, author, pages)
VALUES (1, 'Learning SQL', 'A. Writer', 350);

SELECT * FROM books;
Output
book_id | title        | author    | pages | in_stock
--------+--------------+-----------+-------+---------
1       | Learning SQL | A. Writer | 350   | 0

Key takeaway#

Finished this lesson?