All 40 lessons
Lesson 30 of 40 · Creating & Changing Data
SQL CREATE TABLE and Data Types
By Skillancy Editorial Team
Every example runs on the ShopKart dataset, already loaded in the free SQL Compiler. Click Try it in the SQL Compiler under a query to open it there, then press Run.
CREATE TABLE defines a new table: its name, its columns and each column's data type. Choosing good data types keeps data correct (no text in a price column) and queries fast. This lesson starts the part of SQL known as DDL, the Data Definition Language.
Syntax
CREATE TABLE table_name (
column1 DATA_TYPE [constraints],
column2 DATA_TYPE [constraints],
...
);Common PostgreSQL data types
| Category | Type | Use for | Example value |
|---|---|---|---|
| Whole numbers | SMALLINT, INT, BIGINT | counts, IDs, quantities | 250 |
| Exact decimals | NUMERIC(p, s) / DECIMAL | money, rates | 23999.00 |
| Approximate decimals | REAL, DOUBLE PRECISION | scientific measurements | 0.1234567 |
| Text | VARCHAR(n), TEXT, CHAR(n) | names, emails, codes | 'Bengaluru' |
| Date / time | DATE, TIME, TIMESTAMP, TIMESTAMPTZ | order dates, event times | '2025-08-19' |
| True / false | BOOLEAN | flags such as is_prime | TRUE |
| Auto IDs | GENERATED ALWAYS AS IDENTITY (or SERIAL) | primary keys | 1, 2, 3… |
| Semi-structured | JSONB | flexible attributes | '{"size": "M"}' |
NUMERIC(10, 2) means up to 10 digits in total, 2 of them after the decimal point, so up to 99,999,999.99.
Examples
1. Create a table
A coupons table for ShopKart's promotions:
CREATE TABLE coupons (
coupon_code VARCHAR(20),
description TEXT,
discount_pct NUMERIC(5, 2),
min_order_amt NUMERIC(10, 2),
valid_from DATE,
valid_to DATE,
is_active BOOLEAN
);Try it in the SQL CompilerResult:
Query OK, 0 row(s) affected.
2. Check the new table
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = 'coupons'
ORDER BY ordinal_position;Result:
| column_name | data_type |
|---|---|
| coupon_code | character varying |
| description | text |
| discount_pct | numeric |
| min_order_amt | numeric |
| valid_from | date |
| valid_to | date |
| is_active | boolean |
(7 rows)
information_schema is a set of built-in views that describe every table and column. It works in PostgreSQL, MySQL and SQL Server.
3. Auto-incrementing IDs
Let the database generate IDs:
CREATE TABLE wishlist (
wishlist_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
customer_id INT,
product_id INT,
added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO wishlist (customer_id, product_id) VALUES (1, 103), (4, 111);
SELECT wishlist_id, customer_id, product_id FROM wishlist;Try it in the SQL CompilerResult:
| wishlist_id | customer_id | product_id |
|---|---|---|
| 1 | 1 | 103 |
| 2 | 4 | 111 |
(2 rows)
You didn't supply wishlist_id or added_at; the database filled them in. MySQL uses AUTO_INCREMENT and SQL Server uses IDENTITY(1,1) for the same idea. (PRIMARY KEY and DEFAULT are explained in the constraints lesson.)
4. CREATE TABLE AS: save a query result
Create a table straight from a SELECT, handy for snapshots and analysis tables:
CREATE TABLE delivered_orders_2025 AS
SELECT order_id, customer_id, order_date
FROM orders
WHERE status = 'Delivered'
AND order_date BETWEEN '2025-01-01' AND '2025-12-31';
SELECT COUNT(*) AS rows_copied FROM delivered_orders_2025;Try it in the SQL CompilerResult:
| rows_copied |
|---|
| 16 |
(1 row)
The new table copies column types but not keys, constraints or indexes.
5. Data types enforce correctness
Text that isn't a valid date is rejected:
INSERT INTO coupons (coupon_code, valid_from) VALUES ('DIWALI25', 'next Friday');Error: invalid input syntax for type date: "next Friday"
A value longer than VARCHAR(20) is rejected too:
INSERT INTO coupons (coupon_code) VALUES ('THIS_CODE_IS_FAR_TOO_LONG');Error: value too long for type character varying(20)
Common mistakes
- Storing numbers or dates as text.
'2499'sorts after'10000'as text, and date maths doesn't work on strings. - FLOAT for money. Use
NUMERIC. - Phone numbers as INT. They aren't quantities: leading zeros and
+91get lost. UseVARCHAR. - Spaces or capitals in names.
"Order Date"then needs double quotes forever. Usesnake_case.
Practice question
Create a product_reviews table with an auto-generated ID, product ID, customer ID, a rating from 1 to 5 (whole number), review text and the review date. Insert one review and select it.
Show solution
CREATE TABLE product_reviews (
review_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
product_id INT,
customer_id INT,
rating SMALLINT,
review_text TEXT,
review_date DATE
);
INSERT INTO product_reviews (product_id, customer_id, rating, review_text, review_date)
VALUES (102, 7, 4, 'Good bass for the price', '2025-05-10');
SELECT * FROM product_reviews;Try it in the SQL CompilerResult:
| review_id | product_id | customer_id | rating | review_text | review_date |
|---|---|---|---|---|---|
| 1 | 102 | 7 | 4 | Good bass for the price | 2025-05-10 |
(1 row)
Key takeaways
CREATE TABLEdefines columns and their data types.- Use
INTfor counts,NUMERICfor money,VARCHAR/TEXTfor text,DATE/TIMESTAMPfor time. - Identity columns generate IDs automatically.
CREATE TABLE ... AS SELECTsaves a query result as a new table (without constraints).
Frequently asked questions
What is the difference between VARCHAR and TEXT?
In PostgreSQL there is no performance difference. VARCHAR(n) enforces a maximum length; TEXT has no limit. In MySQL and SQL Server the two behave differently, so VARCHAR(n) is the more portable choice.
Which data type should I use for money?
NUMERIC (also called DECIMAL) with a fixed scale, such as NUMERIC(12,2). Avoid FLOAT and REAL for money because they store approximate values.
What does IF NOT EXISTS do?
CREATE TABLE IF NOT EXISTS skips creation without an error when the table already exists. It does not check that the existing table has the same columns.
Keep learning SQL
One email a week with SQL and analytics guides, new practice questions and cohort dates. No spam, unsubscribe anytime.
Prefer a one-page summary? Download the free SQL cheat sheet (PDF)