sql-expert
Skill6 starsChanged 8 months agoMITView on GitHub
Use this skill when writing, optimizing, or reviewing SQL queries, designing database schemas, or diagnosing slow query performance. Trigger phrases: 'write a SQL query', 'optimize this query', 'why is this slow', 'how do I join these tables'. Not for NoSQL databases or ORM-specific code generation.
5 other projects use a version of this.
Adopted by
Most recently taken up by
- SSameer20/data-analyst-toolkittheir own version, first seen Nov 8, 2026
- turkeryildirim/ai-skillstheir own version, first seen Nov 1, 2026
- paulopestanajunior/agents-configtheir own version, first seen Oct 15, 2026
- nek1987/auto-agent-harnesstheir own version, first seen Oct 11, 2026
- AutumnsGrove/ClaudeSkillstheir own version, first seen Oct 26, 2025
Other versions5 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 5
- AutumnsGrove/ClaudeSkills★ 30same name
- nek1987/auto-agent-harness★ 4same name
- SSameer20/data-analyst-toolkit★ 4same name
- turkeryildirim/ai-skills★ 4same name
- paulopestanajunior/agents-config★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository68 other files it gives its agents.
- dataset-curatorSkill
- eval-designerSkill
- model-comparatorSkill
- prompt-engineerSkill
- business-analystSkill
- competitor-analystSkill
- market-researcherSkill
- meeting-facilitatorSkill
- okr-plannerSkill
- pitch-deck-writerSkill
- product-managerSkill
- ux-researcherSkill
- api-designerSkill
- architecture-designerSkill
- code-reviewerSkill
- debuggerSkill
- documentation-writerSkill
- refactorerSkill
- regex-masterSkill
- security-auditorSkill
- test-writerSkill
- chart-builderSkill
- dashboard-designerSkill
- data-analystSkill
- data-cleanerSkill
- excel-expertSkill
- sql-analystSkill
- color-paletteSkill
- design-critiquerSkill
- frontend-designSkill
- ux-writerSkill
- ci-cd-helperSkill
- docker-expertSkill
- kubernetes-helperSkill
- monitoring-setupSkill
- flashcard-makerSkill
- lesson-plannerSkill
- quiz-creatorSkill
- tutorSkill
- docxSkill
- pdfSkill
- pptxSkill
- xlsxSkill
- budget-plannerSkill
- financial-analystSkill
- invoice-generatorSkill
- contract-reviewerSkill
- legal-summarizerSkill
- terms-of-serviceSkill
- decision-makerSkill
- habit-builderSkill
- journalingSkill
- note-takerSkill
- task-plannerSkill
- citation-formatterSkill
- fact-checkerSkill
- literature-reviewerSkill
- summarizerSkill
- web-researcherSkill
- academic-essaySkill
- The first 60 shown.
The file
Show its rules and text
We split this skill into the rules it gives an agent
20 rules. 0 are common, 11 are distinctive, and 9 are very specific to this project.
0
Common
Most of the 5 edited versions we read keep these.
11
Distinctive
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 47
Check column data types — comparing varchar to int causes implicit casts that break index usage.
- Distinctive: line 50
Start with the simplest correct query.
- Very specific: line 51
Use CTEs (WITH clauses) to break complex queries into named, readable steps.
- Distinctive: line 52
Verify the result against a small known dataset before running on production.
- Very specific: line 59
Look for Seq Scan on large tables — almost always means a missing index.
- Very specific: line 60
Look for Hash Join vs Nested Loop — hash joins are better for large datasets.
- Very specific: line 61
Check rows= estimates vs actual rows — large differences mean stale statistics (ANALYZE table_name).
- Very specific: line 65
Add an index on every foreign key and every column used in WHERE, JOIN ON, or ORDER BY.
- Very specific: line 66
Use composite indexes for queries that filter on multiple columns together: (status, created_at).
- Very specific: line 74
OR across columns: use UNION ALL instead for index friendliness.
- Distinctive: line 85
No repeating groups or arrays in columns.
- Distinctive: line 86
Every non-key column depends on the whole primary key (no partial dependency).
- Distinctive: line 87
Consider denormalization only for read-heavy, performance-critical paths.
- Distinctive: line 108
Fix: Use a range comparison:
- Very specific: line 116
Problem 3: No index on (status, created_at).
- Distinctive: line 251
Always use parameterized queries — never concatenate user input into SQL strings (SQL injection)
- Distinctive: line 254
Test queries on a subset of data before running on full production tables
- Distinctive: line 255
Use transactions for multi-statement writes to ensure atomicity
- Distinctive: line 256
Document complex queries with inline comments explaining the intent of each step
- Very specific: line 269
Use RETURNING id in INSERT/UPDATE to get the affected row's data without a second query
“Common” is measured: kept by at least 6 in 10 of the 5 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
SQL Expert
Overview
The SQL Expert skill covers writing efficient, correct SQL queries — from basic CRUD to advanced analytics using window functions, CTEs, and complex joins. It includes a systematic query optimization process (analyze → explain → index → rewrite), common anti-patterns to avoid, and guidance on aggregations, subqueries, and report-style queries. The examples use standard ANSI SQL with notes for PostgreSQL, MySQL, and SQLite dialect differences where relevant.
When to Use
- Writing SQL queries for data retrieval, aggregation, or reporting
- Optimizing a slow or resource-intensive query
- Designing a normalized database schema
- Understanding and using window functions or CTEs
- Identifying and fixing N+1 query patterns in application code
When NOT to Use
- MongoDB, DynamoDB, or other NoSQL query languages (different paradigm)
- ORM-specific query builders like SQLAlchemy DSL or ActiveRecord (use framework docs)
- Database administration tasks (backups, replication, user management)
- Full-text search configuration (Elasticsearch, pgvector, etc.)
Quick Reference
| Technique | When to Use |
EXPLAIN ANALYZE | Diagnose slow query; understand index usage |
| Index on filter column | WHERE col = ?, ORDER BY col, JOIN ON col |
| Composite index | Multiple columns in WHERE/ORDER BY together |
CTE (WITH) | Break complex queries into readable steps |
| Window function | Ranking, running totals, moving averages |
LATERAL JOIN | Correlated subquery per row (PostgreSQL) |
COALESCE(a, b) | Return first non-null value |
FILTER (WHERE ...) | Conditional aggregation without CASE |
DISTINCT ON | First row per group (PostgreSQL) |
| Partial index | Index only rows matching a WHERE condition |
Instructions
- Understand the data model
- Identify the relevant tables, their primary keys, and foreign key relationships.
- Know the cardinality: one-to-many, many-to-many (junction table needed).
- Check column data types — comparing varchar to int causes implicit casts that break index usage.
- Write a correct query first
- Start with the simplest correct query. Get the right answer before optimizing.
- Use CTEs (
WITHclauses) to break complex queries into named, readable steps. - Verify the result against a small known dataset before running on production.
- Analyze slow queries with EXPLAIN
EXPLAIN ANALYZE SELECT ...;- Look for
Seq Scanon large tables — almost always means a missing index. - Look for
Hash JoinvsNested Loop— hash joins are better for large datasets. - Check
rows=estimates vs actual rows — large differences mean stale statistics (ANALYZE table_name). - High
cost=numbers are relative — focus on the most expensive nodes.
- Look for
- Add indexes strategically
- Add an index on every foreign key and every column used in
WHERE,JOIN ON, orORDER BY. - Use composite indexes for queries that filter on multiple columns together:
(status, created_at). - Partial indexes for sparse conditions:
CREATE INDEX ON orders (user_id) WHERE status = 'pending'. - Too many indexes slow down writes — audit with
pg_stat_user_indexesfor unused indexes.
- Add an index on every foreign key and every column used in
- Avoid common anti-patterns
- N+1 queries: fetching child records in a loop. Solve with a JOIN or a single
IN (...)query. - SELECT *: fetches unused columns; prevents index-only scans.
- Functions on indexed columns in WHERE:
WHERE YEAR(created_at) = 2024breaks index use. Use range:WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01'. - OR across columns: use
UNION ALLinstead for index friendliness. - Implicit type coercion:
WHERE user_id = '42'whenuser_idis integer.
- N+1 queries: fetching child records in a loop. Solve with a JOIN or a single
- Use window functions for analytics
ROW_NUMBER(),RANK(),DENSE_RANK()for ranking within groups.SUM() OVER (PARTITION BY ... ORDER BY ...)for running totals.LAG()/LEAD()for comparing a row to the previous/next row.NTILE(n)for percentile buckets.
- Normalize schema to at least 3NF
- Each table represents one entity.
- No repeating groups or arrays in columns.
- Every non-key column depends on the whole primary key (no partial dependency).
- Consider denormalization only for read-heavy, performance-critical paths.
Examples
Example 1: Optimize a slow query
Input:
-- This query takes 8 seconds on a table with 5 million rows
SELECT *
FROM orders
WHERE YEAR(created_at) = 2024
AND status = 'completed'
ORDER BY created_at DESC;EXPLAIN output shows: Full table scan (Seq Scan), no indexes used.
Output (optimized):
Problem 1: YEAR(created_at) applies a function to the column, preventing index usage.
Fix: Use a range comparison:
WHERE created_at >= '2024-01-01'
AND created_at < '2025-01-01'Problem 2: SELECT * fetches all columns. Use only needed columns.
Problem 3: No index on (status, created_at).
Optimized query:
SELECT
id,
user_id,
total_amount,
status,
created_at
FROM orders
WHERE created_at >= '2024-01-01'
AND created_at < '2025-01-01'
AND status = 'completed'
ORDER BY created_at DESC;Required index:
-- Composite index: status first (equality), then created_at (range + sort)
CREATE INDEX idx_orders_status_created
ON orders (status, created_at DESC);Result: Query time drops from 8s to ~15ms.
Example 2: Write a complex report query with CTEs and window functions
Input: "Show me the top 3 products by revenue for each category, with their rank and percent of category revenue."
Schema:
products (id, name, category_id)
categories (id, name)
order_items (id, order_id, product_id, quantity, unit_price)Output:
WITH product_revenue AS (
-- Step 1: Calculate total revenue per product
SELECT
p.id AS product_id,
p.name AS product_name,
c.id AS category_id,
c.name AS category_name,
SUM(oi.quantity * oi.unit_price) AS revenue
FROM order_items oi
JOIN products p ON p.id = oi.product_id
JOIN categories c ON c.id = p.category_id
GROUP BY p.id, p.name, c.id, c.name
),
ranked AS (
-- Step 2: Rank products within each category and compute category share
SELECT
product_id,
product_name,
category_id,
category_name,
revenue,
RANK() OVER (
PARTITION BY category_id
ORDER BY revenue DESC
) AS rank_in_category,
ROUND(
100.0 * revenue / SUM(revenue) OVER (PARTITION BY category_id),
2
) AS pct_of_category
FROM product_revenue
)
-- Step 3: Filter to top 3 per category
SELECT
category_name,
rank_in_category,
product_name,
revenue,
pct_of_category
FROM ranked
WHERE rank_in_category <= 3
ORDER BY category_name, rank_in_category;Sample output:
category_name | rank | product_name | revenue | pct_of_category
--------------+------+-------------------+----------+----------------
Electronics | 1 | Wireless Headset | 125400.00| 34.21
Electronics | 2 | Laptop Stand | 98200.00| 26.80
Electronics | 3 | USB-C Hub | 76100.00| 20.77
Clothing | 1 | Winter Jacket | 89300.00| 41.12
...Example 3: Fix an N+1 query
Input (Python with ORM, causing N+1):
orders = Order.query.filter_by(status='completed').all()
for order in orders:
# This fires a separate query for EACH order — N+1!
user = User.query.get(order.user_id)
print(f"{user.email}: {order.total}")Output (single query with JOIN):
SELECT
o.id,
o.total,
o.created_at,
u.email,
u.name
FROM orders o
JOIN users u ON u.id = o.user_id
WHERE o.status = 'completed'
ORDER BY o.created_at DESC;Or using SQLAlchemy eager loading:
orders = (
Order.query
.options(joinedload(Order.user))
.filter_by(status='completed')
.all()
)
for order in orders:
print(f"{order.user.email}: {order.total}") # No extra queriesBest Practices
- Always use parameterized queries — never concatenate user input into SQL strings (SQL injection)
- Alias table names in multi-table queries:
orders o,users ufor readability - Format SQL with consistent capitalization: keywords UPPER, identifiers lower
- Test queries on a subset of data before running on full production tables
- Use transactions for multi-statement writes to ensure atomicity
- Document complex queries with inline comments explaining the intent of each step
Common Mistakes
- Forgetting
GROUP BYwhen using aggregate functions (returns wrong results or error) - Using
HAVINGwhenWHEREis correct (WHEREfilters before aggregation;HAVINGafter) - Joining on non-indexed columns, causing full table scans on both tables
- Using
NOT INwith a subquery that can return NULL (always returns zero rows — useNOT EXISTS) - Assuming
ORDER BYwithoutLIMITreturns results in a consistent order (it doesn't) - Running
UPDATEorDELETEwithout aWHEREclause in production
Tips & Tricks
EXPLAIN (ANALYZE, BUFFERS)in PostgreSQL shows cache hit vs disk read — crucial for identifying I/O bottleneckspg_stat_statementsextension tracks the slowest queries in production automatically- Use
RETURNING idinINSERT/UPDATEto get the affected row's data without a second query COPYcommand is orders of magnitude faster thanINSERTfor bulk data loadsGENERATE_SERIES()in PostgreSQL is excellent for filling date gaps in reports
Related Skills
- code-reviewer
- api-designer
- security-auditor
- architecture-designer
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

