thesoftwarehouse/copilot-collections/tsh-sql-and-database-understanding

Claude Code and agent skill by thesoftwarehouse/copilot-collections

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

SQL writing and database engineering patterns, standards, and procedures. Use for designing database schemas, writing performant SQL queries, normalisation strategies, indexing, joins optimisation, locking mechanics, transactions, query debugging with EXPLAIN, and ORM integration. Applies to PostgreSQL, MySQL, MariaDB, SQL Server, and Oracle. Covers ORM usage with TypeORM, Prisma, Doctrine, Eloquent, Entity Framework, Hibernate, and GORM.

Install

npx vskill@latest install thesoftwarehouse/copilot-collections/tsh-sql-and-database-understanding

SKILL.md

SQL & Database Engineering

This skill provides standards, patterns, and procedures for database schema design, writing performant SQL, query debugging, and database engineering best practices. It is database-engine-agnostic with notes on engine-specific behavior where critical.

Guiding Principles

PrincipleApplication
Data Integrity FirstEnforce constraints at the database level (NOT NULL, UNIQUE, FK, CHECK). Never rely solely on application-level validation.
Least PrivilegeDatabase users/roles should have only the permissions they need. Application connections should never use the superuser account.
Explicit Over ImplicitAlways specify column lists in SELECT, INSERT, and JOIN clauses. Avoid SELECT * in production code.
Measure Before OptimisingUse EXPLAIN ANALYZE to identify actual bottlenecks before adding indexes or restructuring queries.
Schema as CodeAll schema changes go through versioned migration files. Never modify production schemas manually.

1. Database Schema Architecture Design

Naming Conventions
ElementConventionExample
Tablessnake_case, plural nounsorder_items, user_addresses
Columnssnake_casefirst_name, created_at
Primary keysid (preferred) or <table_singular>_idid, user_id
Foreign keys<referenced_table_singular>_iduser_id, order_id
Indexesidx_<table>_<columns>idx_orders_user_id_status
Unique constraintsuq_<table>_<columns>uq_users_email
Check constraintschk_<table>_<description>chk_orders_total_positive
Junction/pivot tables<table1>_<table2> (alphabetical)products_tags, roles_users
Standard Columns

Every table MUST include:

sql
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- or BIGSERIAL for auto-increment
-- ... domain columns ...
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

When soft deletes are required by business rules:

sql
deleted_at TIMESTAMP WITH TIME ZONE DEFAULT NULL
Primary Key Strategy
StrategyWhen to UseTrade-offs
UUID v4 / UUID v7Distributed systems, microservices, public-facing IDsLarger storage, random UUIDs cause index fragmentation (prefer UUID v7 for ordered inserts)
ULIDWhen you need sortable unique IDs with good index localityNot natively supported in all databases
BIGSERIAL / IDENTITYSingle-database monoliths, internal IDsSequential, predictable (security concern if exposed), not portable across DB instances

Rule: Never expose auto-increment IDs in public APIs. Use UUIDs or ULIDs for external identifiers.

