# SQL Quiz

## Question 1

What does an INNER JOIN return?

A) All rows from both tables
B) Only rows with matching values in both tables
C) All rows from the left table
D) Only the first matching row from each table

<!-- ANSWER: B -->
<!-- EXPLANATION: INNER JOIN returns only rows where the join condition is satisfied in both tables. Rows with no match in the other table are excluded. -->

## Question 2

What is the difference between LEFT JOIN and INNER JOIN?

A) They are the same
B) LEFT JOIN includes all rows from the left table, even with no match
C) LEFT JOIN is faster
D) INNER JOIN includes NULLs

<!-- ANSWER: B -->
<!-- EXPLANATION: LEFT JOIN returns all rows from the left table. Where there's no match in the right table, right-side columns are NULL. INNER JOIN excludes such rows. -->

## Question 3

When do you use HAVING instead of WHERE?

A) HAVING is for strings, WHERE is for numbers
B) HAVING filters after aggregation; WHERE filters before
C) HAVING is for JOINs, WHERE is for single tables
D) They are interchangeable

<!-- ANSWER: B -->
<!-- EXPLANATION: WHERE filters rows before GROUP BY. HAVING filters groups after aggregation. You use HAVING when the condition involves an aggregate (e.g., SUM(amount) > 100). -->

## Question 4

What does 2NF (Second Normal Form) require?

A) No duplicate rows
B) No partial dependencies — all non-key attributes depend on the whole primary key
C) No more than 2 columns per table
D) All tables must have a foreign key

<!-- ANSWER: B -->
<!-- EXPLANATION: 2NF builds on 1NF (atomic values) and requires that no non-key attribute depends on only part of a composite primary key. This eliminates partial dependencies. -->

## Question 5

Which query finds users who have placed no orders? (users.id, orders.user_id)

A) SELECT * FROM users INNER JOIN orders ON users.id = orders.user_id
B) SELECT * FROM users LEFT JOIN orders ON users.id = orders.user_id WHERE orders.id IS NULL
C) SELECT * FROM users WHERE orders.user_id IS NULL
D) SELECT * FROM users RIGHT JOIN orders ON users.id = orders.user_id

<!-- ANSWER: B -->
<!-- EXPLANATION: LEFT JOIN keeps all users. Where there's no order, orders columns are NULL. WHERE orders.id IS NULL filters to users with no matching order. -->

## Question 6

What is the purpose of an index?

A) To store backup data
B) To speed up queries on indexed columns
C) To enforce unique values
D) To reduce storage

<!-- ANSWER: B -->
<!-- EXPLANATION: Indexes create a data structure (e.g., B-tree) that speeds up lookups, WHERE, JOIN, and ORDER BY on indexed columns. They trade write speed and storage for read speed. -->

## Question 7

<!-- VISUAL: drag-order -->

Put these SQL clause phases in the order they are logically evaluated during query execution:

A) ORDER BY
B) WHERE
C) FROM
D) GROUP BY / HAVING

<!-- ANSWER: C,B,D,A -->
<!-- EXPLANATION: SQL evaluates FROM first (identify tables), then WHERE (filter rows), then GROUP BY/HAVING (aggregation), then ORDER BY (sort results). SELECT projects columns throughout but the logical order of row processing is FROM → WHERE → GROUP BY → ORDER BY. -->

## Question 8

<!-- VISUAL: fill-blank -->

Complete the query to find customers who have ordered more than 5 times:

```sql
SELECT customer_id, COUNT(*) AS order_count
FROM orders
GROUP BY customer_id
___0___ COUNT(*) > 5;
```

<!-- ANSWER: HAVING -->
<!-- EXPLANATION: HAVING filters after aggregation. WHERE cannot use aggregate functions like COUNT(*). HAVING applies to grouped rows, so HAVING COUNT(*) > 5 correctly filters to customers with more than 5 orders. -->
