MENU
Essential Concepts
A handful of techniques are central to writing efficient, sophisticated SQL queries, building on the Basic CRUD examples above.Sorting
Sorting in SQL queries is achieved with the ORDER BY clause:SELECT id, fullname, class FROM Students ORDER BY fullname;| id | fullname | class |
|---|---|---|
| hh09hhhj | Alex Phil | 2A |
| fsh8sd8f | Ivy Hugh | 2D |
| g98fdhh8 | Mike Tudor | 1C |
A descending order is achieved by appending the sort field's name with the DESC keyword.
SELECT id, fullname, class FROM Students ORDER BY fullname DESC;| id | fullname | class |
|---|---|---|
| g98fdhh8 | Mike Tudor | 1C |
| fsh8sd8f | Ivy Hugh | 2D |
| hh09hhhj | Alex Phil | 2A |
After being sorted once, records can be "further sorted" by comparing other fields when the first sort field yields the same values:
SELECT subj, dt, score FROM Tests ORDER BY subj DESC, dt DESC, score ASC;| subj | dt | score |
|---|---|---|
| Maths | 2023-05-13 | 57 |
| Maths | 2023-05-13 | 79 |
| Maths | 2023-03-21 | 45 |
| Maths | 2023-03-21 | 53 |
| Maths | 2023-01-05 | 45 |
| Maths | 2023-01-05 | 87 |
| History | 2023-05-18 | 99 |
Limit
With one integer, the LIMIT n clause specifies the first n records retrieved:SELECT subj, dt, score FROM Tests ORDER BY score LIMIT 3;| subj | dt | score |
|---|---|---|
| Maths | 2023-01-05 | 45 |
| Maths | 2023-03-21 | 45 |
| Maths | 2023-03-21 | 53 |
With two integers, the LIMIT m, n clause specifies the first n records retrieved after skipping an offset of m records:
SELECT subj, dt, score FROM Tests ORDER BY score LIMIT 2,3;| subj | dt | score |
|---|---|---|
| Maths | 2023-03-21 | 53 |
| Maths | 2023-05-13 | 57 |
| Maths | 2023-05-13 | 79 |
To retrieve a random record:
SELECT subj, dt, score FROM Tests ORDER BY RAND() LIMIT 1;Using ORDER BY RAND() can be inefficient for large tables, since it requires MySQL to assign random values to all rows before sorting. For a substantial table, it is recommended to explore alternative methods for retrieving random records, such as building and executing a prepared statement instead:
SET @n = (SELECT COUNT(*) FROM Tests);
SET @n = FLOOR(RAND() * @n);
SET @s = CONCAT('SELECT subj, dt, score FROM Tests LIMIT ',@n,",1;");
PREPARE ps FROM @s;
EXECUTE ps;
DEALLOCATE PREPARE ps;Aggregate
In SQL, aggregates are functions that perform calculations on a set of values and return a single value as the result. Aggregates are commonly used to summarize data and perform calculations across multiple rows of a table.Common SQL aggregates include:
- SUM: Returns the total of all the values in a specified column.
- AVG: Returns the average of all the values in a specified column.
- COUNT: Returns the number of rows in a specified column.
- MAX: Returns the maximum value in a specified column.
- MIN: Returns the minimum value in a specified column.
SELECT subj, AVG(score) FROM Tests GROUP BY subj;| subj | AVG(score) |
|---|---|
| History | 99.0000 |
| Maths | 61.0000 |
When using aggregates in SQL, any non-aggregated columns included in the SELECT statement must also be included in the GROUP BY clause. See Aggregate for a fuller reference on aggregate functions.
Join
In SQL, joins are used to combine rows from two or more tables based on a related column between them. Different tables can be "joined" to relate data across them.SELECT * FROM Students JOIN Tests ON Students.id=Tests.student_id;| id | fullname | dob | class | test_id | student_id | subj | dt | score |
|---|---|---|---|---|---|---|---|---|
| hh09hhhj | Alex Phil | 2010-12-11 | 2A | M_sasgkj | hh09hhhj | Maths | 2023-01-05 | 87 |
| hh09hhhj | Alex Phil | 2010-12-11 | 2A | M_lgjg88 | hh09hhhj | Maths | 2023-03-21 | 53 |
| hh09hhhj | Alex Phil | 2010-12-11 | 2A | M_qas9ij | hh09hhhj | Maths | 2023-05-13 | 57 |
| g98fdhh8 | Mike Tudor | 2011-05-28 | 1C | H_sdjksd | g98fdhh8 | History | 2023-05-18 | 99 |
| fsh8sd8f | Ivy Hugh | 2010-10-23 | 2D | M_sasgkj | fsh8sd8f | Maths | 2023-01-05 | 45 |
| fsh8sd8f | Ivy Hugh | 2010-10-23 | 2D | M_lgjg88 | fsh8sd8f | Maths | 2023-03-21 | 45 |
| fsh8sd8f | Ivy Hugh | 2010-10-23 | 2D | M_qas9ij | fsh8sd8f | Maths | 2023-05-13 | 79 |
There are several types of joins in SQL, including:
- INNER JOIN (example above): Returns only the matching rows from both tables based on the join condition.
- LEFT JOIN (or LEFT OUTER JOIN): Returns all rows from the left table and matching rows from the right table. If there is no match in the right table, the result contains NULL values for the right table's columns.
- RIGHT JOIN (or RIGHT OUTER JOIN): Returns all rows from the right table and matching rows from the left table. If there is no match in the left table, the result contains NULL values for the left table's columns.
- FULL OUTER JOIN (or FULL JOIN): Returns all rows from both tables, including non-matching rows. Non-matching columns are filled with NULL values.
- CROSS JOIN: Returns the Cartesian product of the two tables, combining every row of the first table with every row of the second table. It does not require a join condition.
- SELF JOIN: Joins a table with itself, allowing rows within the same table to be combined based on a related column.
Indexes and Constraints
Recall how the student's id was designated a PRIMARY KEY in Basic CRUD, referenced by the FOREIGN KEY in each test record.A primary key is an index in SQL. Defining a primary key on a table creates a unique index that enforces the primary key constraint. This index is used to speed up searches and queries that use the primary key column(s).
Defining a primary key on a table can potentially slow down writes, since it requires additional overhead to enforce the uniqueness constraint - the database engine must check each new record against the primary key index to ensure the key values are unique. This additional check can result in slower write performance, especially when inserting or updating large amounts of data.
However, the benefits of a primary key, such as improved read performance and data integrity, generally outweigh the potential impact on write performance.
To minimize the impact on write performance, consider the following best practices:
- Keep the primary key simple and concise, consisting of as few columns as possible.
- Avoid using a primary key that is frequently updated or changed.
- Use non-clustered indexes for other columns that are frequently searched or queried.
- Regularly monitor and optimize database performance to ensure it remains optimal.
Subquery
The result of a scalar (0 dimension), vector (1 dimension), or table (2 dimensions) "subquery" can be used within another query, ie. an inner SELECT statement nested within an outer SELECT statement. Subqueries can be nested repeatedly.SELECT * FROM Tests
WHERE subj='Maths' and score >
(SELECT AVG(score) FROM Tests GROUP BY subj HAVING subj='Maths');| test_id | student_id | subj | dt | score |
|---|---|---|---|---|
| M_sasgkj | hh09hhhj | Maths | 2023-01-05 | 87 |
| M_qas9ij | fsh8sd8f | Maths | 2023-05-13 | 79 |
See Subquery for a deeper treatment of subqueries.
CTE
A Common Table Expression (CTE) is a temporary result set that is predefined for use by the later parts of an SQL statement. It behaves like an ordinary table, as shown in the example below.See CTE for a deeper treatment of common table expressions, including recursive CTEs.
ch01-cte-example.sql:
WITH
best_scores AS (
SELECT student_id, subj, MAX(score) as max_score
FROM tests GROUP BY student_id, subj
)
SELECT fullname, subj, max_score FROM students JOIN best_scores ON
students.id=best_scores.student_id;| fullname | subj | max_score |
|---|---|---|
| Alex Phil | Maths | 87 |
| Mike Tudor | History | 99 |
| Ivy Hugh | Maths | 79 |