These ten questions run the length of the chapter, and each turns on behavior that catches working developers out. Every snippet ran on MySQL 9.7.2 524 with its default sql_mode and collation (utf8mb4_0900_ai_ci), against a fresh copy of the chapter's shop database for each question, through the mysql client with --force, so a failing statement reports its error and the next statement still runs. Run nothing: write down exactly what each statement returns or does, and why. The answers, with the reasoning and the section each comes from, are in Appendix H.
Questions
-- 1. Categories 2-5 have no children. Why do these two counts differ?
SELECT COUNT(*) AS not_in FROM categories
WHERE id NOT IN (SELECT parent_id FROM categories);
SELECT COUNT(*) AS not_exists FROM categories c
WHERE NOT EXISTS (SELECT 1 FROM categories k WHERE k.parent_id = c.id);
SELECT COUNT(*) AS fixed FROM categories
WHERE id NOT IN (SELECT parent_id FROM categories WHERE parent_id IS NOT NULL);
SELECT NULL IN (1, NULL) AS a, 1 IN (1, NULL) AS b, 2 NOT IN (1, NULL) AS c;
-- 2. One of these three fails. Which, why is the first legal, and what does the third show?
SELECT c.id, c.name, COUNT(*) AS titles FROM products p
JOIN categories c ON c.id = p.category_id GROUP BY c.id;
SELECT c.name, p.title, MAX(p.price) FROM products p
JOIN categories c ON c.id = p.category_id GROUP BY c.name;
SELECT c.name, ANY_VALUE(p.title) AS a_title, MAX(p.price) AS top FROM products p
JOIN categories c ON c.id = p.category_id GROUP BY c.name ORDER BY c.name LIMIT 1;
-- 3. How many rows does t3 hold at the end, what is in them, and what does SHOW WARNINGS say?
CREATE TABLE t3 (code CHAR(3), qty TINYINT UNSIGNED);
INSERT INTO t3 VALUES ('ABCD', 1);
INSERT IGNORE INTO t3 VALUES ('ABCD', 300), ('XY', -5);
SHOW WARNINGS;
SELECT * FROM t3;-- 4. Five comparisons, then a lookup on a stored name of 'Ana Souza'.
SELECT 'café' = 'CAFE' AS accents, 'a' = 'a ' AS pad, 'ß' = 'ss' AS eszett,
'café' = 'CAFE' COLLATE utf8mb4_0900_as_cs AS as_cs, 'ß' LIKE 'ss' AS like_ss;
SELECT COUNT(*) FROM customers WHERE name = 'ANA SOUZA';
-- 5. Four window columns, two with no explicit frame. Fill in every value.
SELECT sku, category_id AS cat, stock,
SUM(stock) OVER (ORDER BY category_id) AS by_range,
SUM(stock) OVER (ORDER BY category_id, sku ROWS UNBOUNDED PRECEDING) AS by_rows,
LAST_VALUE(sku) OVER (ORDER BY category_id, sku) AS last_sku,
COUNT(*) OVER (PARTITION BY category_id) AS in_cat
FROM products WHERE category_id IN (2, 3) ORDER BY category_id, sku;
-- 6. BK-SQL-02 has attributes {"format": "ebook", "pages": 188}. What are a to f?
SELECT attributes->'$.format' AS a, attributes->>'$.format' AS b,
attributes->'$.format' = 'ebook' AS c, attributes->>'$.pages' + 1 AS d,
attributes->>'$.isbn' IS NULL AS e, JSON_TYPE(attributes->'$.pages') AS f
FROM products WHERE sku = 'BK-SQL-02';
SELECT JSON_EXTRACT('{"n": 1}', '$.n') = JSON_EXTRACT('{"n": 1.0}', '$.n') AS same;-- 7. Default isolation level. Product 1 starts with stock 25. Session B autocommits.
-- session A:
START TRANSACTION;
SELECT stock AS a1 FROM products WHERE id = 1;
-- session B:
UPDATE products SET stock = 99 WHERE id = 1;
-- session A again:
SELECT stock AS a2 FROM products WHERE id = 1;
UPDATE products SET stock = stock - 1 WHERE id = 1;
SELECT stock AS a3 FROM products WHERE id = 1;
COMMIT;
-- 8. Which of the four queries use the new index, and how?
CREATE INDEX idx_cat_price ON products (category_id, price);
EXPLAIN SELECT title FROM products WHERE category_id = 2 AND price > 40;
EXPLAIN SELECT title FROM products WHERE price > 40;
EXPLAIN SELECT title FROM products WHERE category_id + 0 = 2;
EXPLAIN SELECT title FROM products WHERE category_id = 2 ORDER BY price DESC LIMIT 1;-- 9. Customer 8 has no orders; product 3 appears in order 2. What is left in wishlist,
-- and what does the last DELETE report?
CREATE TABLE wishlist (customer_id INT UNSIGNED NULL, product_id INT UNSIGNED NULL,
FOREIGN KEY (customer_id) REFERENCES customers (id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE SET NULL);
INSERT INTO wishlist VALUES (7, 3), (8, 3), (8, 5);
DELETE FROM customers WHERE id = 8;
DELETE FROM products WHERE id = 3;
SELECT * FROM wishlist;
DELETE FROM customers WHERE id = 1;
-- 10. A PHP 5-era login check calls the first three. Which statements succeed on 9.7?
SELECT MD5('shop');
SELECT SHA1('shop');
SELECT LEFT(SHA2('shop', 256), 16) AS sha256, LENGTH(UNHEX(SHA2('shop', 256))) AS bytes;
SELECT PASSWORD('shop');
SET @u = '6ccd780c-baba-1026-9564-5b8c656024db';
SELECT LENGTH(UUID()) AS text_len, LENGTH(UUID_TO_BIN(UUID(), 1)) AS bin_len,
UUID_TO_BIN(@u, 1) = UUID_TO_BIN(@u) AS same;