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-guide-23description: 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 Tables26- **Case:** Use `UPPER_SNAKE_CASE` or `PascalCase` consistently. (Standard: `UPPER_SNAKE_CASE` for SQL compatibility).27- **Plurality:** Use **Singular** names for entities to represent the definition of a single record (e.g., `USER`, `ORDER`, not `USERS`).28- **Prefixes:** Avoid Hungarian notation (e.g., `tbl_User`).29- **Junction Tables:** Combine names of related tables (e.g., `USER_ROLE`).3031### 1.2 Columns32- **Case:** Use `lower_snake_case`.33- **Clarity:** Names should be descriptive (e.g., `created_at` instead of `date`).34- **Booleans:** Prefix with `is_`, `has_`, or `can_` (e.g., `is_active`).35- **Foreign Keys:** Use `fk_<target_table_id>` or `<target_table>_id` consistently.3637### 1.3 Keys & Constraints38Explicitly name all constraints to facilitate debugging.39- **Primary Keys:** `pk_<table_name>`40- **Foreign Keys:** `fk_<source>_<target>`41- **Unique:** `uq_<table_name>_<columns>`42- **Check:** `ck_<table_name>_<condition_description>`4344### 1.4 Database Objects45- **Views:** Prefix with `v_` or `vw_`.46- **Materialized Views:** Prefix with `mv_`.47- **Functions:** Prefix with `fn_` (e.g., `fn_calculate_tax`).48- **Procedures:** Prefix with `sp_` (Stored Procedure) (e.g., `sp_archive_orders`).49- **Triggers:** Prefix with `trg_` followed by timing (e.g., `trg_users_before_insert`).50- **Indexes:** Prefix with `idx_` followed by table and columns (e.g., `idx_employee_organization_id`).5152## 2. Formatting5354### 2.1 Keywords55- Write all SQL keywords in **UPPERCASE** (e.g., `SELECT`, `FROM`, `WHERE`).5657### 2.2 Indentation58- Use 4 spaces for indentation.59- Align clauses for readability.6061```sql62SELECT63 u.id,64 u.email,65 COUNT(o.id) AS total_orders66FROM USER u67LEFT JOIN ORDER o ON u.id = o.user_id68WHERE69 u.is_active = TRUE70GROUP BY71 u.id,72 u.email;73```7475### 2.3 Comments76- Use `--` for single-line comments.77- Use `/* ... */` for multi-line block comments.78- **Header:** Every script/procedure must have a header documenting Author, Date, and Purpose.7980```sql81-- =============================================================================82-- PURPOSE: Calculates monthly recurring revenue83-- AUTHOR: [Name]84-- DATE: YYYY-MM-DD85-- =============================================================================86```8788## 3. Best Practices89- **No `SELECT *`:** Always specify columns explicitly to avoid breaking changes when schemas evolve.90- **Aliases:** Use short, meaningful aliases for tables (e.g., `u` for `USER`).91- **Termination:** Always terminate statements with a semicolon `;`.9293## 4. Reference Implementation9495Below is an example schema that demonstrates the application of these Style, Design, and Security rules.9697```sql98-- =============================================================================99-- SCRIPT: Example Schema100-- PURPOSE: Demonstrates the application of custom-rules/database standards.101-- =============================================================================102103-- 1. Table Creation (Style Guide: UPPER_SNAKE_CASE, Singular)104-- Design Pattern: Surrogate PK, text type usage.105CREATE TABLE ORGANIZATION (106 id SERIAL PRIMARY KEY,107 name TEXT NOT NULL,108 tax_id VARCHAR(50) NOT NULL,109 is_active BOOLEAN DEFAULT TRUE,110 created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),111 112 -- Explicit Constraint Naming113 CONSTRAINT uq_organization_tax_id UNIQUE (tax_id),114 CONSTRAINT ck_organization_name_len CHECK (LENGTH(name) > 0)115);116117-- 2. Child Table with Foreign Key118CREATE TABLE EMPLOYEE (119 id SERIAL PRIMARY KEY,120 organization_id INT NOT NULL,121 email VARCHAR(255) NOT NULL,122 full_name TEXT NOT NULL,123 salary DECIMAL(10, 2) CHECK (salary >= 0),124 125 -- Foreign Key with Indexing (to be added below)126 CONSTRAINT fk_employee_organization FOREIGN KEY (organization_id) REFERENCES ORGANIZATION(id)127);128129-- 3. Indexing (Efficiency Pattern)130-- Index FKs131CREATE INDEX idx_employee_organization_id ON EMPLOYEE(organization_id);132-- Index Searchable fields133CREATE INDEX idx_employee_email ON EMPLOYEE(email);134135-- 4. Junction Table (N:M Relationship)136CREATE TABLE PROJECT (137 id SERIAL PRIMARY KEY,138 name TEXT NOT NULL139);140141CREATE TABLE EMPLOYEE_ASSIGNMENT (142 employee_id INT NOT NULL,143 project_id INT NOT NULL,144 assigned_at TIMESTAMP DEFAULT NOW(),145 146 PRIMARY KEY (employee_id, project_id),147 CONSTRAINT fk_assignment_employee FOREIGN KEY (employee_id) REFERENCES EMPLOYEE(id),148 CONSTRAINT fk_assignment_project FOREIGN KEY (project_id) REFERENCES PROJECT(id)149);150151-- 5. Stored Procedure (Logic Guidelines)152-- Header, idempotent, error handling153CREATE OR REPLACE PROCEDURE sp_register_employee(154 p_org_id INT,155 p_email VARCHAR,156 p_name VARCHAR157)158LANGUAGE plpgsql159AS $$160BEGIN161 -- Validation162 IF NOT EXISTS (SELECT 1 FROM ORGANIZATION WHERE id = p_org_id) THEN163 RAISE EXCEPTION 'Organization % does not exist', p_org_id;164 END IF;165166 -- Insertion167 INSERT INTO EMPLOYEE (organization_id, email, full_name)168 VALUES (p_org_id, p_email, p_name);169 170 -- Transaction control is implicit in procedures if needed, or controlled by caller.171 172EXCEPTION173 WHEN unique_violation THEN174 RAISE NOTICE 'Employee % already registered.', p_email;175END;176$$;177178-- 6. RLS (Security Guidelines)179ALTER TABLE EMPLOYEE ENABLE ROW LEVEL SECURITY;180181CREATE POLICY employee_isolation_policy ON EMPLOYEE182FOR ALL183USING (organization_id = current_setting('app.current_org_id')::INT);184```