tribunal-kit 2.4.6 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/ARCHITECTURE.md +99 -99
- package/.agent/GEMINI.md +52 -52
- package/.agent/agents/accessibility-reviewer.md +139 -86
- package/.agent/agents/ai-code-reviewer.md +160 -90
- package/.agent/agents/backend-specialist.md +164 -127
- package/.agent/agents/code-archaeologist.md +115 -73
- package/.agent/agents/database-architect.md +130 -110
- package/.agent/agents/debugger.md +137 -97
- package/.agent/agents/dependency-reviewer.md +78 -30
- package/.agent/agents/devops-engineer.md +161 -118
- package/.agent/agents/documentation-writer.md +151 -87
- package/.agent/agents/explorer-agent.md +117 -99
- package/.agent/agents/frontend-reviewer.md +127 -47
- package/.agent/agents/frontend-specialist.md +169 -109
- package/.agent/agents/game-developer.md +28 -164
- package/.agent/agents/logic-reviewer.md +87 -49
- package/.agent/agents/mobile-developer.md +151 -103
- package/.agent/agents/mobile-reviewer.md +133 -50
- package/.agent/agents/orchestrator.md +121 -110
- package/.agent/agents/penetration-tester.md +103 -77
- package/.agent/agents/performance-optimizer.md +136 -92
- package/.agent/agents/performance-reviewer.md +139 -69
- package/.agent/agents/product-manager.md +104 -70
- package/.agent/agents/product-owner.md +6 -25
- package/.agent/agents/project-planner.md +95 -95
- package/.agent/agents/qa-automation-engineer.md +174 -87
- package/.agent/agents/security-auditor.md +133 -129
- package/.agent/agents/seo-specialist.md +160 -99
- package/.agent/agents/sql-reviewer.md +132 -44
- package/.agent/agents/supervisor-agent.md +137 -109
- package/.agent/agents/swarm-worker-contracts.md +17 -17
- package/.agent/agents/swarm-worker-registry.md +46 -46
- package/.agent/agents/test-coverage-reviewer.md +132 -53
- package/.agent/agents/test-engineer.md +0 -21
- package/.agent/agents/type-safety-reviewer.md +143 -33
- package/.agent/patterns/generator.md +9 -9
- package/.agent/patterns/inversion.md +12 -12
- package/.agent/patterns/pipeline.md +9 -9
- package/.agent/patterns/reviewer.md +13 -13
- package/.agent/patterns/tool-wrapper.md +9 -9
- package/.agent/rules/GEMINI.md +63 -63
- package/.agent/scripts/__pycache__/auto_preview.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/bundle_analyzer.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/checklist.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/dependency_analyzer.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/security_scan.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/session_manager.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/skill_integrator.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/swarm_dispatcher.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/test_runner.cpython-311.pyc +0 -0
- package/.agent/scripts/__pycache__/verify_all.cpython-311.pyc +0 -0
- package/.agent/scripts/compress_skills.py +167 -0
- package/.agent/scripts/consolidate_skills.py +173 -0
- package/.agent/scripts/deep_compress.py +202 -0
- package/.agent/scripts/minify_context.py +80 -0
- package/.agent/scripts/security_scan.py +1 -1
- package/.agent/scripts/strip_tribunal.py +41 -0
- package/.agent/skills/agent-organizer/SKILL.md +60 -100
- package/.agent/skills/agentic-patterns/SKILL.md +0 -70
- package/.agent/skills/ai-prompt-injection-defense/SKILL.md +108 -53
- package/.agent/skills/api-patterns/SKILL.md +197 -257
- package/.agent/skills/api-security-auditor/SKILL.md +125 -57
- package/.agent/skills/app-builder/SKILL.md +326 -50
- package/.agent/skills/app-builder/templates/SKILL.md +13 -15
- package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +16 -16
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +22 -22
- package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +18 -18
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +20 -20
- package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +17 -17
- package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +18 -18
- package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +21 -21
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +19 -19
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +26 -26
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +26 -26
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +19 -19
- package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +18 -18
- package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +20 -20
- package/.agent/skills/appflow-wireframe/SKILL.md +71 -98
- package/.agent/skills/architecture/SKILL.md +161 -200
- package/.agent/skills/authentication-best-practices/SKILL.md +121 -54
- package/.agent/skills/bash-linux/SKILL.md +71 -166
- package/.agent/skills/behavioral-modes/SKILL.md +8 -69
- package/.agent/skills/brainstorming/SKILL.md +345 -127
- package/.agent/skills/building-native-ui/SKILL.md +125 -57
- package/.agent/skills/clean-code/SKILL.md +266 -149
- package/.agent/skills/code-review-checklist/SKILL.md +0 -62
- package/.agent/skills/config-validator/SKILL.md +73 -131
- package/.agent/skills/csharp-developer/SKILL.md +434 -73
- package/.agent/skills/database-design/SKILL.md +190 -275
- package/.agent/skills/deployment-procedures/SKILL.md +81 -158
- package/.agent/skills/devops-engineer/SKILL.md +255 -94
- package/.agent/skills/devops-incident-responder/SKILL.md +50 -69
- package/.agent/skills/doc.md +5 -5
- package/.agent/skills/documentation-templates/SKILL.md +19 -63
- package/.agent/skills/edge-computing/SKILL.md +75 -165
- package/.agent/skills/extract-design-system/SKILL.md +84 -58
- package/.agent/skills/framer-motion-expert/SKILL.md +195 -0
- package/.agent/skills/frontend-design/SKILL.md +151 -499
- package/.agent/skills/game-design-expert/SKILL.md +71 -0
- package/.agent/skills/game-engineering-expert/SKILL.md +88 -0
- package/.agent/skills/geo-fundamentals/SKILL.md +52 -178
- package/.agent/skills/github-operations/SKILL.md +197 -272
- package/.agent/skills/gsap-expert/SKILL.md +194 -0
- package/.agent/skills/i18n-localization/SKILL.md +60 -172
- package/.agent/skills/intelligent-routing/SKILL.md +123 -103
- package/.agent/skills/lint-and-validate/SKILL.md +8 -52
- package/.agent/skills/llm-engineering/SKILL.md +281 -195
- package/.agent/skills/local-first/SKILL.md +76 -159
- package/.agent/skills/mcp-builder/SKILL.md +48 -188
- package/.agent/skills/mobile-design/SKILL.md +213 -219
- package/.agent/skills/motion-engineering/SKILL.md +184 -0
- package/.agent/skills/nextjs-react-expert/SKILL.md +184 -203
- package/.agent/skills/nodejs-best-practices/SKILL.md +403 -185
- package/.agent/skills/observability/SKILL.md +211 -203
- package/.agent/skills/parallel-agents/SKILL.md +53 -146
- package/.agent/skills/performance-profiling/SKILL.md +171 -151
- package/.agent/skills/plan-writing/SKILL.md +49 -153
- package/.agent/skills/platform-engineer/SKILL.md +57 -103
- package/.agent/skills/playwright-best-practices/SKILL.md +110 -63
- package/.agent/skills/powershell-windows/SKILL.md +61 -179
- package/.agent/skills/python-patterns/SKILL.md +7 -35
- package/.agent/skills/python-pro/SKILL.md +273 -114
- package/.agent/skills/react-specialist/SKILL.md +227 -108
- package/.agent/skills/readme-builder/SKILL.md +15 -85
- package/.agent/skills/realtime-patterns/SKILL.md +216 -243
- package/.agent/skills/red-team-tactics/SKILL.md +10 -51
- package/.agent/skills/rust-pro/SKILL.md +525 -142
- package/.agent/skills/seo-fundamentals/SKILL.md +92 -153
- package/.agent/skills/server-management/SKILL.md +110 -166
- package/.agent/skills/shadcn-ui-expert/SKILL.md +154 -55
- package/.agent/skills/skill-creator/SKILL.md +18 -58
- package/.agent/skills/sql-pro/SKILL.md +543 -68
- package/.agent/skills/supabase-postgres-best-practices/SKILL.md +28 -68
- package/.agent/skills/swiftui-expert/SKILL.md +124 -57
- package/.agent/skills/systematic-debugging/SKILL.md +49 -151
- package/.agent/skills/tailwind-patterns/SKILL.md +433 -149
- package/.agent/skills/tdd-workflow/SKILL.md +63 -169
- package/.agent/skills/test-result-analyzer/SKILL.md +33 -73
- package/.agent/skills/testing-patterns/SKILL.md +437 -130
- package/.agent/skills/trend-researcher/SKILL.md +30 -71
- package/.agent/skills/ui-ux-pro-max/SKILL.md +0 -41
- package/.agent/skills/ui-ux-researcher/SKILL.md +51 -91
- package/.agent/skills/vue-expert/SKILL.md +225 -119
- package/.agent/skills/vulnerability-scanner/SKILL.md +264 -226
- package/.agent/skills/web-accessibility-auditor/SKILL.md +141 -58
- package/.agent/skills/web-design-guidelines/SKILL.md +17 -61
- package/.agent/skills/webapp-testing/SKILL.md +71 -196
- package/.agent/skills/whimsy-injector/SKILL.md +58 -132
- package/.agent/skills/workflow-optimizer/SKILL.md +28 -68
- package/.agent/workflows/api-tester.md +96 -224
- package/.agent/workflows/audit.md +81 -122
- package/.agent/workflows/brainstorm.md +69 -105
- package/.agent/workflows/changelog.md +65 -97
- package/.agent/workflows/create.md +73 -88
- package/.agent/workflows/debug.md +80 -111
- package/.agent/workflows/deploy.md +119 -92
- package/.agent/workflows/enhance.md +80 -91
- package/.agent/workflows/fix.md +68 -97
- package/.agent/workflows/generate.md +165 -164
- package/.agent/workflows/migrate.md +106 -109
- package/.agent/workflows/orchestrate.md +103 -86
- package/.agent/workflows/performance-benchmarker.md +77 -268
- package/.agent/workflows/plan.md +120 -98
- package/.agent/workflows/preview.md +39 -96
- package/.agent/workflows/refactor.md +105 -97
- package/.agent/workflows/review-ai.md +63 -102
- package/.agent/workflows/review.md +71 -110
- package/.agent/workflows/session.md +53 -113
- package/.agent/workflows/status.md +42 -88
- package/.agent/workflows/strengthen-skills.md +90 -51
- package/.agent/workflows/swarm.md +114 -129
- package/.agent/workflows/test.md +125 -102
- package/.agent/workflows/tribunal-backend.md +60 -78
- package/.agent/workflows/tribunal-database.md +62 -100
- package/.agent/workflows/tribunal-frontend.md +62 -82
- package/.agent/workflows/tribunal-full.md +56 -100
- package/.agent/workflows/tribunal-mobile.md +65 -94
- package/.agent/workflows/tribunal-performance.md +62 -105
- package/.agent/workflows/ui-ux-pro-max.md +72 -121
- package/README.md +11 -15
- package/package.json +1 -1
- package/.agent/skills/api-patterns/api-style.md +0 -42
- package/.agent/skills/api-patterns/auth.md +0 -24
- package/.agent/skills/api-patterns/documentation.md +0 -26
- package/.agent/skills/api-patterns/graphql.md +0 -41
- package/.agent/skills/api-patterns/rate-limiting.md +0 -31
- package/.agent/skills/api-patterns/response.md +0 -37
- package/.agent/skills/api-patterns/rest.md +0 -40
- package/.agent/skills/api-patterns/security-testing.md +0 -122
- package/.agent/skills/api-patterns/trpc.md +0 -41
- package/.agent/skills/api-patterns/versioning.md +0 -22
- package/.agent/skills/app-builder/agent-coordination.md +0 -71
- package/.agent/skills/app-builder/feature-building.md +0 -53
- package/.agent/skills/app-builder/project-detection.md +0 -34
- package/.agent/skills/app-builder/scaffolding.md +0 -118
- package/.agent/skills/app-builder/tech-stack.md +0 -40
- package/.agent/skills/architecture/context-discovery.md +0 -43
- package/.agent/skills/architecture/examples.md +0 -94
- package/.agent/skills/architecture/pattern-selection.md +0 -68
- package/.agent/skills/architecture/patterns-reference.md +0 -50
- package/.agent/skills/architecture/trade-off-analysis.md +0 -77
- package/.agent/skills/brainstorming/dynamic-questioning.md +0 -360
- package/.agent/skills/database-design/database-selection.md +0 -43
- package/.agent/skills/database-design/indexing.md +0 -39
- package/.agent/skills/database-design/migrations.md +0 -48
- package/.agent/skills/database-design/optimization.md +0 -36
- package/.agent/skills/database-design/orm-selection.md +0 -30
- package/.agent/skills/database-design/schema-design.md +0 -56
- package/.agent/skills/dotnet-core-expert/SKILL.md +0 -103
- package/.agent/skills/framer-motion-animations/SKILL.md +0 -74
- package/.agent/skills/frontend-design/animation-guide.md +0 -331
- package/.agent/skills/frontend-design/color-system.md +0 -329
- package/.agent/skills/frontend-design/decision-trees.md +0 -418
- package/.agent/skills/frontend-design/motion-graphics.md +0 -306
- package/.agent/skills/frontend-design/typography-system.md +0 -363
- package/.agent/skills/frontend-design/ux-psychology.md +0 -1116
- package/.agent/skills/frontend-design/visual-effects.md +0 -383
- package/.agent/skills/game-development/2d-games/SKILL.md +0 -119
- package/.agent/skills/game-development/3d-games/SKILL.md +0 -135
- package/.agent/skills/game-development/SKILL.md +0 -236
- package/.agent/skills/game-development/game-art/SKILL.md +0 -185
- package/.agent/skills/game-development/game-audio/SKILL.md +0 -190
- package/.agent/skills/game-development/game-design/SKILL.md +0 -129
- package/.agent/skills/game-development/mobile-games/SKILL.md +0 -108
- package/.agent/skills/game-development/multiplayer/SKILL.md +0 -132
- package/.agent/skills/game-development/pc-games/SKILL.md +0 -144
- package/.agent/skills/game-development/vr-ar/SKILL.md +0 -123
- package/.agent/skills/game-development/web-games/SKILL.md +0 -150
- package/.agent/skills/intelligent-routing/router-manifest.md +0 -65
- package/.agent/skills/mobile-design/decision-trees.md +0 -516
- package/.agent/skills/mobile-design/mobile-backend.md +0 -491
- package/.agent/skills/mobile-design/mobile-color-system.md +0 -420
- package/.agent/skills/mobile-design/mobile-debugging.md +0 -122
- package/.agent/skills/mobile-design/mobile-design-thinking.md +0 -357
- package/.agent/skills/mobile-design/mobile-navigation.md +0 -458
- package/.agent/skills/mobile-design/mobile-performance.md +0 -767
- package/.agent/skills/mobile-design/mobile-testing.md +0 -356
- package/.agent/skills/mobile-design/mobile-typography.md +0 -433
- package/.agent/skills/mobile-design/platform-android.md +0 -666
- package/.agent/skills/mobile-design/platform-ios.md +0 -561
- package/.agent/skills/mobile-design/touch-psychology.md +0 -537
- package/.agent/skills/nextjs-react-expert/1-async-eliminating-waterfalls.md +0 -312
- package/.agent/skills/nextjs-react-expert/2-bundle-bundle-size-optimization.md +0 -240
- package/.agent/skills/nextjs-react-expert/3-server-server-side-performance.md +0 -490
- package/.agent/skills/nextjs-react-expert/4-client-client-side-data-fetching.md +0 -264
- package/.agent/skills/nextjs-react-expert/5-rerender-re-render-optimization.md +0 -581
- package/.agent/skills/nextjs-react-expert/6-rendering-rendering-performance.md +0 -432
- package/.agent/skills/nextjs-react-expert/7-js-javascript-performance.md +0 -684
- package/.agent/skills/nextjs-react-expert/8-advanced-advanced-patterns.md +0 -150
- package/.agent/skills/vulnerability-scanner/checklists.md +0 -121
|
@@ -1,104 +1,579 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sql-pro
|
|
3
|
-
description: Senior SQL developer across major databases (PostgreSQL, MySQL, SQL Server, Oracle).
|
|
3
|
+
description: Senior SQL developer across major databases (PostgreSQL, MySQL, SQL Server, Oracle). Complex query design with CTEs, window functions, PIVOT, recursive queries, JSON operations, full-text search, performance optimization with EXPLAIN ANALYZE, indexing strategies, partitioning, and schema architecture. Use when writing queries, designing schemas, optimizing performance, or debugging slow queries.
|
|
4
4
|
allowed-tools: Read, Write, Edit, Glob, Grep
|
|
5
|
-
version:
|
|
6
|
-
last-updated: 2026-03-
|
|
5
|
+
version: 2.0.0
|
|
6
|
+
last-updated: 2026-03-30
|
|
7
7
|
applies-to-model: gemini-2.5-pro, claude-3-7-sonnet
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
#
|
|
10
|
+
# SQL Pro — Advanced Query & Schema Mastery
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Common Table Expressions (CTEs)
|
|
15
|
+
|
|
16
|
+
### Basic CTE
|
|
17
|
+
|
|
18
|
+
```sql
|
|
19
|
+
-- CTE for readability and reuse
|
|
20
|
+
WITH active_users AS (
|
|
21
|
+
SELECT id, name, email, created_at
|
|
22
|
+
FROM users
|
|
23
|
+
WHERE is_active = true
|
|
24
|
+
AND last_login > CURRENT_DATE - INTERVAL '30 days'
|
|
25
|
+
),
|
|
26
|
+
user_orders AS (
|
|
27
|
+
SELECT user_id, COUNT(*) AS order_count, SUM(total) AS total_spent
|
|
28
|
+
FROM orders
|
|
29
|
+
WHERE status = 'completed'
|
|
30
|
+
GROUP BY user_id
|
|
31
|
+
)
|
|
32
|
+
SELECT
|
|
33
|
+
u.name,
|
|
34
|
+
u.email,
|
|
35
|
+
COALESCE(o.order_count, 0) AS orders,
|
|
36
|
+
COALESCE(o.total_spent, 0) AS revenue
|
|
37
|
+
FROM active_users u
|
|
38
|
+
LEFT JOIN user_orders o ON u.id = o.user_id
|
|
39
|
+
ORDER BY revenue DESC;
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Recursive CTE (Hierarchical Data)
|
|
43
|
+
|
|
44
|
+
```sql
|
|
45
|
+
-- Org chart: find all reports under a manager
|
|
46
|
+
WITH RECURSIVE org_tree AS (
|
|
47
|
+
-- Base case: the starting manager
|
|
48
|
+
SELECT id, name, manager_id, 1 AS depth
|
|
49
|
+
FROM employees
|
|
50
|
+
WHERE id = 42 -- starting point
|
|
51
|
+
|
|
52
|
+
UNION ALL
|
|
13
53
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
54
|
+
-- Recursive case: find direct reports
|
|
55
|
+
SELECT e.id, e.name, e.manager_id, t.depth + 1
|
|
56
|
+
FROM employees e
|
|
57
|
+
INNER JOIN org_tree t ON e.manager_id = t.id
|
|
58
|
+
WHERE t.depth < 10 -- safety limit to prevent infinite loops
|
|
59
|
+
)
|
|
60
|
+
SELECT * FROM org_tree ORDER BY depth, name;
|
|
61
|
+
|
|
62
|
+
-- ❌ HALLUCINATION TRAP: Always include a depth/cycle guard
|
|
63
|
+
-- Without it, circular references cause infinite recursion
|
|
64
|
+
-- PostgreSQL: use CYCLE detection clause (PG 14+)
|
|
65
|
+
-- SQL Server: use MAXRECURSION option
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### CTE for Running Totals & Pagination
|
|
69
|
+
|
|
70
|
+
```sql
|
|
71
|
+
-- Keyset pagination (faster than OFFSET for large tables)
|
|
72
|
+
WITH page AS (
|
|
73
|
+
SELECT id, name, created_at
|
|
74
|
+
FROM products
|
|
75
|
+
WHERE (created_at, id) < (:last_created_at, :last_id) -- cursor
|
|
76
|
+
ORDER BY created_at DESC, id DESC
|
|
77
|
+
LIMIT 20
|
|
78
|
+
)
|
|
79
|
+
SELECT * FROM page;
|
|
80
|
+
|
|
81
|
+
-- ❌ HALLUCINATION TRAP: OFFSET-based pagination gets slower with higher pages
|
|
82
|
+
-- OFFSET 100000, LIMIT 20 scans and discards 100,000 rows
|
|
83
|
+
-- Keyset pagination is O(1) regardless of page number
|
|
84
|
+
```
|
|
20
85
|
|
|
21
86
|
---
|
|
22
87
|
|
|
23
|
-
##
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
88
|
+
## Window Functions
|
|
89
|
+
|
|
90
|
+
### Ranking Functions
|
|
91
|
+
|
|
92
|
+
```sql
|
|
93
|
+
-- ROW_NUMBER: unique sequential number per partition
|
|
94
|
+
SELECT
|
|
95
|
+
department,
|
|
96
|
+
name,
|
|
97
|
+
salary,
|
|
98
|
+
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_in_dept
|
|
99
|
+
FROM employees;
|
|
100
|
+
|
|
101
|
+
-- RANK vs DENSE_RANK
|
|
102
|
+
-- RANK: 1, 2, 2, 4 (gaps after ties)
|
|
103
|
+
-- DENSE_RANK: 1, 2, 2, 3 (no gaps)
|
|
104
|
+
SELECT
|
|
105
|
+
name,
|
|
106
|
+
score,
|
|
107
|
+
RANK() OVER (ORDER BY score DESC) AS rank,
|
|
108
|
+
DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rank
|
|
109
|
+
FROM leaderboard;
|
|
110
|
+
|
|
111
|
+
-- NTILE: divide into N equal groups
|
|
112
|
+
SELECT
|
|
113
|
+
name,
|
|
114
|
+
revenue,
|
|
115
|
+
NTILE(4) OVER (ORDER BY revenue DESC) AS quartile
|
|
116
|
+
FROM companies;
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Aggregate Windows
|
|
120
|
+
|
|
121
|
+
```sql
|
|
122
|
+
-- Running total
|
|
123
|
+
SELECT
|
|
124
|
+
date,
|
|
125
|
+
amount,
|
|
126
|
+
SUM(amount) OVER (ORDER BY date) AS running_total,
|
|
127
|
+
AVG(amount) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS moving_avg_7d
|
|
128
|
+
FROM daily_revenue;
|
|
129
|
+
|
|
130
|
+
-- Percentage of total
|
|
131
|
+
SELECT
|
|
132
|
+
category,
|
|
133
|
+
revenue,
|
|
134
|
+
ROUND(100.0 * revenue / SUM(revenue) OVER (), 2) AS pct_of_total
|
|
135
|
+
FROM category_sales;
|
|
136
|
+
|
|
137
|
+
-- Difference from previous row
|
|
138
|
+
SELECT
|
|
139
|
+
month,
|
|
140
|
+
revenue,
|
|
141
|
+
revenue - LAG(revenue) OVER (ORDER BY month) AS mom_change,
|
|
142
|
+
ROUND(100.0 * (revenue - LAG(revenue) OVER (ORDER BY month))
|
|
143
|
+
/ NULLIF(LAG(revenue) OVER (ORDER BY month), 0), 2) AS mom_pct_change
|
|
144
|
+
FROM monthly_revenue;
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Frame Clauses
|
|
148
|
+
|
|
149
|
+
```sql
|
|
150
|
+
-- Frame clause controls which rows the window function sees
|
|
151
|
+
SUM(amount) OVER (
|
|
152
|
+
ORDER BY date
|
|
153
|
+
ROWS BETWEEN 2 PRECEDING AND CURRENT ROW -- last 3 rows (physical)
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
SUM(amount) OVER (
|
|
157
|
+
ORDER BY date
|
|
158
|
+
RANGE BETWEEN INTERVAL '7 days' PRECEDING AND CURRENT ROW -- last 7 days (logical)
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
-- ROWS vs RANGE:
|
|
162
|
+
-- ROWS = physical row count (exact)
|
|
163
|
+
-- RANGE = logical value range (handles ties differently)
|
|
164
|
+
|
|
165
|
+
-- ❌ HALLUCINATION TRAP: Default frame is RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
|
|
166
|
+
-- This means SUM() OVER (ORDER BY x) includes ALL preceding rows, not just "the one before"
|
|
167
|
+
-- To get a true running count of N rows, use ROWS BETWEEN explicitly
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Lead / Lag Analysis
|
|
171
|
+
|
|
172
|
+
```sql
|
|
173
|
+
-- Next and previous values
|
|
174
|
+
SELECT
|
|
175
|
+
event_date,
|
|
176
|
+
user_id,
|
|
177
|
+
LAG(event_date) OVER (PARTITION BY user_id ORDER BY event_date) AS prev_visit,
|
|
178
|
+
LEAD(event_date) OVER (PARTITION BY user_id ORDER BY event_date) AS next_visit,
|
|
179
|
+
event_date - LAG(event_date) OVER (PARTITION BY user_id ORDER BY event_date) AS days_between
|
|
180
|
+
FROM user_events;
|
|
181
|
+
|
|
182
|
+
-- FIRST_VALUE / LAST_VALUE
|
|
183
|
+
SELECT
|
|
184
|
+
department,
|
|
185
|
+
name,
|
|
186
|
+
salary,
|
|
187
|
+
FIRST_VALUE(name) OVER (PARTITION BY department ORDER BY salary DESC) AS highest_paid,
|
|
188
|
+
LAST_VALUE(name) OVER (
|
|
189
|
+
PARTITION BY department ORDER BY salary DESC
|
|
190
|
+
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING -- ⚠️ required!
|
|
191
|
+
) AS lowest_paid
|
|
192
|
+
FROM employees;
|
|
193
|
+
|
|
194
|
+
-- ❌ HALLUCINATION TRAP: LAST_VALUE without explicit frame clause returns CURRENT ROW
|
|
195
|
+
-- You MUST specify ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
|
|
196
|
+
```
|
|
32
197
|
|
|
33
198
|
---
|
|
34
199
|
|
|
35
|
-
##
|
|
200
|
+
## PIVOT / UNPIVOT / Conditional Aggregation
|
|
36
201
|
|
|
37
|
-
###
|
|
38
|
-
* Common Table Expressions (CTEs), Recursive CTEs.
|
|
39
|
-
* Window functions: Ranking functions (`ROW_NUMBER`, `RANK`), Aggregate windows, Lead/lag analysis, Frame clause optimization.
|
|
40
|
-
* PIVOT/UNPIVOT operations, Hierarchical queries, Temporal queries.
|
|
202
|
+
### PostgreSQL / Standard SQL (Conditional Aggregation)
|
|
41
203
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
204
|
+
```sql
|
|
205
|
+
-- PostgreSQL doesn't have PIVOT — use conditional aggregation
|
|
206
|
+
SELECT
|
|
207
|
+
product_name,
|
|
208
|
+
SUM(CASE WHEN quarter = 'Q1' THEN revenue ELSE 0 END) AS q1,
|
|
209
|
+
SUM(CASE WHEN quarter = 'Q2' THEN revenue ELSE 0 END) AS q2,
|
|
210
|
+
SUM(CASE WHEN quarter = 'Q3' THEN revenue ELSE 0 END) AS q3,
|
|
211
|
+
SUM(CASE WHEN quarter = 'Q4' THEN revenue ELSE 0 END) AS q4,
|
|
212
|
+
SUM(revenue) AS total
|
|
213
|
+
FROM quarterly_sales
|
|
214
|
+
GROUP BY product_name
|
|
215
|
+
ORDER BY total DESC;
|
|
46
216
|
|
|
47
|
-
|
|
48
|
-
*
|
|
49
|
-
|
|
50
|
-
|
|
217
|
+
-- PostgreSQL crosstab (requires tablefunc extension)
|
|
218
|
+
SELECT * FROM crosstab(
|
|
219
|
+
'SELECT product, quarter, revenue FROM sales ORDER BY 1, 2',
|
|
220
|
+
'SELECT DISTINCT quarter FROM sales ORDER BY 1'
|
|
221
|
+
) AS ct(product TEXT, q1 NUMERIC, q2 NUMERIC, q3 NUMERIC, q4 NUMERIC);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### SQL Server PIVOT
|
|
51
225
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
*
|
|
55
|
-
|
|
226
|
+
```sql
|
|
227
|
+
-- SQL Server native PIVOT
|
|
228
|
+
SELECT *
|
|
229
|
+
FROM (
|
|
230
|
+
SELECT product_name, quarter, revenue
|
|
231
|
+
FROM quarterly_sales
|
|
232
|
+
) AS source
|
|
233
|
+
PIVOT (
|
|
234
|
+
SUM(revenue)
|
|
235
|
+
FOR quarter IN ([Q1], [Q2], [Q3], [Q4])
|
|
236
|
+
) AS pivoted;
|
|
237
|
+
```
|
|
56
238
|
|
|
57
239
|
---
|
|
58
240
|
|
|
59
|
-
##
|
|
241
|
+
## JSON Operations
|
|
60
242
|
|
|
61
|
-
|
|
243
|
+
### PostgreSQL JSONB
|
|
62
244
|
|
|
245
|
+
```sql
|
|
246
|
+
-- Query JSON fields
|
|
247
|
+
SELECT
|
|
248
|
+
id,
|
|
249
|
+
profile->>'name' AS name, -- text extraction
|
|
250
|
+
profile->'address'->>'city' AS city, -- nested extraction
|
|
251
|
+
(profile->>'age')::int AS age -- cast to int
|
|
252
|
+
FROM users
|
|
253
|
+
WHERE profile->>'country' = 'US'
|
|
254
|
+
AND (profile->>'age')::int >= 18;
|
|
255
|
+
|
|
256
|
+
-- JSONB containment
|
|
257
|
+
SELECT * FROM products
|
|
258
|
+
WHERE metadata @> '{"category": "electronics"}'; -- contains
|
|
259
|
+
|
|
260
|
+
-- JSONB existence
|
|
261
|
+
SELECT * FROM products
|
|
262
|
+
WHERE metadata ? 'warranty'; -- key exists
|
|
263
|
+
|
|
264
|
+
-- JSONB array queries
|
|
265
|
+
SELECT * FROM users
|
|
266
|
+
WHERE profile->'tags' ? 'premium'; -- array contains value
|
|
267
|
+
|
|
268
|
+
-- Update JSONB
|
|
269
|
+
UPDATE users
|
|
270
|
+
SET profile = jsonb_set(profile, '{address,city}', '"New York"')
|
|
271
|
+
WHERE id = 1;
|
|
272
|
+
|
|
273
|
+
-- JSONB aggregation
|
|
274
|
+
SELECT jsonb_agg(jsonb_build_object('id', id, 'name', name)) AS users_json
|
|
275
|
+
FROM users
|
|
276
|
+
WHERE is_active = true;
|
|
277
|
+
|
|
278
|
+
-- ❌ HALLUCINATION TRAP: -> returns JSON, ->> returns TEXT
|
|
279
|
+
-- Filtering on -> requires JSON comparison
|
|
280
|
+
-- Filtering on ->> allows string comparison
|
|
281
|
+
-- Always cast ->> results when comparing numbers: (col->>'age')::int
|
|
63
282
|
```
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Indexing Strategy
|
|
287
|
+
|
|
288
|
+
### Index Types
|
|
289
|
+
|
|
290
|
+
```sql
|
|
291
|
+
-- B-tree (default — good for equality and range)
|
|
292
|
+
CREATE INDEX idx_users_email ON users (email);
|
|
293
|
+
|
|
294
|
+
-- Composite index (column order matters!)
|
|
295
|
+
CREATE INDEX idx_orders_user_date ON orders (user_id, created_at DESC);
|
|
296
|
+
-- ✅ Supports: WHERE user_id = 1 AND created_at > '2024-01-01'
|
|
297
|
+
-- ✅ Supports: WHERE user_id = 1 (uses leftmost prefix)
|
|
298
|
+
-- ❌ Does NOT support: WHERE created_at > '2024-01-01' (skips first column)
|
|
299
|
+
|
|
300
|
+
-- Partial / Filtered index (index only matching rows)
|
|
301
|
+
CREATE INDEX idx_active_users ON users (email) WHERE is_active = true;
|
|
302
|
+
-- Smaller index, faster queries when filtering by is_active
|
|
303
|
+
|
|
304
|
+
-- Covering index (INCLUDE — avoids table lookup)
|
|
305
|
+
CREATE INDEX idx_orders_covering ON orders (user_id)
|
|
306
|
+
INCLUDE (total, status, created_at);
|
|
307
|
+
-- All needed columns in the index = index-only scan
|
|
308
|
+
|
|
309
|
+
-- GIN index (for JSONB, arrays, full-text search)
|
|
310
|
+
CREATE INDEX idx_products_metadata ON products USING gin (metadata);
|
|
311
|
+
|
|
312
|
+
-- GiST index (for geometric, range, full-text)
|
|
313
|
+
CREATE INDEX idx_locations_geo ON locations USING gist (coordinates);
|
|
314
|
+
|
|
315
|
+
-- BRIN index (for naturally ordered data like timestamps)
|
|
316
|
+
CREATE INDEX idx_logs_timestamp ON logs USING brin (created_at);
|
|
317
|
+
-- Tiny index, perfect for append-only tables with timestamp ordering
|
|
72
318
|
```
|
|
73
319
|
|
|
320
|
+
### SARGability
|
|
321
|
+
|
|
322
|
+
```sql
|
|
323
|
+
-- SARGable = Search ARGument ABLE — can the query use an index?
|
|
324
|
+
|
|
325
|
+
-- ✅ SARGable (index seekable)
|
|
326
|
+
WHERE created_at >= '2024-01-01'
|
|
327
|
+
WHERE email = 'alice@test.com'
|
|
328
|
+
WHERE name LIKE 'Ali%' -- prefix match
|
|
329
|
+
|
|
330
|
+
-- ❌ NOT SARGable (forces full table scan)
|
|
331
|
+
WHERE YEAR(created_at) = 2024 -- function on column
|
|
332
|
+
WHERE LOWER(email) = 'alice@test.com' -- function on column
|
|
333
|
+
WHERE name LIKE '%alice%' -- leading wildcard
|
|
334
|
+
WHERE amount + tax > 100 -- expression on column
|
|
335
|
+
WHERE COALESCE(name, '') = '' -- function on column
|
|
336
|
+
|
|
337
|
+
-- ✅ Fix: functional index (PostgreSQL)
|
|
338
|
+
CREATE INDEX idx_users_email_lower ON users (LOWER(email));
|
|
339
|
+
-- Now WHERE LOWER(email) = 'alice@test.com' IS SARGable
|
|
340
|
+
|
|
341
|
+
-- ✅ Fix: computed column (SQL Server)
|
|
342
|
+
ALTER TABLE users ADD email_lower AS LOWER(email) PERSISTED;
|
|
343
|
+
CREATE INDEX idx_email_lower ON users (email_lower);
|
|
344
|
+
|
|
345
|
+
-- ❌ HALLUCINATION TRAP: Implicit type conversions destroy SARGability
|
|
346
|
+
-- WHERE varchar_column = 123 ← implicit cast on EVERY row
|
|
347
|
+
-- WHERE varchar_column = '123' ← direct comparison, uses index
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## EXPLAIN ANALYZE (Query Optimization)
|
|
353
|
+
|
|
354
|
+
```sql
|
|
355
|
+
-- PostgreSQL
|
|
356
|
+
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
|
|
357
|
+
SELECT * FROM orders WHERE user_id = 42 AND status = 'completed';
|
|
358
|
+
|
|
359
|
+
-- Reading the output:
|
|
360
|
+
-- Seq Scan → full table scan (usually bad for large tables)
|
|
361
|
+
-- Index Scan → using an index to find rows (good)
|
|
362
|
+
-- Index Only Scan → all data from index, no table access (best)
|
|
363
|
+
-- Bitmap Scan → index + bitmap for multiple conditions (good for moderate selectivity)
|
|
364
|
+
-- Hash Join → building hash table for join (good for large joins)
|
|
365
|
+
-- Nested Loop → for each row in A, scan B (good for small datasets, bad for large)
|
|
366
|
+
-- Sort → explicit sorting (check if index can avoid this)
|
|
367
|
+
|
|
368
|
+
-- Key metrics:
|
|
369
|
+
-- actual time=X..Y → X = time to first row, Y = time to all rows (ms)
|
|
370
|
+
-- rows=N → actual rows returned
|
|
371
|
+
-- loops=N → number of times this node executed
|
|
372
|
+
-- Buffers: shared hit=N → pages read from cache (good)
|
|
373
|
+
-- Buffers: shared read=N → pages read from disk (measure of I/O cost)
|
|
374
|
+
|
|
375
|
+
-- SQL Server
|
|
376
|
+
SET STATISTICS IO ON;
|
|
377
|
+
SET STATISTICS TIME ON;
|
|
378
|
+
SELECT * FROM orders WHERE user_id = 42;
|
|
379
|
+
-- Check: logical reads (from cache), physical reads (from disk)
|
|
380
|
+
|
|
381
|
+
-- ❌ HALLUCINATION TRAP: EXPLAIN without ANALYZE shows estimates, NOT actuals
|
|
382
|
+
-- Always use EXPLAIN ANALYZE for real performance data
|
|
383
|
+
-- But CAREFUL: ANALYZE actually EXECUTES the query
|
|
384
|
+
-- For destructive queries (DELETE, UPDATE), wrap in a transaction:
|
|
385
|
+
BEGIN;
|
|
386
|
+
EXPLAIN ANALYZE DELETE FROM users WHERE id = 1;
|
|
387
|
+
ROLLBACK; -- prevents actual deletion
|
|
388
|
+
```
|
|
74
389
|
|
|
75
390
|
---
|
|
76
391
|
|
|
77
|
-
##
|
|
392
|
+
## Table Partitioning
|
|
393
|
+
|
|
394
|
+
```sql
|
|
395
|
+
-- PostgreSQL range partitioning (ideal for time-series data)
|
|
396
|
+
CREATE TABLE events (
|
|
397
|
+
id BIGSERIAL,
|
|
398
|
+
event_type TEXT NOT NULL,
|
|
399
|
+
payload JSONB,
|
|
400
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
401
|
+
) PARTITION BY RANGE (created_at);
|
|
78
402
|
|
|
79
|
-
|
|
80
|
-
|
|
403
|
+
-- Create monthly partitions
|
|
404
|
+
CREATE TABLE events_2024_01 PARTITION OF events
|
|
405
|
+
FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
|
|
406
|
+
CREATE TABLE events_2024_02 PARTITION OF events
|
|
407
|
+
FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');
|
|
81
408
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
3. **Cursor Loops** — avoid procedural `WHILE`/cursor loops where a set-based operation (JOIN or Window Function) will suffice.
|
|
86
|
-
4. **Missing Indexes for Foreign Keys** — always ensure relationships are backed by efficient indexing.
|
|
87
|
-
5. **Implicit Conversions** — avoid joining/filtering on mismatched data types which prevents Index Seeks (SARGability).
|
|
409
|
+
-- Queries automatically prune partitions:
|
|
410
|
+
-- SELECT * FROM events WHERE created_at >= '2024-02-01'
|
|
411
|
+
-- Only scans events_2024_02 and later — skips events_2024_01 entirely
|
|
88
412
|
|
|
89
|
-
|
|
413
|
+
-- List partitioning (for categorical data)
|
|
414
|
+
CREATE TABLE orders (
|
|
415
|
+
id SERIAL,
|
|
416
|
+
region TEXT NOT NULL,
|
|
417
|
+
total NUMERIC
|
|
418
|
+
) PARTITION BY LIST (region);
|
|
90
419
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
✅ Is the query SARGable (Search-Argument-Able) to leverage existing indexes?
|
|
95
|
-
✅ Did I replace correlated subqueries with robust `JOIN`s or `APPLY`/`LATERAL` clauses?
|
|
96
|
-
✅ Are there any procedural loops that could be written as a set-based approach?
|
|
97
|
-
✅ Did I parameterize all data inputs to prevent SQL Injection?
|
|
420
|
+
CREATE TABLE orders_us PARTITION OF orders FOR VALUES IN ('US');
|
|
421
|
+
CREATE TABLE orders_eu PARTITION OF orders FOR VALUES IN ('EU', 'UK');
|
|
422
|
+
CREATE TABLE orders_apac PARTITION OF orders FOR VALUES IN ('JP', 'KR', 'AU');
|
|
98
423
|
```
|
|
99
424
|
|
|
100
|
-
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## Transactions & Concurrency
|
|
428
|
+
|
|
429
|
+
```sql
|
|
430
|
+
-- Proper transaction pattern
|
|
431
|
+
BEGIN;
|
|
432
|
+
|
|
433
|
+
-- Lock the row for update (prevents concurrent modification)
|
|
434
|
+
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
|
|
435
|
+
|
|
436
|
+
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
|
|
437
|
+
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
|
|
438
|
+
|
|
439
|
+
-- Verify consistency
|
|
440
|
+
DO $$
|
|
441
|
+
BEGIN
|
|
442
|
+
IF (SELECT SUM(balance) FROM accounts) <> 10000 THEN
|
|
443
|
+
RAISE EXCEPTION 'Balance integrity violation';
|
|
444
|
+
END IF;
|
|
445
|
+
END $$;
|
|
446
|
+
|
|
447
|
+
COMMIT;
|
|
448
|
+
|
|
449
|
+
-- Isolation levels (ordered by strictness)
|
|
450
|
+
SET TRANSACTION ISOLATION LEVEL READ COMMITTED; -- default (PostgreSQL)
|
|
451
|
+
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; -- snapshot isolation
|
|
452
|
+
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- strictest (may abort)
|
|
453
|
+
|
|
454
|
+
-- Advisory locks (application-level locking)
|
|
455
|
+
SELECT pg_advisory_lock(12345); -- acquire
|
|
456
|
+
-- ... do work ...
|
|
457
|
+
SELECT pg_advisory_unlock(12345); -- release
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## MERGE / UPSERT
|
|
463
|
+
|
|
464
|
+
```sql
|
|
465
|
+
-- PostgreSQL UPSERT (ON CONFLICT)
|
|
466
|
+
INSERT INTO products (sku, name, price, updated_at)
|
|
467
|
+
VALUES ('ABC-123', 'Widget', 29.99, NOW())
|
|
468
|
+
ON CONFLICT (sku) DO UPDATE SET
|
|
469
|
+
name = EXCLUDED.name,
|
|
470
|
+
price = EXCLUDED.price,
|
|
471
|
+
updated_at = EXCLUDED.updated_at;
|
|
472
|
+
|
|
473
|
+
-- SQL Server MERGE
|
|
474
|
+
MERGE INTO products AS target
|
|
475
|
+
USING staging_products AS source
|
|
476
|
+
ON target.sku = source.sku
|
|
477
|
+
WHEN MATCHED THEN
|
|
478
|
+
UPDATE SET
|
|
479
|
+
name = source.name,
|
|
480
|
+
price = source.price,
|
|
481
|
+
updated_at = GETDATE()
|
|
482
|
+
WHEN NOT MATCHED THEN
|
|
483
|
+
INSERT (sku, name, price, created_at)
|
|
484
|
+
VALUES (source.sku, source.name, source.price, GETDATE());
|
|
485
|
+
|
|
486
|
+
-- ❌ HALLUCINATION TRAP: PostgreSQL uses ON CONFLICT, not MERGE
|
|
487
|
+
-- MERGE was added in PostgreSQL 15+ but ON CONFLICT is idiomatic
|
|
488
|
+
-- SQL Server uses MERGE — do not confuse the two syntaxes
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
---
|
|
101
492
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
493
|
+
## Full-Text Search (PostgreSQL)
|
|
494
|
+
|
|
495
|
+
```sql
|
|
496
|
+
-- Create tsvector column and GIN index
|
|
497
|
+
ALTER TABLE articles ADD COLUMN search_vector tsvector;
|
|
498
|
+
|
|
499
|
+
UPDATE articles SET search_vector =
|
|
500
|
+
setweight(to_tsvector('english', COALESCE(title, '')), 'A') ||
|
|
501
|
+
setweight(to_tsvector('english', COALESCE(body, '')), 'B');
|
|
502
|
+
|
|
503
|
+
CREATE INDEX idx_articles_search ON articles USING gin (search_vector);
|
|
504
|
+
|
|
505
|
+
-- Search with ranking
|
|
506
|
+
SELECT
|
|
507
|
+
title,
|
|
508
|
+
ts_rank(search_vector, query) AS rank
|
|
509
|
+
FROM articles, to_tsquery('english', 'database & optimization') AS query
|
|
510
|
+
WHERE search_vector @@ query
|
|
511
|
+
ORDER BY rank DESC
|
|
512
|
+
LIMIT 20;
|
|
513
|
+
|
|
514
|
+
-- Trigger to auto-update search vector
|
|
515
|
+
CREATE FUNCTION update_search_vector() RETURNS trigger AS $$
|
|
516
|
+
BEGIN
|
|
517
|
+
NEW.search_vector :=
|
|
518
|
+
setweight(to_tsvector('english', COALESCE(NEW.title, '')), 'A') ||
|
|
519
|
+
setweight(to_tsvector('english', COALESCE(NEW.body, '')), 'B');
|
|
520
|
+
RETURN NEW;
|
|
521
|
+
END $$ LANGUAGE plpgsql;
|
|
522
|
+
|
|
523
|
+
CREATE TRIGGER trg_articles_search
|
|
524
|
+
BEFORE INSERT OR UPDATE OF title, body ON articles
|
|
525
|
+
FOR EACH ROW EXECUTE FUNCTION update_search_vector();
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
## Security
|
|
531
|
+
|
|
532
|
+
```sql
|
|
533
|
+
-- ✅ ALWAYS use parameterized queries
|
|
534
|
+
-- PostgreSQL (via psycopg)
|
|
535
|
+
cursor.execute("SELECT * FROM users WHERE email = %s", (email,))
|
|
536
|
+
|
|
537
|
+
-- Python SQLAlchemy
|
|
538
|
+
stmt = select(User).where(User.email == email)
|
|
539
|
+
|
|
540
|
+
-- ❌ NEVER: String interpolation for SQL
|
|
541
|
+
-- ❌ f"SELECT * FROM users WHERE email = '{email}'"
|
|
542
|
+
-- ❌ "SELECT * FROM users WHERE email = '" + email + "'"
|
|
543
|
+
-- These allow SQL injection: email = "'; DROP TABLE users; --"
|
|
544
|
+
|
|
545
|
+
-- Row-Level Security (PostgreSQL)
|
|
546
|
+
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
|
|
547
|
+
|
|
548
|
+
CREATE POLICY documents_owner_policy ON documents
|
|
549
|
+
USING (owner_id = current_setting('app.current_user_id')::int);
|
|
550
|
+
|
|
551
|
+
-- Grant minimum permissions
|
|
552
|
+
GRANT SELECT, INSERT ON users TO app_role;
|
|
553
|
+
-- ❌ NEVER: GRANT ALL ON DATABASE TO app_role
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
558
|
+
## Output Format
|
|
559
|
+
|
|
560
|
+
When this skill produces or reviews code, structure your output as follows:
|
|
561
|
+
|
|
562
|
+
```
|
|
563
|
+
━━━ SQL Pro Report ━━━━━━━━━━━━━━━━━━━━━━━━
|
|
564
|
+
Skill: SQL Pro
|
|
565
|
+
Database: [PostgreSQL/MySQL/SQL Server/Oracle]
|
|
566
|
+
Scope: [N queries · N tables]
|
|
567
|
+
─────────────────────────────────────────────────
|
|
568
|
+
✅ Passed: [checks that passed, or "All clean"]
|
|
569
|
+
⚠️ Warnings: [non-blocking issues, or "None"]
|
|
570
|
+
❌ Blocked: [blocking issues requiring fix, or "None"]
|
|
571
|
+
─────────────────────────────────────────────────
|
|
572
|
+
VBC status: PENDING → VERIFIED
|
|
573
|
+
Evidence: [EXPLAIN ANALYZE output / migration success / test pass]
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
**VBC (Verification-Before-Completion) is mandatory.**
|
|
577
|
+
Do not mark status as VERIFIED until concrete terminal evidence is provided.
|
|
578
|
+
|
|
579
|
+
---
|