| name | sql-master |
| description | Advanced SQL expertise including window functions, CTEs, recursive queries, query optimization with EXPLAIN plans, indexing strategies, pivot/unpivot operations, JSON operations, full-text search, stored procedures, and identification of performance anti-patterns across PostgreSQL, MySQL, and SQL Server.
Use when the user asks about sql master, sql master best practices, or needs guidance on sql master implementation.
Do NOT use when the user needs a different specialized skill or is asking about an unrelated technology domain.
|
| license | Apache-2.0 |
| metadata | {"author":"foundry-skills","version":"1.0.0","tags":"data-science sql guide","category":"data-engineering","subcategory":"pipelines-etl","depends":"","disclaimer":"none","difficulty":"advanced"} |
SQL Master
Overview
This skill provides deep expertise in advanced SQL techniques that separate production-grade database work from basic querying. It covers the full spectrum from analytical window functions through query optimization, enabling you to write SQL that is both correct and performant at scale.
Window Functions
Window functions operate over a set of rows related to the current row without collapsing the result set. They are essential for ranking, running totals, moving averages, and gap-and-island analysis.
Ranking Functions
SELECT
employee_id,
department,
salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_val,
DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dense_rank_val,
NTILE(4) OVER (PARTITION BY department ORDER BY salary DESC) AS quartile
FROM employees;
Offset Functions
SELECT
order_date,
revenue,
LAG(revenue, 1) OVER (ORDER BY order_date) AS prev_day_revenue,
LEAD(revenue, 1) OVER (ORDER BY order_date) AS next_day_revenue,
revenue - LAG(revenue, 1) OVER (ORDER BY order_date) AS day_over_day_change,
FIRST_VALUE(revenue) OVER (
PARTITION BY DATE_TRUNC('month', order_date)
ORDER BY order_date
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS first_day_of_month_revenue
FROM daily_revenue;
Frame Specifications
SELECT
trade_date,
close_price,
AVG(close_price) OVER (
ORDER BY trade_date
ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
) AS ma_7,
AVG(close_price) OVER (
ORDER BY trade_date
ROWS BETWEEN 29 PRECEDING AND CURRENT ROW
) AS ma_30,
# ... (condensed) ...
WHERE ticker = 'AAPL';
Common Table Expressions (CTEs)
Standard CTEs
WITH monthly_sales AS (
SELECT
DATE_TRUNC('month', order_date) AS month,
SUM(amount) AS total_sales
FROM orders
GROUP BY 1
),
monthly_growth AS (
SELECT
month,
total_sales,
LAG(total_sales) OVER (ORDER BY month) AS prev_month_sales,
ROUND(
(total_sales - LAG(total_sales) OVER (ORDER BY month))
/ LAG(total_sales) OVER (ORDER BY month) * 100, 2
) AS growth_pct
FROM monthly_sales
)
SELECT * FROM monthly_growth WHERE growth_pct < 0;
Recursive CTEs
WITH RECURSIVE org_tree AS (
SELECT
employee_id,
name,
manager_id,
1 AS depth,
ARRAY[employee_id] AS path,
name::TEXT AS hierarchy
FROM employees
WHERE manager_id IS NULL
UNION ALL
# ... (condensed) ...
SELECT dt + INTERVAL '1 day'
FROM date_series
WHERE dt < DATE '2024-12-31'
)
SELECT dt FROM date_series;
Gap and Island Analysis
WITH numbered AS (
SELECT
event_date,
event_date - (ROW_NUMBER() OVER (ORDER BY event_date))::INT * INTERVAL '1 day' AS grp
FROM events
),
islands AS (
SELECT
MIN(event_date) AS island_start,
MAX(event_date) AS island_end,
COUNT(*) AS island_length
FROM numbered
GROUP BY grp
)
SELECT * FROM islands ORDER BY island_start;
Query Optimization
Reading EXPLAIN Plans
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON)
SELECT * FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE o.order_date > '2024-01-01';
Join Strategy Selection (Internal Optimizer Logic)
| Join Type | Best When | Cost |
|---|
| Nested Loop | Small outer table, indexed inner | O(n * m) worst, O(n * log m) with index |
| Hash Join | No useful indexes, equality joins | O(n + m) but needs memory |
| Merge Join | Both inputs sorted or indexable | O(n + m) but needs sorting |
Statistics and Cardinality
ANALYZE table_name;
SELECT
schemaname, tablename, n_live_tup, n_dead_tup,
last_vacuum, last_autovacuum, last_analyze, last_autoanalyze
FROM pg_stat_user_tables;
CREATE STATISTICS stats_name (dependencies)
ON column_a, column_b FROM table_name;
Indexing Strategies
Index Type Decision Tree
- Equality lookups on single column -> B-tree (default)
- Range queries, ORDER BY -> B-tree
- Full-text search -> GIN on tsvector
- JSONB containment queries -> GIN
- Geometric/spatial data -> GiST or SP-GiST
- Low-cardinality columns -> BRIN (if physically correlated)
- Pattern matching (LIKE 'prefix%') -> B-tree with text_pattern_ops
- Pattern matching (LIKE '%middle%') -> GIN with pg_trgm
Composite Index Design
CREATE INDEX idx_orders_status_created_name
ON orders (status, created_at, name);
CREATE INDEX idx_orders_covering
ON orders (customer_id)
INCLUDE (order_date, total_amount);
CREATE INDEX idx_orders_active
ON orders (customer_id, order_date)
WHERE status = 'active';
CREATE INDEX idx_users_lower_email
ON users (LOWER(email));
Index Maintenance
SELECT
schemaname, tablename, indexname,
idx_scan AS times_used,
pg_size_pretty(pg_relation_size(indexrelid)) AS index_size
FROM pg_stat_user_indexes
WHERE idx_scan = 0
AND indexrelid NOT IN (SELECT conindid FROM pg_constraint)
ORDER BY pg_relation_size(indexrelid) DESC;
SELECT
schemaname, relname,
seq_scan, seq_tup_read,
idx_scan, idx_tup_fetch,
seq_tup_read / GREATEST(seq_scan, 1) AS avg_rows_per_seq_scan
FROM pg_stat_user_tables
WHERE seq_scan > 100
ORDER BY seq_tup_read DESC;
Pivot and Unpivot Operations
SELECT
department,
COUNT(*) FILTER (WHERE status = 'active') AS active_count,
COUNT(*) FILTER (WHERE status = 'inactive') AS inactive_count,
COUNT(*) FILTER (WHERE status = 'pending') AS pending_count
FROM employees
GROUP BY department;
SELECT
product_category,
SUM(CASE WHEN quarter = 'Q1' THEN revenue END) AS q1_revenue,
SUM(CASE WHEN quarter = 'Q2' THEN revenue END) AS q2_revenue,
# ... (condensed) ...
SELECT p.product_id, v.quarter, v.revenue
FROM quarterly_products p
CROSS JOIN LATERAL (
VALUES ('Q1', p.q1_rev), ('Q2', p.q2_rev), ('Q3', p.q3_rev), ('Q4', p.q4_rev)
) AS v(quarter, revenue);
JSON Operations
SELECT
data->>'name' AS name_text,
data->'address'->>'city' AS city,
data#>>'{address,zip}' AS zip_alt_syntax,
jsonb_array_length(data->'tags') AS tag_count
FROM users;
SELECT * FROM events
WHERE payload @> '{"type": "purchase"}'::jsonb;
# ... (condensed) ...
CROSS JOIN LATERAL jsonb_array_elements(o.items) AS item;
SELECT * FROM events
WHERE payload @? '$.items[*] ? (@.price > 100)';
Full-Text Search
ALTER TABLE articles ADD COLUMN search_vector tsvector;
UPDATE articles SET search_vector =
setweight(to_tsvector('english', COALESCE(title, '')), 'A') ||
setweight(to_tsvector('english', COALESCE(abstract, '')), 'B') ||
setweight(to_tsvector('english', COALESCE(body, '')), 'C');
CREATE INDEX idx_articles_fts ON articles USING GIN(search_vector);
CREATE TRIGGER articles_search_update
BEFORE INSERT OR UPDATE ON articles
FOR EACH ROW EXECUTE FUNCTION
# ... (condensed) ...
FROM articles,
to_tsquery('english', 'machine & learning & !supervised') AS query
WHERE search_vector @@ query
ORDER BY rank DESC
LIMIT 20;
Stored Procedures and Functions
CREATE OR REPLACE FUNCTION transfer_funds(
p_from_account BIGINT,
p_to_account BIGINT,
p_amount NUMERIC(15,2)
) RETURNS JSONB
LANGUAGE plpgsql
AS $$
DECLARE
v_from_balance NUMERIC(15,2);
v_result JSONB;
BEGIN
SELECT balance INTO v_from_balance
# ... (condensed) ...
'message', SQLERRM,
'code', SQLSTATE
);
END;
$$;
Performance Anti-Patterns
The Deadly Seven
- **SELECT ***: Fetches unnecessary columns, defeats covering indexes, increases I/O
- N+1 queries: Loop issuing one query per row instead of a single JOIN or IN clause
- Functions in WHERE on indexed columns:
WHERE YEAR(created_at) = 2024 cannot use index; use WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01'
- Implicit type conversions:
WHERE varchar_col = 12345 forces full scan; match types explicitly
- OR on different columns:
WHERE col_a = 1 OR col_b = 2 often forces sequential scan; rewrite as UNION ALL
- Correlated subqueries that could be joins: Executes subquery once per outer row
- Missing LIMIT on existence checks: Use
EXISTS(SELECT 1 ...) not COUNT(*) > 0
Query Rewriting Patterns
SELECT * FROM orders o
WHERE (SELECT MAX(order_date) FROM orders o2 WHERE o2.customer_id = o.customer_id) = o.order_date;
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date DESC) AS rn
FROM orders
) sub WHERE rn = 1;
SELECT * FROM customers c
WHERE (SELECT COUNT(*) FROM orders o WHERE o.customer_id = c.id) > 0;
# ... (condensed) ...
JOIN orders o ON c.id = o.customer_id;
SELECT c.* FROM customers c
WHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);
Advanced Techniques
GROUPING SETS, CUBE, and ROLLUP
SELECT
COALESCE(region, '(All Regions)') AS region,
COALESCE(product, '(All Products)') AS product,
SUM(revenue) AS total_revenue,
GROUPING(region) AS is_region_total,
GROUPING(product) AS is_product_total
FROM sales
GROUP BY GROUPING SETS (
(region, product),
(region),
(product),
()
)
ORDER BY GROUPING(region), GROUPING(product), region, product;
Materialized Views
CREATE MATERIALIZED VIEW mv_daily_metrics AS
SELECT
DATE_TRUNC('day', event_time) AS day,
event_type,
COUNT(*) AS event_count,
COUNT(DISTINCT user_id) AS unique_users,
AVG(duration_ms) AS avg_duration
FROM events
GROUP BY 1, 2
WITH DATA;
CREATE UNIQUE INDEX ON mv_daily_metrics (day, event_type);
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_daily_metrics;
Lateral Joins
SELECT c.customer_name, recent_orders.*
FROM customers c
CROSS JOIN LATERAL (
SELECT order_id, order_date, total_amount
FROM orders o
WHERE o.customer_id = c.id
ORDER BY order_date DESC
LIMIT 3
) AS recent_orders;
Decision Framework
When approaching a SQL problem:
- Correctness first: Write the logically correct query, then optimize
- Check the plan: Always run EXPLAIN ANALYZE before and after optimization
- Measure, do not guess: Use
pg_stat_statements or query store to find actual slow queries
- Index with purpose: Every index slows writes; ensure it serves real query patterns
- Denormalize deliberately: Only when read patterns demand it, and document why
- Test at scale: Queries that are fast on 1000 rows may be catastrophic on 10 million
When to Use
Use this skill when:
- Designing or implementing sql master solutions
- Reviewing or improving existing sql master approaches
- Making architectural or implementation decisions about sql master
- Learning sql master patterns and best practices
- Troubleshooting sql master-related issues
Do NOT use this skill when:
- The question is about a fundamentally different technology domain
- A more specific sibling skill covers the exact topic needed
- The user needs a complete hands-on tutorial rather than expert guidance
Output Format
# Sql Master Analysis
## Context Assessment
[Situation summary and constraints]
## Recommended Approach
[Primary recommendation with rationale]
## Implementation Steps
1. [Step with specific details]
2. [Step with specific details]
3. [Step with specific details]
## Trade-offs and Considerations
- [Key trade-off 1]
- [Key trade-off 2]
## Next Steps
- [Immediate action item]
- [Follow-up action item]
Example
Input: "Help me implement sql master for a medium-scale production application"
Output: A structured analysis covering current state assessment, recommended sql master approach with specific patterns, implementation roadmap with milestones, and risk mitigation strategies tailored to the application scale and constraints.
Edge Cases
- Legacy system integration: When sql master must coexist with legacy approaches, provide a gradual migration path rather than a complete rewrite
- Scale mismatch: When the solution complexity exceeds the project scale, recommend a simpler approach and note when to revisit
- Team skill gaps: When the team lacks experience with the recommended approach, include learning resources and simpler alternatives
- Conflicting requirements: When constraints conflict (e.g., performance vs. maintainability), explicitly state the trade-off and recommend based on stated priorities