CTEs (using WITH) and subqueries allow you to break down complex problems into manageable,
readable steps.
They are essential for creating temporary result sets that you can reference within a larger query.
FROM clause, a CTE improves readability:SELECT
WITH CustomerOrderTotals AS (
SELECT
CustomerID,
SUM(TotalAmount) AS TotalSpent,
COUNT(OrderID) AS OrderCount
FROM
Orders
GROUP BY
CustomerID
)
-- Now use the CTE in the main query
SELECT
CustomerID,
TotalSpent,
OrderCount,
TotalSpent / OrderCount AS AvgOrderValue
FROM
CustomerOrderTotals
WHERE
TotalSpent > 1000;
GROUP BY and HAVING Clause)While WHERE filters individual rows before aggregation, HAVING filters groups
GROUP BY after aggregation. This is crucial for analyzing summary data.
SELECT
Category,
COUNT(ProductID) AS ProductCount
FROM
Products
GROUP BY
Category
HAVING
COUNT(ProductID) > 100; -- Filters only the groups where the count is over 100
CASE Statements and Conditional LogicCASE statements are SQL's way of implementing if-else logic, allowing you to categorize data or
display different values based on certain conditions.
SELECT
ProductName,
Price,
CASE
WHEN Price > 500 THEN 'High'
WHEN Price > 100 THEN 'Medium'
ELSE 'Low'
END AS PriceRange
FROM
Products;
Views are virtual tables based on the result-set of a query. They simplify complex queries for
end-users and enhance security.
Stored procedures are precompiled SQL code stored in the database. They can be called by name,
making them reusable and efficient.
CREATE VIEW RecentSales AS
SELECT
O.OrderID,
C.CustomerName,
O.OrderDate,
O.TotalAmount
FROM
Orders O
JOIN
Customers C ON O.CustomerID = C.CustomerID
WHERE
O.OrderDate >= DATEADD(day, -30, GETDATE());
A beginner knows INNER JOIN. An intermediate user understands how different join types relate to
database
relationship types (one-to-many, many-to-many) and can choose the correct join to ensure data integrity and
completeness.
LEFT JOIN (or LEFT OUTER JOIN): Returns all records from the left table,
and the matched records from the right table. If no match is found, result is NULL on the right side.RIGHT JOIN: Returns all records from the right table, and the matched records from the left
table.FULL OUTER JOIN: Returns all records when there is a match in either the left or the right
table.CROSS JOIN: Returns the Cartesian product of rows from both tables (every row from the left
combined with every row from the right).
Left Join): Listing all customers, including those
who have not
placed an order. Similarly (Right Join) - will have all orders including those with missing
customer_id.
SELECT
C.CustomerName,
O.OrderID,
O.OrderDate
FROM
Customers C
LEFT JOIN
Orders O ON C.CustomerID = O.CustomerID
WHERE
O.OrderID IS NULL; -- NULL Filters specifically for customers who have NO orders
Example (Cross Join): Every row from left table combined with every row
from right table (Cartesian Product of the two tables), which means all possible pairs of rows from the two
tables: Consider | customer_id | customer_name |
|---|---|
| 101 | Alice |
| 102 | Bob |
| 103 | Charlie |
| product_id | product_name |
|---|---|
| 2001 | Mobile |
| 2002 | TV |
| 2003 | Laptop |
SELECT
C.CustomerName,
P.ProductName
FROM
Customers C
CROSS JOIN
Products P; --- The result will be 3 x 3 = (9) records of all possible pairs of customer and products
An intermediate user understands that how data is stored, matters. Indexes are like book
indexes—they help the database engine find rows quickly without reading the entire table (a slow Table
Scan). The ability to view a query's execution plan is key to identifying performance
bottlenecks.
Orders table is slow:
SELECT
*
FROM
Orders
WHERE
OrderDate BETWEEN '2025-01-01' AND '2025-01-31';
An intermediate user would: CREATE INDEX
idx_order_date
ON Orders (OrderDate);
Re-evaluate: Rerunning the query now shows an "Index Seek" in the execution plan, and the total
query cost drops significantly.