04 - SQL DDL: Creating Database Schemas
1824 words
9 min read
Visual companion
Python
Type and operator map
Python Week 1: the first filter for runtime behavior
View
Revision summary
What this note is really saying
Short form
# 04 - SQL DDL: Creating Database Schemas ## 🎯 Learning Objectives After reading this topic, you will be able to: - Write SQL DDL statements to create tables with appropriate data types - Define primary keys, foreign keys, and other constraints - Use ALTER TABLE to modify existing schemas - Explain the difference b...

04 - SQL DDL: Creating Database Schemas
🎯 Learning Objectives
After reading this topic, you will be able to:
- Write SQL DDL statements to create tables with appropriate data types
- Define primary keys, foreign keys, and other constraints
- Use ALTER TABLE to modify existing schemas
- Explain the difference between CREATE TYPE and CREATE DOMAIN
- Enforce referential integrity with ON DELETE/ON UPDATE actions
📋 Prerequisites
- 03 - Relational Model — Keys (primary, foreign, candidate), domains, referential integrity
- Basic SQL terminology — what a table is
📖 Core Content
4.1 Intuition: DDL is the Blueprint
If a database is a building, DDL (Data Definition Language) is the architectural blueprint. It defines:
- What tables exist
- What columns each table has
- What data types those columns hold
- What rules (constraints) the data must follow The actual data (rows) comes later via DML (INSERT, UPDATE, etc.). DDL is about structure — it's executed once and changes rarely.
Why This Matters: A well-designed schema is the foundation of a good database. Poor schema design leads to data anomalies, performance problems, and maintenance nightmares. Getting the DDL right is the most important step.
4.2 CREATE TABLE: The Basics
sqlCREATE TABLE instructor ( ID VARCHAR(5), name VARCHAR(20) NOT NULL, dept_name VARCHAR(20), salary NUMERIC(8,2), PRIMARY KEY (ID) );
Syntax breakdown:
CREATE TABLE instructor (...)— Creates a table namedinstructorID VARCHAR(5)— Column named ID with variable-length string up to 5 charsname VARCHAR(20) NOT NULL— Column cannot contain NULL valuessalary NUMERIC(8,2)— Decimal number with 8 digits total, 2 after decimal pointPRIMARY KEY (ID)— Enforces uniqueness and NOT NULL on ID
4.3 SQL Data Types
| Category | Data Type | Description | Example |
|---|---|---|---|
| String | CHAR(n) | Fixed-length string (padded with spaces) | CHAR(10) → 'hello ' |
| String | VARCHAR(n) | Variable-length string (up to n) | VARCHAR(50) → 'hello' |
| Numeric | INT / INTEGER | Whole numbers (typically 4 bytes) | INT → 42 |
| Numeric | SMALLINT | Small integer (2 bytes) | SMALLINT → 100 |
| Numeric | NUMERIC(p,d) | Exact decimal (p total digits, d decimal) | NUMERIC(8,2) → 12345.67 |
| Numeric | REAL / FLOAT | Approximate floating point | REAL → 3.14 |
| Date/Time | DATE | Date (year-month-day) | DATE → '2024-01-15' |
| Date/Time | TIME | Time (hour:minute:second) | TIME → '14:30:00' |
| Date/Time | TIMESTAMP | Date + Time | TIMESTAMP → '2024-01-15 14:30:00' |
| Large Object | BLOB | Binary large object (images, files) | BLOB |
| Large Object | CLOB | Character large object (text documents) | CLOB |
Choosing the right data type:
- Use
VARCHARnotCHARfor strings of varying length (saves space) - Use
INTfor whole numbers,NUMERICfor money (exact decimals) - Use
DATE/TIMESTAMPfor temporal data (not strings!)
4.4 Integrity Constraints
sqlCREATE TABLE student ( ID VARCHAR(5) PRIMARY KEY, -- inline primary key name VARCHAR(20) NOT NULL, -- must have a value dept_name VARCHAR(20), tot_cred NUMERIC(3,0) DEFAULT 0, -- default value if not specified email VARCHAR(50) UNIQUE, -- no duplicates allowed age NUMERIC(3,0) CHECK (age >= 0 AND age < 150), -- domain constraint CONSTRAINT valid_dept CHECK (dept_name IN ('CS', 'Math', 'Physics')) );
NOT NULL
Ensures a column never has NULL:
sqlname VARCHAR(20) NOT NULL
UNIQUE
Ensures all values in a column (or combination) are distinct:
sqlemail VARCHAR(50) UNIQUE
CHECK
Validates values against a condition:
sqlCHECK (salary >= 0) CHECK (semester IN ('Fall', 'Spring', 'Summer')) CHECK (end_date > start_date)
PRIMARY KEY
Shortcut for
NOT NULL + UNIQUE. A table can have only one:sqlPRIMARY KEY (ID) -- or composite: PRIMARY KEY (course_id, semester, year)
FOREIGN KEY
Links to another table's primary key:
sqlFOREIGN KEY (dept_name) REFERENCES department(dept_name)
4.5 Referential Integrity: ON DELETE and ON UPDATE
What happens when a referenced row is deleted or updated?
sqlCREATE TABLE course ( course_id VARCHAR(8) PRIMARY KEY, title VARCHAR(50), dept_name VARCHAR(20), credits NUMERIC(2,0), FOREIGN KEY (dept_name) REFERENCES department(dept_name) ON DELETE CASCADE ON UPDATE CASCADE );
| Action | DELETE Behavior | UPDATE Behavior |
|---|---|---|
| CASCADE | Delete referencing rows | Update referencing rows |
| SET NULL | Set foreign key to NULL | Set foreign key to NULL |
| SET DEFAULT | Set to default value | Set to default value |
| RESTRICT (default) | Reject delete | Reject update |
| NO ACTION | Same as RESTRICT (check at end of transaction) | Same as RESTRICT |
Example: If
department('CS') is deleted:CASCADE: All courses withdept_name='CS'are also deletedSET NULL: Courses'dept_namebecomes NULLRESTRICT: Delete is rejected until courses are reassigned
Best Practice: UseRESTRICTfor critical data (don't accidentally delete a department and all its courses),CASCADEfor dependent data (delete an order and its line items).
4.6 ALTER TABLE
Modify an existing table's schema:
sql-- Add a column ALTER TABLE instructor ADD COLUMN phone VARCHAR(15); -- Drop a column ALTER TABLE instructor DROP COLUMN phone; -- Add a constraint ALTER TABLE instructor ADD CONSTRAINT unique_email UNIQUE(email); -- Add a foreign key ALTER TABLE teaches ADD FOREIGN KEY (course_id) REFERENCES course(course_id); -- Drop a constraint ALTER TABLE instructor DROP CONSTRAINT unique_email;
4.7 DROP TABLE
Completely removes a table and its data:
sqlDROP TABLE instructor; -- removes table permanently (irreversible!)
To delete all rows but keep the structure:
sqlDELETE FROM instructor; -- removes all rows, table remains
4.8 CREATE TYPE vs. CREATE DOMAIN
Both create reusable data types, but with an important difference:
sql-- CREATE TYPE: New type, no constraints CREATE TYPE dollars AS NUMERIC(12,2) FINAL; CREATE TABLE department ( dept_name VARCHAR(20), building VARCHAR(15), budget dollars -- uses the custom type ); -- CREATE DOMAIN: New type WITH constraints CREATE DOMAIN degree_level AS VARCHAR(10) CONSTRAINT degree_level_test CHECK (VALUE IN ('Bachelors', 'Masters', 'Doctorate')); CREATE TABLE professor ( name VARCHAR(50), level degree_level -- constrained to specific values );
| Feature | CREATE TYPE | CREATE DOMAIN |
|---|---|---|
| Constraints allowed | No | Yes |
| Overrideable operators | Yes | No |
| Column-level defaults | No | Yes |
Equivalent to typedef | Yes | Constrained typedef |
4.9 Schema Creation: Complete Example
Let's build a university database schema from scratch:
sql-- Strong entities first (no foreign keys) CREATE TABLE department ( dept_name VARCHAR(20) PRIMARY KEY, building VARCHAR(15), budget NUMERIC(12,2) CHECK (budget >= 0) ); CREATE TABLE student ( ID VARCHAR(5) PRIMARY KEY, name VARCHAR(20) NOT NULL, dept_name VARCHAR(20), tot_cred NUMERIC(3,0) DEFAULT 0, FOREIGN KEY (dept_name) REFERENCES department(dept_name) ); -- ... more tables with foreign keys CREATE TABLE course ( course_id VARCHAR(8) PRIMARY KEY, title VARCHAR(50), dept_name VARCHAR(20), credits NUMERIC(2,0) CHECK (credits > 0), FOREIGN KEY (dept_name) REFERENCES department(dept_name) ); -- Tables referencing earlier tables CREATE TABLE takes ( ID VARCHAR(5), course_id VARCHAR(8), semester VARCHAR(6), year NUMERIC(4,0), grade VARCHAR(2), PRIMARY KEY (ID, course_id, semester, year), FOREIGN KEY (ID) REFERENCES student(ID), FOREIGN KEY (course_id) REFERENCES course(course_id) );
📐 Key Formulas / Concepts
| Constraint | Syntax | Effect |
|---|---|---|
| PRIMARY KEY | PRIMARY KEY (col) | Unique + NOT NULL; one per table |
| FOREIGN KEY | FOREIGN KEY (col) REFERENCES t(col) | Links to another table |
| NOT NULL | col type NOT NULL | Column must have a value |
| UNIQUE | col type UNIQUE | No duplicate values allowed |
| CHECK | CHECK (condition) | Validates data against condition |
| DEFAULT | col type DEFAULT val | Sets default value |
| ON DELETE CASCADE | ON DELETE CASCADE | Deleting parent deletes children |
| ON DELETE SET NULL | ON DELETE SET NULL | Deleting parent nullifies FK |
| ON DELETE RESTRICT | Default | Rejects delete if children exist |
⚠️ Common Pitfalls
Pitfall 1: Forgetting that PRIMARY KEY Implies NOT NULL
The Mistake: Declaring
PRIMARY KEY and also NOT NULL on the same column.
Why It's Wrong: PRIMARY KEY already includes NOT NULL. Redundant declaration is harmless but unnecessary.
Correct: Just use PRIMARY KEY.Pitfall 2: Using VARCHAR for Dates
The Mistake: "I'll just store dates as VARCHAR — '2024-01-15' works fine."
Why It's Wrong: VARCHAR dates don't prevent invalid dates ('2024-13-01'), can't be sorted chronologically, and can't use date arithmetic (ADD_MONTHS, etc.).
Correct: Use
DATE or TIMESTAMP for all temporal data.Pitfall 3: Confusing CASCADE Actions
The Mistake: "ON DELETE CASCADE deletes the foreign key column, not the rows."
Why It's Wrong: CASCADE means: when the parent row is deleted, also delete the child rows that reference it. It doesn't delete columns — it deletes entire rows.
Correct:
ON DELETE CASCADE: Parent row deleted → all child rows referencing it are deleted too. Use cautiously!📝 Practice Questions
Q1. Write a CREATE TABLE statement for a department table with: dept_name (primary key), building, budget (must be >= 0).
AnswersqlCREATE TABLE department ( dept_name VARCHAR(20) PRIMARY KEY, building VARCHAR(15), budget NUMERIC(12,2) CHECK (budget >= 0) );
Q2. Write a CREATE TABLE for employee with: emp_id (PK), name (NOT NULL), email (UNIQUE), salary (must be positive), dept_id (FK referencing department).
AnswersqlCREATE TABLE employee ( emp_id INTEGER PRIMARY KEY, name VARCHAR(50) NOT NULL, email VARCHAR(100) UNIQUE, salary NUMERIC(10,2) CHECK (salary > 0), dept_id INTEGER REFERENCES department(dept_id) );
Q3. What is the difference between DROP TABLE and DELETE FROM?
Answer
DROP TABLE instructor— Removes the entire table (structure + data). Table no longer exists.DELETE FROM instructor— Removes all rows. Table structure remains, can still insert new data.DROP is DDL (changes schema); DELETE is DML (changes data only).
Q4. Explain what ON DELETE CASCADE does. Give an example.
AnswerON DELETE CASCADE means: when a row in the parent table is deleted, all rows in the child table that reference it are automatically deleted too.Example: Ifdepartment('CS')is deleted, and courses table hasFOREIGN KEY (dept_name) REFERENCES department(dept_name) ON DELETE CASCADE, then all CS courses are deleted as well.Use when: child rows have no meaning without the parent (e.g., order items without the order).
Q5. Add a column phone to the instructor table.
AnswersqlALTER TABLE instructor ADD COLUMN phone VARCHAR(15);
Q6. What is the difference between CREATE TYPE and CREATE DOMAIN?
Answer
CREATE TYPEcreates a new data type (like typedef in C). Cannot add constraints.CREATE DOMAINcreates a new data type WITH constraints (CHECK conditions).Example:sqlCREATE DOMAIN positive_int AS INTEGER CHECK (VALUE > 0); CREATE TYPE ssn AS VARCHAR(9); -- no constraints
Q7. What are the five possible actions for foreign key ON DELETE? Briefly describe each.
Answer
- CASCADE — Delete referencing rows too
- SET NULL — Set foreign key to NULL
- SET DEFAULT — Set foreign key to its default value
- RESTRICT — Don't allow delete if there are referencing rows
- NO ACTION — Same as RESTRICT, but checked at end of transaction
Q8. Write the ALTER TABLE commands to: (a) make email NOT NULL, (b) add a CHECK that age >= 18.
Answersql-- (a) Make email NOT NULL ALTER TABLE student ALTER COLUMN email SET NOT NULL; -- (b) Add age check constraint ALTER TABLE student ADD CONSTRAINT age_check CHECK (age >= 18);
🔗 Cross-References
- Next Topic: 05 - SQL Queries
- Previous Topic: 03 - Relational Model
- Related: BSCS2003 (MAD 1) — Creating tables for web applications
- Related: BSMS2001 (BDM) — Database schema design for business
- Textbook: Silberschatz, Korth, Sudarshan — Chapter 3 (SQL), Chapter 4 (Intermediate SQL) Join Discord Previous03 - Relational ModelNext05 - SQL Queries