Primer - SQL common mistakes
SQL Common Coding Mistakes Cheat Sheet
1. SQL Injection
- Never use raw input in queries: Use parameterized queries or prepared statements.
-- Bad (Vulnerable to SQL injection) SELECT * FROM users WHERE username = '" + user_input + "'; -- Good (Parameterized) SELECT * FROM users WHERE username = ?; -- (Prepared statement)
2. Missing Indexes
- Slow queries? Check if columns in
WHERE
,JOIN
,ORDER BY
are indexed.-- Add an index if frequently queried CREATE INDEX idx_username ON users(username);
- Avoid unnecessary indexes (slows down inserts/updates).
3. Implicit Type Conversion
- Comparing different types (e.g., string vs number) can cause full table scans.
-- Bad (If 'id' is VARCHAR but compared to a number) SELECT * FROM users WHERE id = 123; -- Good (Explicit type matching) SELECT * FROM users WHERE id = '123';
4. Cartesian Products (Cross Joins)
- Missing
JOIN
conditions lead to unintended huge results.-- Bad (Returns all combinations) SELECT * FROM users, orders; -- Good (Explicit JOIN) SELECT * FROM users JOIN orders ON users.id = orders.user_id;
5. NULL Handling
NULL
comparisons requireIS NULL
/IS NOT NULL
(not= NULL
).-- Bad (Doesn't work) SELECT * FROM users WHERE deleted_at = NULL; -- Good SELECT * FROM users WHERE deleted_at IS NULL;
- Aggregate functions (
COUNT
,SUM
) ignoreNULL
values.
6. GROUP BY Mistakes
- Non-aggregated columns in
SELECT
must be inGROUP BY
.-- Bad (May return arbitrary values) SELECT user_id, username, COUNT(*) FROM orders; -- Good SELECT user_id, username, COUNT(*) FROM orders GROUP BY user_id, username;
7. Subquery Performance
- Avoid
NOT IN
with NULLs (returns no rows if subquery containsNULL
).-- Bad (Fails silently if subquery has NULL) SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM orders); -- Better (Use NOT EXISTS) SELECT * FROM users WHERE NOT EXISTS (SELECT 1 FROM orders WHERE orders.user_id = users.id);
8. Transaction Errors
- Forgotten
COMMIT
/ROLLBACK
leads to locks or partial updates.BEGIN TRANSACTION; UPDATE accounts SET balance = balance - 100 WHERE user_id = 1; UPDATE accounts SET balance = balance + 100 WHERE user_id = 2; COMMIT; -- Or ROLLBACK if error occurs
9. Over-fetching Data
- Avoid
SELECT *
(fetch only needed columns).-- Bad (Unnecessary data transfer) SELECT * FROM users; -- Good SELECT id, username FROM users;
10. Date/Time Pitfalls
- Time zones matter! Store in UTC and convert on display.
-- Bad (Timezone-dependent) INSERT INTO logs (event_time) VALUES (NOW()); -- Good (Explicit UTC) INSERT INTO logs (event_time) VALUES (UTC_TIMESTAMP());
11. Case Sensitivity & Collation
LIKE
vs=
(case sensitivity depends on collation).-- May behave differently based on collation SELECT * FROM users WHERE username LIKE 'john%'; SELECT * FROM users WHERE username = 'John';
12. Deadlocks & Long-running Queries
- Avoid holding locks too long (optimize transactions).
- Use
EXPLAIN
to debug slow queries.
Debug Tools:
EXPLAIN QUERY PLAN
(SQLite) /EXPLAIN ANALYZE
(PostgreSQL)- Query profiling (
SET profiling = 1;
in MySQL)
Keep this handy to avoid costly SQL mistakes! ๐