How does ORDER BY decide the sort order, and what happens when two rows have the same sort value?
ORDER BY sorts the rows that survive the earlier stages of the query. You can sort by an expression, by an alias, by a column you did not project, or by an ordinal position. When several rows tie on the sort key, the order between them is unspecified — the engine is free to return them in any order it likes, and the order can differ between runs, between engines and between two versions of the same engine.
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name VARCHAR(120) NOT NULL,
category VARCHAR(60) NOT NULL,
unit_price DECIMAL(10, 2) NOT NULL
);
INSERT INTO products (id, name, category, unit_price) VALUES
(1, 'Mechanical Keyboard', 'peripherals', 79.50),
(2, 'USB-C Hub', 'peripherals', 32.00),
(3, '27-inch Monitor', 'displays', 249.99),
(4, 'Standing Desk', 'furniture', 419.00),
(5, 'Webcam 4K', 'peripherals', 129.00);
SELECT name, category, unit_price
FROM products
ORDER BY category, unit_price DESC;Five rows come back, sorted by category alphabetically, then by price descending inside each category: the 27-inch Monitor in displays, the Standing Desk in furniture, and then the three peripherals ordered as Mechanical Keyboard at 79.50, Webcam 4K at 129.00 and USB-C Hub at 32.00. The secondary key is what makes that last group deterministic — without it, those three rows would come back in an unspecified order.
That is the reason to always add a tiebreaker to an ORDER BY. Any query that feeds a paginated API or a report needs a total order, and a total order means every row must be distinguishable by the sort key. Adding id as a final key — ORDER BY category, unit_price DESC, id — makes the result reproducible and lets the engine use an index for the whole sort.
Two more details worth knowing. Sorting by a column that is not in the SELECT list is allowed, but it can defeat an index if the engine would otherwise have covered the scan from the index alone. And ORDER BY on a large result set is expensive: it forces a sort of every surviving row unless an index already provides the order, which is why an index on the sort key is one of the highest-value things you can add.