Decision Tree
Need table name? → UPPER_SNAKE_CASE, singular
Need column name? → lower_snake_case
Need boolean column? → Prefix with is_, has_, can_
Need index name? → idx_table_columns
Need constraint name? → pk_, fk_, uq_, ck_ prefixes
SQL Style Guide
To ensure maintainability, readability, and consistency across database projects, follow these styling and naming conventions.
1. Naming Conventions
1.1 Tables
- Case: Use
UPPER_SNAKE_CASE or PascalCase consistently. (Standard: UPPER_SNAKE_CASE for SQL compatibility).
- Plurality: Use Singular names for entities to represent the definition of a single record (e.g.,
USER, ORDER, not USERS).
- Prefixes: Avoid Hungarian notation (e.g.,
tbl_User).
- Junction Tables: Combine names of related tables (e.g.,
USER_ROLE).
1.2 Columns
- Case: Use
lower_snake_case.
- Clarity: Names should be descriptive (e.g.,
created_at instead of date).
- Booleans: Prefix with
is_, has_, or can_ (e.g., is_active).
- Foreign Keys: Use
fk_<target_table_id> or <target_table>_id consistently.
1.3 Keys & Constraints
Explicitly name all constraints to facilitate debugging.
- Primary Keys:
pk_<table_name>
- Foreign Keys:
fk_<source>_<target>
- Unique:
uq_<table_name>_<columns>
- Check:
ck_<table_name>_<condition_description>
1.4 Database Objects
- Views: Prefix with
v_ or vw_.
- Materialized Views: Prefix with
mv_.
- Functions: Prefix with
fn_ (e.g., fn_calculate_tax).
- Procedures: Prefix with
sp_ (Stored Procedure) (e.g., sp_archive_orders).
- Triggers: Prefix with
trg_ followed by timing (e.g., trg_users_before_insert).
- Indexes: Prefix with
idx_ followed by table and columns (e.g., idx_employee_organization_id).
2. Formatting
2.1 Keywords
- Write all SQL keywords in UPPERCASE (e.g.,
SELECT, FROM, WHERE).
2.2 Indentation
- Use 4 spaces for indentation.
- Align clauses for readability.
SELECT
u.id,
u.email,
COUNT(o.id) AS total_orders
FROM USER u
LEFT JOIN ORDER o ON u.id = o.user_id
WHERE
u.is_active = TRUE
GROUP BY
u.id,
u.email;
2.3 Comments
- Use
-- for single-line comments.
- Use
/* ... */ for multi-line block comments.
- Header: Every script/procedure must have a header documenting Author, Date, and Purpose.
-- =============================================================================
-- PURPOSE: Calculates monthly recurring revenue
-- AUTHOR: [Name]
-- DATE: YYYY-MM-DD
-- =============================================================================
3. Best Practices
- No
SELECT *: Always specify columns explicitly to avoid breaking changes when schemas evolve.
- Aliases: Use short, meaningful aliases for tables (e.g.,
u for USER).
- Termination: Always terminate statements with a semicolon
;.
4. Reference Implementation
Below is an example schema that demonstrates the application of these Style, Design, and Security rules.
-- =============================================================================
-- SCRIPT: Example Schema
-- PURPOSE: Demonstrates the application of custom-rules/database standards.
-- =============================================================================
-- 1. Table Creation (Style Guide: UPPER_SNAKE_CASE, Singular)
-- Design Pattern: Surrogate PK, text type usage.
CREATE TABLE ORGANIZATION (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
tax_id VARCHAR(50) NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
-- Explicit Constraint Naming
CONSTRAINT uq_organization_tax_id UNIQUE (tax_id),
CONSTRAINT ck_organization_name_len CHECK (LENGTH(name) > 0)
);
-- 2. Child Table with Foreign Key
CREATE TABLE EMPLOYEE (
id SERIAL PRIMARY KEY,
organization_id INT NOT NULL,
email VARCHAR(255) NOT NULL,
full_name TEXT NOT NULL,
salary DECIMAL(10, 2) CHECK (salary >= 0),
-- Foreign Key with Indexing (to be added below)
CONSTRAINT fk_employee_organization FOREIGN KEY (organization_id) REFERENCES ORGANIZATION(id)
);
-- 3. Indexing (Efficiency Pattern)
-- Index FKs
CREATE INDEX idx_employee_organization_id ON EMPLOYEE(organization_id);
-- Index Searchable fields
CREATE INDEX idx_employee_email ON EMPLOYEE(email);
-- 4. Junction Table (N:M Relationship)
CREATE TABLE PROJECT (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE EMPLOYEE_ASSIGNMENT (
employee_id INT NOT NULL,
project_id INT NOT NULL,
assigned_at TIMESTAMP DEFAULT NOW(),
PRIMARY KEY (employee_id, project_id),
CONSTRAINT fk_assignment_employee FOREIGN KEY (employee_id) REFERENCES EMPLOYEE(id),
CONSTRAINT fk_assignment_project FOREIGN KEY (project_id) REFERENCES PROJECT(id)
);
-- 5. Stored Procedure (Logic Guidelines)
-- Header, idempotent, error handling
CREATE OR REPLACE PROCEDURE sp_register_employee(
p_org_id INT,
p_email VARCHAR,
p_name VARCHAR
)
LANGUAGE plpgsql
AS $$
BEGIN
-- Validation
IF NOT EXISTS (SELECT 1 FROM ORGANIZATION WHERE id = p_org_id) THEN
RAISE EXCEPTION 'Organization % does not exist', p_org_id;
END IF;
-- Insertion
INSERT INTO EMPLOYEE (organization_id, email, full_name)
VALUES (p_org_id, p_email, p_name);
-- Transaction control is implicit in procedures if needed, or controlled by caller.
EXCEPTION
WHEN unique_violation THEN
RAISE NOTICE 'Employee % already registered.', p_email;
END;
$$;
-- 6. RLS (Security Guidelines)
ALTER TABLE EMPLOYEE ENABLE ROW LEVEL SECURITY;
CREATE POLICY employee_isolation_policy ON EMPLOYEE
FOR ALL
USING (organization_id = current_setting('app.current_org_id')::INT);
1---2name: style-guide3description: SQL Naming, Formatting, and Style Guide Trigger: When following database naming conventions.4license: Apache-2.05---67## Decision Tree89```10Need table name? → UPPER_SNAKE_CASE, singular11Need column name? → lower_snake_case12Need boolean column? → Prefix with is_, has_, can_13Need index name? → idx_table_columns14Need constraint name? → pk_, fk_, uq_, ck_ prefixes15```1617---1819# SQL Style Guide2021To ensure maintainability, readability, and consistency across database projects, follow these styling and naming conventions.2223## 1. Naming Conventions2425### 1.1 Tables2627- **Case:** Use `UPPER_SNAKE_CASE` or `PascalCase` consistently. (Standard: `UPPER_SNAKE_CASE` for SQL compatibility).28- **Plurality:** Use **Singular** names for entities to represent the definition of a single record (e.g., `USER`, `ORDER`, not `USERS`).29- **Prefixes:** Avoid Hungarian notation (e.g., `tbl_User`).30- **Junction Tables:** Combine names of related tables (e.g., `USER_ROLE`).3132### 1.2 Columns3334- **Case:** Use `lower_snake_case`.35- **Clarity:** Names should be descriptive (e.g., `created_at` instead of `date`).36- **Booleans:** Prefix with `is_`, `has_`, or `can_` (e.g., `is_active`).37- **Foreign Keys:** Use `fk_<target_table_id>` or `<target_table>_id` consistently.3839### 1.3 Keys & Constraints4041Explicitly name all constraints to facilitate debugging.4243- **Primary Keys:** `pk_<table_name>`44- **Foreign Keys:** `fk_<source>_<target>`45- **Unique:** `uq_<table_name>_<columns>`46- **Check:** `ck_<table_name>_<condition_description>`4748### 1.4 Database Objects4950- **Views:** Prefix with `v_` or `vw_`.51- **Materialized Views:** Prefix with `mv_`.52- **Functions:** Prefix with `fn_` (e.g., `fn_calculate_tax`).53- **Procedures:** Prefix with `sp_` (Stored Procedure) (e.g., `sp_archive_orders`).54- **Triggers:** Prefix with `trg_` followed by timing (e.g., `trg_users_before_insert`).55- **Indexes:** Prefix with `idx_` followed by table and columns (e.g., `idx_employee_organization_id`).5657## 2. Formatting5859### 2.1 Keywords6061- Write all SQL keywords in **UPPERCASE** (e.g., `SELECT`, `FROM`, `WHERE`).6263### 2.2 Indentation6465- Use 4 spaces for indentation.66- Align clauses for readability.6768```sql69SELECT70 u.id,71 u.email,72 COUNT(o.id) AS total_orders73FROM USER u74LEFT JOIN ORDER o ON u.id = o.user_id75WHERE76 u.is_active = TRUE77GROUP BY78 u.id,79 u.email;80```8182### 2.3 Comments8384- Use `--` for single-line comments.85- Use `/* ... */` for multi-line block comments.86- **Header:** Every script/procedure must have a header documenting Author, Date, and Purpose.8788```sql89-- =============================================================================90-- PURPOSE: Calculates monthly recurring revenue91-- AUTHOR: [Name]92-- DATE: YYYY-MM-DD93-- =============================================================================94```9596## 3. Best Practices9798- **No `SELECT *`:** Always specify columns explicitly to avoid breaking changes when schemas evolve.99- **Aliases:** Use short, meaningful aliases for tables (e.g., `u` for `USER`).100- **Termination:** Always terminate statements with a semicolon `;`.101102## 4. Reference Implementation103104Below is an example schema that demonstrates the application of these Style, Design, and Security rules.105106```sql107-- =============================================================================108-- SCRIPT: Example Schema109-- PURPOSE: Demonstrates the application of custom-rules/database standards.110-- =============================================================================111112-- 1. Table Creation (Style Guide: UPPER_SNAKE_CASE, Singular)113-- Design Pattern: Surrogate PK, text type usage.114CREATE TABLE ORGANIZATION (115 id SERIAL PRIMARY KEY,116 name TEXT NOT NULL,117 tax_id VARCHAR(50) NOT NULL,118 is_active BOOLEAN DEFAULT TRUE,119 created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),120121 -- Explicit Constraint Naming122 CONSTRAINT uq_organization_tax_id UNIQUE (tax_id),123 CONSTRAINT ck_organization_name_len CHECK (LENGTH(name) > 0)124);125126-- 2. Child Table with Foreign Key127CREATE TABLE EMPLOYEE (128 id SERIAL PRIMARY KEY,129 organization_id INT NOT NULL,130 email VARCHAR(255) NOT NULL,131 full_name TEXT NOT NULL,132 salary DECIMAL(10, 2) CHECK (salary >= 0),133134 -- Foreign Key with Indexing (to be added below)135 CONSTRAINT fk_employee_organization FOREIGN KEY (organization_id) REFERENCES ORGANIZATION(id)136);137138-- 3. Indexing (Efficiency Pattern)139-- Index FKs140CREATE INDEX idx_employee_organization_id ON EMPLOYEE(organization_id);141-- Index Searchable fields142CREATE INDEX idx_employee_email ON EMPLOYEE(email);143144-- 4. Junction Table (N:M Relationship)145CREATE TABLE PROJECT (146 id SERIAL PRIMARY KEY,147 name TEXT NOT NULL148);149150CREATE TABLE EMPLOYEE_ASSIGNMENT (151 employee_id INT NOT NULL,152 project_id INT NOT NULL,153 assigned_at TIMESTAMP DEFAULT NOW(),154155 PRIMARY KEY (employee_id, project_id),156 CONSTRAINT fk_assignment_employee FOREIGN KEY (employee_id) REFERENCES EMPLOYEE(id),157 CONSTRAINT fk_assignment_project FOREIGN KEY (project_id) REFERENCES PROJECT(id)158);159160-- 5. Stored Procedure (Logic Guidelines)161-- Header, idempotent, error handling162CREATE OR REPLACE PROCEDURE sp_register_employee(163 p_org_id INT,164 p_email VARCHAR,165 p_name VARCHAR166)167LANGUAGE plpgsql168AS $$169BEGIN170 -- Validation171 IF NOT EXISTS (SELECT 1 FROM ORGANIZATION WHERE id = p_org_id) THEN172 RAISE EXCEPTION 'Organization % does not exist', p_org_id;173 END IF;174175 -- Insertion176 INSERT INTO EMPLOYEE (organization_id, email, full_name)177 VALUES (p_org_id, p_email, p_name);178179 -- Transaction control is implicit in procedures if needed, or controlled by caller.180181EXCEPTION182 WHEN unique_violation THEN183 RAISE NOTICE 'Employee % already registered.', p_email;184END;185$$;186187-- 6. RLS (Security Guidelines)188ALTER TABLE EMPLOYEE ENABLE ROW LEVEL SECURITY;189190CREATE POLICY employee_isolation_policy ON EMPLOYEE191FOR ALL192USING (organization_id = current_setting('app.current_org_id')::INT);193```