Data Types — Choose Precisely
NeedUseAvoid
Monetary valuesNUMERIC(19,4) or DECIMAL(19,4)FLOAT, DOUBLE (precision loss)
TimestampsTIMESTAMP WITH TIME ZONETIMESTAMP without timezone
Boolean flagsBOOLEANTINYINT, CHAR(1)
Short text (name, email)VARCHAR(n) with appropriate limitUnbounded TEXT for structured fields
Long text (descriptions)TEXTVARCHAR(10000)
EnumsVARCHAR with CHECK constraint or native ENUMMagic integers
JSON/semi-structuredJSONB (PostgreSQL) or JSONStoring relational data as JSON
IP addressesINET (PostgreSQL) or VARCHAR(45)VARCHAR(15) (IPv6 won't fit)
Enum Handling

Prefer CHECK constraints over native ENUM types for portability and ease of migration:

sql
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
status VARCHAR(20) NOT NULL DEFAULT 'pending'
CONSTRAINT chk_orders_status CHECK (status IN ('pending', 'confirmed', 'shipped', 'delivered', 'cancelled')),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

Adding a new enum value is a simple ALTER TABLE ... DROP CONSTRAINT + ADD CONSTRAINT, no table rewrite required.

Schema Design Checklist
Schema design checklist:
- [ ] Every table has a primary key (UUID or BIGSERIAL)
- [ ] Every table has created_at and updated_at columns
- [ ] All foreign keys have corresponding indexes
- [ ] All columns have appropriate NOT NULL constraints
- [ ] Unique constraints are defined where business rules require uniqueness
- [ ] CHECK constraints enforce valid value ranges and enums
- [ ] Naming follows snake_case conventions consistently
- [ ] Data types are chosen precisely (no FLOAT for money, no TEXT for emails)
- [ ] Soft delete (deleted_at) is used only where business rules require it
- [ ] No business logic is embedded in database triggers or stored procedures (keep logic in the application layer)

2. Normalisation Strategies

Normal Forms Reference
Normal FormRuleViolation ExampleFix
1NFEvery column holds atomic (indivisible) values. No repeating groups.tags: "php,sql,go" in a single columnCreate a separate tags table with a junction table
2NF1NF + every non-key column depends on the entire primary key (relevant for composite keys)order_items(order_id, product_id, product_name) — product_name depends only on product_idMove product_name to the products table
3NF2NF + no transitive dependencies (non-key column depends on another non-key column)employees(id, department_id, department_name) — department_name depends on department_id, not on idMove department_name to a departments table
BCNF3NF + every determinant is a candidate keyRare in practice; address when composite keys create functional dependency issuesDecompose the table so every determinant is a key
When to Use Each Level

Target 3NF by default. This eliminates redundancy while keeping the schema manageable.

Use 2NF only as an intermediate step when refactoring legacy schemas — never as a design target.

Use BCNF when you have composite primary keys with overlapping candidate keys (uncommon in application databases).

Practical Normalisation Example

Unnormalised (0NF):

orders:
| order_id | customer_name | customer_email | items |
|----------|---------------|---------------------|--------------------------------|
| 1 | John Doe | john@example.com | Widget x2, Gadget x1 |

1NF — Atomic values, no repeating groups:

sql
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
customer_name VARCHAR(100) NOT NULL,
customer_email VARCHAR(255) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
CREATE TABLE order_items (
id BIGSERIAL PRIMARY KEY,
order_id BIGINT NOT NULL REFERENCES orders(id),
product_name VARCHAR(100) NOT NULL,
quantity INT NOT NULL CHECK (quantity > 0)
);

2NF — Remove partial dependencies (product details depend on product, not order):

sql
CREATE TABLE products (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price NUMERIC(19,4) NOT NULL
);
CREATE TABLE order_items (
id BIGSERIAL PRIMARY KEY,
order_id BIGINT NOT NULL REFERENCES orders(id),
product_id BIGINT NOT NULL REFERENCES products(id),
quantity INT NOT NULL CHECK (quantity > 0),
unit_price NUMERIC(19,4) NOT NULL -- snapshot of price at order time
);

3NF — Remove transitive dependencies (customer depends on customer, not order):

sql
CREATE TABLE customers (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE
);
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
customer_id BIGINT NOT NULL REFERENCES customers(id),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
Strategic Denormalisation

Denormalise only when you have measured performance data (via EXPLAIN ANALYZE) proving that joins are the bottleneck. Common valid cases:

PatternWhen to UseExample
Materialised/cached columnsFrequently read aggregate that is expensive to compute on every queryorders.total_amount computed from order_items and stored on the order row
Snapshot columnsValues that must be preserved at a point in time even if the source changesorder_items.unit_price (price at time of purchase, not current product price)
Read-optimised viewsReporting or analytics queries that span many tablesMaterialised views refreshed periodically
Search/filter columnsColumns derived from related tables used heavily in WHERE clausesorders.customer_country duplicated from customers.country for filtering

Rules for denormalisation:

  • Always document why the denormalisation exists (code comment + migration description).
  • Ensure the denormalised data is kept in sync (application-level updates, triggers as last resort, or materialised view refresh).
  • Treat denormalised data as a cache — the normalised source remains the source of truth.

3. Relationships & Foreign Keys

Relationship Types

One-to-Many (most common):

sql
-- A customer has many orders
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
customer_id BIGINT NOT NULL REFERENCES customers(id) ON DELETE RESTRICT,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_orders_customer_id ON orders(customer_id);

Many-to-Many (junction table):

sql
-- Products can have many tags, tags can belong to many products
CREATE TABLE products_tags (
product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE CASCADE,
tag_id BIGINT NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
PRIMARY KEY (product_id, tag_id)
);
CREATE INDEX idx_products_tags_tag_id ON products_tags(tag_id);

One-to-One:

sql
-- Each user has exactly one profile
CREATE TABLE user_profiles (
user_id BIGINT PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
bio TEXT,
avatar_url VARCHAR(500)
);
ON DELETE / ON UPDATE Actions
ActionMeaningWhen to Use
RESTRICT (default)Prevent deletion if referenced rows existDefault for most business entities (prevent accidental data loss)
CASCADEDelete/update child rows when parent is deleted/updatedJunction tables, dependent child records that have no meaning without parent
SET NULLSet FK to NULL when parent is deletedOptional relationships where the child can exist independently
SET DEFAULTSet FK to its default valueRare — use when a fallback reference makes business sense
NO ACTIONSame as RESTRICT but checked at end of transactionWhen deferred constraint checking is needed

Rule: Default to RESTRICT. Use CASCADE only on junction tables and tightly coupled child tables. Always explicitly specify the action — never rely on implicit defaults.

Self-Referencing Relationships
sql
-- Categories with parent-child hierarchy
CREATE TABLE categories (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
parent_id BIGINT REFERENCES categories(id) ON DELETE SET NULL
);
CREATE INDEX idx_categories_parent_id ON categories(parent_id);

For deep hierarchies (trees), consider:

  • Adjacency list (above) — simple, good for shallow trees
  • Materialised path — path VARCHAR(500) storing /1/5/12/ — good for read-heavy trees
  • Nested sets — complex to maintain but fast for subtree queries
  • Closure table — separate table storing all ancestor-descendant pairs — balanced read/write performance

4. Indexes

Index Types

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
266
Repository forks
18
7-day trend score
28

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/thesoftwarehouse/copilot-collections/tsh-sql-and-database-understanding/badge)](https://verified-skill.com/skills/thesoftwarehouse/copilot-collections/tsh-sql-and-database-understanding)

Something wrong with this skill or its page? Tell us.