Chapter 3 Beginner 56 Questions

Practice Questions — Data Types and Constraints (NOT NULL, UNIQUE, PRIMARY KEY)

← Back to Notes
11 Easy
12 Medium
9 Hard

Topic-Specific Questions

Question 1
Easy
What data type should you use for a student's age?
Range is 0-150 at most.
TINYINT UNSIGNED (range 0-255, 1 byte) is ideal. INT works but wastes 3 bytes per row.
Question 2
Easy
What data type for a 12-digit Aadhaar number, and why not BIGINT?
Aadhaar can start with 0, and you never do math on it.
CHAR(12). Not BIGINT because (a) Aadhaar numbers can start with 0 which BIGINT would strip, and (b) we never perform arithmetic on an Aadhaar.
Question 3
Easy
What data type for a user's profile bio that can be up to 2000 characters?
Varchar limit vs TEXT.
VARCHAR(2000) or TEXT. VARCHAR is preferred here since 2000 chars is well below the VARCHAR limit and VARCHAR can be indexed fully.
Question 4
Easy
What data type for a date of birth?
Do you need the time of day?
DATE. Only year-month-day is needed — not hours or minutes.
Question 5
Easy
What data type for a product price like 1499.50?
Never FLOAT for money.
DECIMAL(10, 2) — up to 10 total digits with 2 after the decimal. Supports up to 99,999,999.99.
Question 6
Easy
Name three constraints that can be applied to a column in SQL.
Any three of six common ones.
Any three of: NOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY, CHECK, DEFAULT.
Question 7
Easy
What is the difference between PRIMARY KEY and UNIQUE?
Nullability and count per table.
PRIMARY KEY: uniquely identifies a row, cannot be NULL, only ONE per table. UNIQUE: values must be different, CAN be NULL (and multiple NULLs are usually allowed), MANY UNIQUE constraints allowed per table.
Question 8
Easy
What does AUTO_INCREMENT do?
Relates to ID generation.
AUTO_INCREMENT automatically assigns the next integer value to a column on each INSERT, so you don't have to provide the id yourself.
Question 9
Easy
What is the difference between CHAR(10) and VARCHAR(10)?
Storage and padding.
CHAR(10) always takes exactly 10 characters of storage (padded with spaces if shorter). VARCHAR(10) takes only the actual length plus 1-2 bytes overhead. VARCHAR is better for variable-length data; CHAR is marginally faster for strictly fixed-length data.
Question 10
Medium
When would you use DATETIME vs TIMESTAMP?
Time zones and range.
DATETIME: stores literal wall-clock time, range 1000-9999, no time zone logic. Use for fixed events like scheduled meeting times. TIMESTAMP: stored as UTC, converted to server time zone on read, range 1970-2038. Use for created_at/updated_at where automatic time zone handling is helpful.
Question 11
Medium
What is a composite primary key? Give an example.
More than one column.
A composite primary key is made of two or more columns. The COMBINATION must be unique, though each individual column may have duplicates. Example: an enrollments(student_id, course_id) table where a student can take many courses and a course has many students, but each (student, course) pair is unique.
Question 12
Medium
Why should you never store money as FLOAT?
Binary representation of decimal fractions.
FLOAT stores values in binary floating-point, which cannot exactly represent decimal fractions like 0.1 or 19.99. Summing 0.1 ten times gives 0.9999999 instead of 1.0. Over millions of transactions, balances silently drift. Always use DECIMAL for money.
Question 13
Medium
Write a CREATE TABLE for employees with: emp_id (auto-increment primary key), name (required up to 50 chars), email (unique, required), salary (decimal for money, required, must be positive), hire_date (date, required, default today).
Combine all the constraints you learned.
CREATE TABLE employees (
    emp_id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    salary DECIMAL(10,2) NOT NULL CHECK (salary > 0),
    hire_date DATE NOT NULL DEFAULT (CURRENT_DATE)
);
Question 14
Medium
Write a CREATE TABLE for an orders table that links to employees via a FOREIGN KEY.
FOREIGN KEY ... REFERENCES.
CREATE TABLE orders (
    order_id INT AUTO_INCREMENT PRIMARY KEY,
    emp_id INT NOT NULL,
    amount DECIMAL(10,2) NOT NULL CHECK (amount > 0),
    order_date DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (emp_id) REFERENCES employees(emp_id)
);
Question 15
Medium
Write a CREATE TABLE for a junction table enrollments that captures which student is enrolled in which course, with enrollment date. Use a composite primary key.
PRIMARY KEY (student_id, course_id).
CREATE TABLE enrollments (
    student_id INT,
    course_id INT,
    enrolled_on DATE DEFAULT (CURRENT_DATE),
    PRIMARY KEY (student_id, course_id)
);
Question 16
Medium
Can a PRIMARY KEY column be NULL?
Think about what a primary key represents.
No. A PRIMARY KEY is implicitly NOT NULL. It must uniquely identify each row, and NULL means "unknown", which cannot uniquely identify anything.
Question 17
Medium
Can a UNIQUE column be NULL?
Yes, usually, and multiple NULLs are allowed.
Yes. In MySQL, a UNIQUE column allows NULL values and treats multiple NULLs as NOT duplicates of each other — so multiple rows can have NULL in a UNIQUE column.
Question 18
Hard
Your team wants to add a CHECK constraint to ensure an age column is between 18 and 100. Write the constraint.
CHECK (condition).
age INT NOT NULL CHECK (age BETWEEN 18 AND 100)
Or equivalently: CHECK (age >= 18 AND age <= 100).
Question 19
Hard
Why might you use ENUM('Male', 'Female', 'Other') instead of VARCHAR(10) for a gender column?
Space and validation.
Two reasons: (1) ENUM is stored internally as a 1-byte integer regardless of string length — far more efficient; (2) ENUM restricts values to the listed options, so no one can insert 'male ' (trailing space), 'MALE', or 'foo' — the database validates for you.
Question 20
Hard
Your DBA proposes using DOUBLE for storing student CGPAs. Is that acceptable or would you push back?
Precision matters for grades.
Push back. CGPA is shown to students to 2 decimal places and can cause disputes if rounding drifts (9.24 vs 9.25 affects scholarships). Use DECIMAL(3, 2) for exact 0.00-9.99 representation.

