Skip to content
/ Chapter 8 · Changing Data and Tables
Lesson 8.8 · garden_shop
Lesson 8.8

CREATE TABLE in SQL

CREATE TABLE names each column and its type. The types decide what the table accepts and what you can do with the values later.

Every table so far came with the dataset, or with a starter that built it for you. Making your own takes one statement: CREATE TABLE, a name, and a list of columns, each with a type. Here the shop starts a log of visits to its suppliers:

Pattern
create or replace table supplier_visits (
  visit_id    integer,
  supplier_id integer,
  visited_on  date,
  notes       varchar,
  follow_up   boolean default false
);

insert into supplier_visits (visit_id, supplier_id, visited_on, notes)
values (1, 4, '2024-04-18', 'New orchid line in June.');

select * from supplier_visits;

Text accepts anything, and that's the problem

A first draft often makes every column varchar, because text accepts whatever arrives. It also accepts 'five' as a rating, and the cost shows up when you use the values. On a text column, avg(rating) fails with No function matches the given name and argument types 'avg(VARCHAR)', and reviewed_on + 14 fails the same way. DuckDB won't guess that text holds a number or a date.

With the right types, the bad value is stopped at the door instead. Inserting 'five' into an integer column fails with Conversion Error: Could not convert string 'five' to INT32, and 'May 2' into a date column fails because it isn't YYYY-MM-DD. One conversion doesn't fail: 4.5 inserted into an integer column is stored as 5, without a warning. Lesson 2.7 · Integers, decimals, and floats covers which type keeps which digits.

A default fills what the INSERT leaves out

follow_up boolean default false means a row inserted without a follow_up value gets false. Without the default, it gets NULL, and a later where not follow_up skips that row, because not NULL is still unknown.

The default applies only when the column is left out of the INSERT. An INSERT that names the column and passes null stores NULL. Lesson 8.9 · Rules with constraints shows how to forbid that.

Running it twice

A plain create table fails on its second run with Table with name "supplier_visits" already exists! create or replace table throws the old table away, rows included, and builds the new one. That's what you want while you are still deciding on the columns, and it's why the exercises in this chapter use it. Never point it at a table whose rows you need. Lesson 18.5 · Write a rerunnable script compares it with IF NOT EXISTS.

Check what you built

DESCRIBE lists a table's columns, their types, and their defaults. Run it after a CREATE TABLE to confirm the table is the shape you meant:

Columns and types
describe supplier_visits;

Don't trust the results grid for this. A date stored as text displays as 2024-04-18, exactly like a real date. Inside a query, typeof(visited_on) from Lesson 2.7 · Integers, decimals, and floats tells them apart: it says DATE for one and VARCHAR for the other.

Schema · Garden Shop Table · products 9 columns · 24 rows
Table · products

One row per product, with price, cost, and inventory levels.

9 columns · 24 rows
product_id int product_name text category_id int supplier_id int price decimal cost decimal quantity_on_hand int reorder_level int discontinued bool
Your task

The starter's draft stores every column as text. Rebuild product_reviews so that review_id, product_id, and rating are integers, review_text is text, reviewed_on is a date, and verified is a boolean that defaults to false. Keep the INSERT and the final SELECT, which returns review_id, product_id, rating, reviewed_on, verified, and the type of reviewed_on, sorted by review_id.

·

Run your query to inspect the result.

Expected answer
  • Columns: review_id, product_id, rating, reviewed_on, verified.
  • Rows: 4 reviews, by review_id.
  • verified is false on every row, filled in by the default, because the INSERT leaves it out.
  • reviewed_on_type says DATE on every row. A date stored as text looks the same in the grid, but typeof() says VARCHAR.