Mixed & Application Questions

Question 1
Easy
Match each data type with its best use case: INT, VARCHAR(50), DATE, DECIMAL(10,2), BOOLEAN.
One per column.
INT → row IDs, counts. VARCHAR(50) → names, emails. DATE → date of birth, joining date. DECIMAL(10,2) → money, product price. BOOLEAN → yes/no flags like is_active.
Question 2
Easy
Spot the bad choice and fix it:
CREATE TABLE users (
    id INT,
    phone INT,
    bio VARCHAR(5000),
    balance FLOAT
);
Phone, bio, balance all wrong.
CREATE TABLE users (
    id INT PRIMARY KEY,
    phone VARCHAR(15),       -- was INT, lost leading zeros
    bio TEXT,                 -- was VARCHAR(5000), too big for VARCHAR
    balance DECIMAL(12,2)     -- was FLOAT, loses precision on money
);
Question 3
Medium
Can a table have zero constraints? Is that a good design?
MySQL allows it, but...
Yes, MySQL allows it. But it is a poor design. Without constraints, bad data silently flows in and you end up cleaning the mess later in queries.
Question 4
Medium
Create a products table: id auto-increment PK, name required up to 80 chars, sku unique required 20 chars, price decimal for money must be positive, category an ENUM of 'Electronics', 'Books', 'Clothing', and is_active boolean defaulting TRUE.
Combine everything.
CREATE TABLE products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(80) NOT NULL,
    sku VARCHAR(20) NOT NULL UNIQUE,
    price DECIMAL(10,2) NOT NULL CHECK (price > 0),
    category ENUM('Electronics', 'Books', 'Clothing') NOT NULL,
    is_active BOOLEAN DEFAULT TRUE
);
Question 5
Medium
What happens if you try to insert a CGPA of 11.5 into a column declared as DECIMAL(3,2) CHECK (cgpa <= 10)?
Two things could fail.
Two possible issues. First, DECIMAL(3,2) means 3 total digits with 2 after the decimal — max allowed is 9.99, so 11.5 exceeds the type's max. Second, even if the type allowed it, the CHECK (cgpa <= 10) would reject it. In MySQL you'll get an "Out of range" error first.
Question 6
Medium
Why do FOREIGN KEY constraints sometimes prevent deletes you think should work?
Orphan child rows.
If another table references a row via FOREIGN KEY, deleting the parent leaves orphan children. MySQL blocks the delete by default. You must either delete the children first or configure ON DELETE CASCADE / SET NULL on the FK.
Question 7
Hard
A colleague declares a column as VARCHAR(50) but always inserts values exactly 50 characters long. Is VARCHAR fine here or should they switch to CHAR?
Fixed length implies fixed storage.
Switch to CHAR(50). Since every value is exactly 50 characters, CHAR is slightly faster (fixed-width rows) and saves the 1-2 byte length prefix that VARCHAR adds to every value.
Question 8
Hard
You need to store the exact moment (to the microsecond) a user clicked a button. Which type: DATETIME(6), TIMESTAMP(6), or BIGINT storing epoch microseconds?
Time zone and range matter.
Depends. TIMESTAMP(6) gives microsecond precision and automatic UTC handling — best if you are before 2038. DATETIME(6) gives microseconds but no time zone logic — best if you might store events beyond 2038 or want the literal wall-clock time. BIGINT is the most portable and survives the 2038 bug but requires application-level conversion to a readable date.
Question 9
Hard
Your friend says: "Since UNIQUE constraints prevent duplicates, we can just slap UNIQUE on many columns and skip the PRIMARY KEY." Counter this.
Primary keys do more than uniqueness.
Three reasons to still have a PRIMARY KEY: (1) PK implies NOT NULL (UNIQUE alone allows NULL). (2) PK creates the main clustered index in InnoDB — hugely impacts storage layout and query speed. (3) Foreign keys from other tables need a primary key (or unique key) to reference.
Question 10
Hard
Fix the design error:
CREATE TABLE bookings (
    user_id INT UNIQUE,
    room_id INT UNIQUE,
    booking_date DATE
);
The business rule is: a user can book many rooms; a room can be booked by many users; but no (user, room, date) triple should repeat.
Neither column alone is unique.
CREATE TABLE bookings (
    user_id INT,
    room_id INT,
    booking_date DATE,
    PRIMARY KEY (user_id, room_id, booking_date)
);
Question 11
Hard
A table has created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP and updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP. Explain what happens on INSERT and on UPDATE.
ON UPDATE changes the behavior.
On INSERT: both columns get the current timestamp. On UPDATE of any other column in the row: updated_at is automatically refreshed to the current timestamp, but created_at stays unchanged.
Question 12
Hard
Design a course_enrollments table for a college. Rules: a student takes many courses; a course has many students; each enrollment has a date and optional final grade (A, B, C, D, F); you should not be able to re-enroll the same student in the same course (unless they're repeating, in which case a separate attempt_no distinguishes them).
Composite PK with attempt_no.
CREATE TABLE course_enrollments (
    student_id INT NOT NULL,
    course_id INT NOT NULL,
    attempt_no TINYINT NOT NULL DEFAULT 1,
    enrolled_on DATE NOT NULL DEFAULT (CURRENT_DATE),
    grade CHAR(1) CHECK (grade IN ('A','B','C','D','F')),
    PRIMARY KEY (student_id, course_id, attempt_no),
    FOREIGN KEY (student_id) REFERENCES students(student_id),
    FOREIGN KEY (course_id) REFERENCES courses(course_id)
);

Multiple Choice Questions

MCQ 1
Which data type is best for storing exact monetary amounts?
  • A. FLOAT
  • B. DOUBLE
  • C. DECIMAL
  • D. INT
Answer: C
C is correct. DECIMAL stores values exactly, which is essential for money. FLOAT and DOUBLE introduce binary floating-point rounding errors. INT can't store paise/cents as a decimal.
MCQ 2
Which data type should a 10-digit Indian mobile number be stored as?
  • A. INT
  • B. BIGINT
  • C. DECIMAL(10,0)
  • D. VARCHAR(15)
Answer: D
D is correct. Phone numbers may have leading zeros, country codes, hyphens, or spaces. VARCHAR preserves all of that. Numeric types would strip leading zeros and block international formats.
MCQ 3
How many primary keys can a table have?
  • A. One
  • B. Two
  • C. As many as you want
  • D. Zero
Answer: A
A is correct. A table can have only ONE primary key (though it can be composed of multiple columns — a composite key). You can have many UNIQUE constraints, but only one PRIMARY KEY.
MCQ 4
Which keyword enforces that a column cannot have duplicate values?
  • A. NOT NULL
  • B. UNIQUE
  • C. CHECK
  • D. DEFAULT
Answer: B
B is correct. UNIQUE prevents duplicate values. NOT NULL prevents empty values. CHECK enforces a general condition. DEFAULT provides a fallback.
MCQ 5
Which data type stores only date (no time) in MySQL?
  • A. DATETIME
  • B. TIMESTAMP
  • C. DATE
  • D. TIME
Answer: C
C is correct. DATE stores YYYY-MM-DD only. DATETIME and TIMESTAMP include time. TIME stores only HH:MM:SS.
MCQ 6
What does AUTO_INCREMENT do?
  • A. Automatically updates the column on every change
  • B. Automatically generates a new integer value for each inserted row
  • C. Automatically deletes old rows
  • D. Automatically checks constraints
Answer: B
B is correct. AUTO_INCREMENT generates a new (usually sequential) integer for each INSERT. You can omit the column in INSERT and MySQL fills it in.
MCQ 7
Which type is appropriate for an Aadhaar number (12 digits, fixed length)?
  • A. INT
  • B. BIGINT
  • C. CHAR(12)
  • D. VARCHAR(12)
Answer: C
C is correct. Aadhaar is exactly 12 digits, never changes length, and can have leading zeros. CHAR(12) is slightly better than VARCHAR(12) for fixed-length strings. Numeric types lose leading zeros.
MCQ 8
Which combination of constraints does PRIMARY KEY imply?
  • A. UNIQUE only
  • B. NOT NULL only
  • C. UNIQUE and NOT NULL
  • D. CHECK and DEFAULT
Answer: C
C is correct. A PRIMARY KEY is implicitly both UNIQUE (no duplicate values) and NOT NULL (must have a value). That's why it can uniquely identify every row.
MCQ 9
What is the difference between DATETIME and TIMESTAMP in MySQL?
  • A. TIMESTAMP is time-zone-aware and has a smaller range (1970-2038); DATETIME is literal and has a huge range (1000-9999)
  • B. They are the same thing
  • C. TIMESTAMP stores only the time, DATETIME stores only the date
  • D. DATETIME is faster than TIMESTAMP
Answer: A
A is correct. TIMESTAMP is stored in UTC and auto-converted to session time zone on read, but its range is limited due to the Y2K38 problem. DATETIME is stored as the literal wall-clock time with a 1000-9999 range, no TZ logic.
MCQ 10
Which is a correct CREATE TABLE statement?
  • A. CREATE TABLE t (a INT UNIQUE, b INT UNIQUE, PRIMARY KEY (a, b));
  • B. CREATE TABLE t (a INT PRIMARY KEY PRIMARY KEY);
  • C. CREATE TABLE t (a INT, b INT, PRIMARY KEY a);
  • D. CREATE TABLE t (a INT, b INT, PRIMARY KEY (a), PRIMARY KEY (b));
Answer: A
A is correct. You can have multiple UNIQUE columns plus a composite PRIMARY KEY. B has duplicate keywords. C has syntax error (no parentheses around column name). D has two PRIMARY KEYs which isn't allowed.
MCQ 11
Which of the following is NOT a valid MySQL numeric type?
  • A. TINYINT
  • B. SMALLINT
  • C. LARGEINT
  • D. BIGINT
Answer: C
C is correct. LARGEINT is not a MySQL type. The valid integer types are TINYINT (1 byte), SMALLINT (2), MEDIUMINT (3), INT (4), and BIGINT (8).
MCQ 12
In MySQL, BOOLEAN is internally stored as which type?
  • A. CHAR(1)
  • B. TINYINT(1)
  • C. BIT
  • D. ENUM
Answer: B
B is correct. MySQL's BOOLEAN is a synonym for TINYINT(1), with TRUE = 1 and FALSE = 0. You can write either BOOLEAN or TINYINT(1); they are equivalent.
MCQ 13
DECIMAL(7, 2) can store values up to:
  • A. 9999.99
  • B. 99999.99
  • C. 999999.99
  • D. 9999999.99
Answer: B
B is correct. DECIMAL(7,2) means 7 total digits with 2 after the decimal, leaving 5 before: max is 99999.99. For larger money amounts, use DECIMAL(10,2) or DECIMAL(15,2).
MCQ 14
Which is TRUE about FOREIGN KEY constraints?
  • A. They reference any column in any table
  • B. They prevent orphan rows by requiring the referenced value to exist in the parent table
  • C. They replace PRIMARY KEY
  • D. They are the same as UNIQUE
Answer: B
B is correct. Foreign keys ensure referential integrity: every child value must correspond to an existing parent row. They typically reference a PRIMARY KEY or UNIQUE column in the parent table.
MCQ 15
Your table has a UNIQUE constraint on email. How many rows can have email = NULL in MySQL?
  • A. At most one
  • B. Zero (NOT NULL implied)
  • C. Any number
  • D. Depends on SQL mode
Answer: C
C is correct. In MySQL, UNIQUE treats multiple NULLs as not duplicates of each other, so any number of rows can have email = NULL. This differs from SQL Server's classic behavior (at most one NULL) but matches PostgreSQL and the SQL standard.
MCQ 16
An INSERT gives "ERROR 1452: Cannot add or update a child row: a foreign key constraint fails". What is the cause?
  • A. A UNIQUE constraint violation
  • B. A primary key violation
  • C. The value in the FK column doesn't exist in the parent table
  • D. The AUTO_INCREMENT ran out of IDs
Answer: C
C is correct. Error 1452 means the foreign key refers to a non-existent parent row. Example: inserting an order with student_id=999 when no student 999 exists. Fix: either create the parent first, or fix the FK value.
MCQ 17
Which statement about CHECK constraints in MySQL is TRUE?
  • A. CHECK has always been enforced in every MySQL version
  • B. CHECK is only enforced in MySQL 8.0.16 and later; earlier versions parsed but ignored them
  • C. CHECK only works with numeric columns
  • D. CHECK cannot be used with NOT NULL
Answer: B
B is correct. Historically MySQL parsed CHECK constraints for syntax compatibility but ignored them at runtime. Starting with MySQL 8.0.16 (April 2019), CHECK is properly enforced. Older MySQL installs silently accept invalid rows.
MCQ 18
You create: id INT AUTO_INCREMENT PRIMARY KEY and insert 10 rows (IDs 1-10), then DELETE all rows. You then insert one row. What id does it get?
  • A. 1
  • B. 10
  • C. 11
  • D. Depends
Answer: C
C is correct. DELETE does not reset AUTO_INCREMENT. The counter continues from where it left off, so the new row gets id=11. If you had used TRUNCATE instead of DELETE, the counter would reset to 1.
MCQ 19
You need to store a very long article (say, 200KB of text). Best type?
  • A. VARCHAR(65535)
  • B. TEXT
  • C. MEDIUMTEXT
  • D. LONGTEXT
Answer: C
C is correct. TEXT holds up to ~64KB — 200KB won't fit. MEDIUMTEXT holds up to 16MB. LONGTEXT is overkill for 200KB but would also work. VARCHAR is capped at 65,535 bytes across the whole row, so 200KB is impossible in VARCHAR.
MCQ 20
Which design prevents re-enrolling the same student in the same course twice?
  • A. Two separate UNIQUE constraints on student_id and course_id
  • B. A composite PRIMARY KEY on (student_id, course_id)
  • C. CHECK (student_id != course_id)
  • D. AUTO_INCREMENT on both columns
Answer: B
B is correct. A composite PRIMARY KEY on (student_id, course_id) enforces uniqueness of the PAIR, which is exactly the rule. Option A would wrongly force each student to appear only once across all enrollments and each course to appear only once — far too restrictive.

Coding Challenges

Challenge 1: Design a Realistic students Table

Easy
Design a students table with: id (auto-increment PK), name (required, up to 60 chars), email (required, unique, up to 100 chars), phone (optional, up to 15 chars), dob (date, required), cgpa (decimal with 2 decimal places, 0 to 10, default 0), is_active (boolean defaulting TRUE), created_at (timestamp auto-set on insert).
Sample Input
(No input)
Sample Output
A clean CREATE TABLE with the correct types and constraints.
Use all six common constraints where appropriate.
CREATE TABLE students (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(60) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    phone VARCHAR(15),
    dob DATE NOT NULL,
    cgpa DECIMAL(4,2) DEFAULT 0.00 CHECK (cgpa >= 0 AND cgpa <= 10),
    is_active BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Quick sanity check
DESCRIBE students;

Challenge 2: Pick the Right Type

Easy
For each real-world field, suggest the best MySQL data type and briefly justify: (a) User's age, (b) Aadhaar number, (c) Email, (d) Blog post body, (e) Product price in INR, (f) Order timestamp, (g) Employee joining date.
Sample Input
(No input)
Sample Output
Annotated list with type + 1-line reason.
Write as SQL comments.
-- (a) age           -> TINYINT UNSIGNED   (range 0-255, 1 byte)
-- (b) aadhaar       -> CHAR(12)            (fixed 12 digits, leading zeros)
-- (c) email         -> VARCHAR(100)        (variable, index-friendly)
-- (d) blog body     -> MEDIUMTEXT          (can exceed 64KB)
-- (e) price INR     -> DECIMAL(10,2)       (exact money, no float errors)
-- (f) order time    -> TIMESTAMP           (auto time-zone, for audit)
-- (g) joining_date  -> DATE                (year-month-day only)

Challenge 3: Employees With Constraints

Medium
Create an employees table: emp_id auto-increment PK; name required up to 50 chars; email required and unique up to 100 chars; salary DECIMAL(10,2) required and strictly positive; department ENUM of 'HR','IT','Finance','Sales','Marketing' required; hire_date DATE defaulting to current date. Then insert three valid employees and attempt one invalid insert (negative salary) to show the CHECK working.
Sample Input
(No input)
Sample Output
Three valid rows. Fourth insert raises a CHECK error.
Use CHECK and ENUM and DEFAULT.
CREATE DATABASE IF NOT EXISTS hr;
USE hr;
DROP TABLE IF EXISTS employees;

CREATE TABLE employees (
    emp_id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    salary DECIMAL(10,2) NOT NULL CHECK (salary > 0),
    department ENUM('HR','IT','Finance','Sales','Marketing') NOT NULL,
    hire_date DATE NOT NULL DEFAULT (CURRENT_DATE)
);

-- 3 valid inserts
INSERT INTO employees (name, email, salary, department) VALUES
    ('Kavya Nair',    'kavya@corp.com',  60000.00, 'HR'),
    ('Arjun Mehta',   'arjun@corp.com',  85000.00, 'IT'),
    ('Sneha Patel',   'sneha@corp.com',  72000.50, 'Finance');

-- 1 invalid insert (negative salary)
INSERT INTO employees (name, email, salary, department)
VALUES ('Rahul Joshi', 'rahul@corp.com', -50000.00, 'Sales');
-- Expected error:
-- ERROR 3819 (HY000): Check constraint 'employees_chk_1' is violated.

Challenge 4: Orders with Foreign Key

Medium
Assuming employees from the previous challenge, create an orders table that links each order to an employee. Columns: order_id auto PK; emp_id INT required, FK to employees; amount decimal money positive; order_date datetime default CURRENT_TIMESTAMP. Insert 2 valid orders, then attempt an invalid one referencing a non-existent emp_id to show FK protection.
Sample Input
(No input)
Sample Output
Two valid rows. Third insert raises FK error.
Use FOREIGN KEY REFERENCES.
CREATE TABLE orders (
    order_id INT AUTO_INCREMENT PRIMARY KEY,
    emp_id INT NOT NULL,
    amount DECIMAL(10,2) NOT NULL CHECK (amount > 0),
    order_date DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (emp_id) REFERENCES employees(emp_id)
);

-- Valid
INSERT INTO orders (emp_id, amount) VALUES (1, 1500.00);
INSERT INTO orders (emp_id, amount) VALUES (2, 2499.99);

-- Invalid: emp_id 999 does not exist
INSERT INTO orders (emp_id, amount) VALUES (999, 500.00);
-- Expected:
-- ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails

SELECT * FROM orders;

Challenge 5: DECIMAL vs FLOAT Demo

Hard
Create two tables payments_decimal and payments_float that each have one column amount of type DECIMAL(10,2) and FLOAT respectively. Insert 1000 rows of 0.01 into each (you can use a stored procedure or a large VALUES list of 10 rows and run it multiple times). Sum the amounts. Observe the difference and write a final comment explaining why DECIMAL is mandatory for money.
Sample Input
(No input)
Sample Output
total_decimal = 10.00 exact. total_float = 9.99999... or 10.000000.. imprecise.
Demonstrate with at least 100 rows to make the error visible.
DROP TABLE IF EXISTS payments_decimal;
DROP TABLE IF EXISTS payments_float;

CREATE TABLE payments_decimal (amount DECIMAL(10,2));
CREATE TABLE payments_float   (amount FLOAT);

-- Insert 10 rows of 0.01 at a time, 10 times => 100 rows
INSERT INTO payments_decimal VALUES
 (0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01);
INSERT INTO payments_decimal SELECT * FROM payments_decimal;
INSERT INTO payments_decimal SELECT * FROM payments_decimal;  -- now 40 rows
INSERT INTO payments_decimal SELECT * FROM payments_decimal;  -- now 80 rows
INSERT INTO payments_decimal VALUES
 (0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),
 (0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01);
-- now 100 rows

INSERT INTO payments_float VALUES
 (0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01);
INSERT INTO payments_float SELECT * FROM payments_float;
INSERT INTO payments_float SELECT * FROM payments_float;
INSERT INTO payments_float SELECT * FROM payments_float;
INSERT INTO payments_float VALUES
 (0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),
 (0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01),(0.01);

SELECT SUM(amount) AS total_decimal FROM payments_decimal;
-- +---------------+
-- | total_decimal |
-- +---------------+
-- |          1.00 |   (100 * 0.01 = exact 1.00)

SELECT SUM(amount) AS total_float FROM payments_float;
-- +----------------------+
-- | total_float          |
-- +----------------------+
-- | 0.9999999776482582   |   (binary float drift!)

-- CONCLUSION:
-- Over just 100 tiny transactions the FLOAT sum is already off by ~0.0001.
-- On 10 million real transactions, this becomes a visible mismatch.
-- Always use DECIMAL for money.

Challenge 6: Course Enrollment System

Hard
Design three tables — students, courses, enrollments — for a realistic college. Include correct PRIMARY KEYs, composite PK on enrollments(student_id, course_id), FOREIGN KEYs, CHECK on marks (0-100), DEFAULT for enrollment_date, and appropriate types. Insert 3 students, 3 courses, and 5 enrollments.
Sample Input
(No input)
Sample Output
Three tables created, populated, and a SELECT joining them at the end.
Use every constraint type you've learned.
-- Reset
DROP TABLE IF EXISTS enrollments;
DROP TABLE IF EXISTS students;
DROP TABLE IF EXISTS courses;

-- students
CREATE TABLE students (
    student_id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(60) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    dob DATE NOT NULL
);

-- courses
CREATE TABLE courses (
    course_id INT AUTO_INCREMENT PRIMARY KEY,
    course_name VARCHAR(80) NOT NULL UNIQUE,
    credits TINYINT NOT NULL CHECK (credits BETWEEN 1 AND 6)
);

-- enrollments (junction)
CREATE TABLE enrollments (
    student_id INT NOT NULL,
    course_id INT NOT NULL,
    enrolled_on DATE NOT NULL DEFAULT (CURRENT_DATE),
    marks TINYINT CHECK (marks BETWEEN 0 AND 100),
    PRIMARY KEY (student_id, course_id),
    FOREIGN KEY (student_id) REFERENCES students(student_id),
    FOREIGN KEY (course_id)  REFERENCES courses(course_id)
);

INSERT INTO students (name, email, dob) VALUES
    ('Aarav Sharma', 'aarav@college.edu', '2005-03-15'),
    ('Priya Iyer',   'priya@college.edu', '2004-11-22'),
    ('Rohan Verma',  'rohan@college.edu', '2005-07-08');

INSERT INTO courses (course_name, credits) VALUES
    ('Database Systems', 4),
    ('Data Structures',  4),
    ('Operating Systems', 3);

INSERT INTO enrollments (student_id, course_id, marks) VALUES
    (1, 1, 87),
    (1, 2, 92),
    (2, 1, 78),
    (2, 3, 85),
    (3, 2, 91);

-- Verify with a simple JOIN (covered in Chapter 11)
SELECT s.name, c.course_name, e.marks
FROM enrollments e
JOIN students s ON s.student_id = e.student_id
JOIN courses  c ON c.course_id  = e.course_id;

-- Expected: 5 rows with student name, course name, and marks.

Need to Review the Concepts?

Go back to the detailed notes for this chapter.

Read Chapter Notes

Want to master SQL and databases with a mentor?

Explore our MySQL Masterclass