Skip to content

Commit a32d5af

Browse files
docs: add naming dilemma blog (#902)
* add naming dilemma blog * update url
1 parent d48bfd3 commit a32d5af

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
---
2+
title: 'SQL Table Naming Dilemma: Singular vs. Plural'
3+
author: Adela
4+
updated_at: 2025/10/01 18:00
5+
feature_image: /content/blog/sql-table-naming-dilemma-singular-vs-plural/cover.webp
6+
tags: Explanation
7+
description: A comprehensive guide to understanding the dilemma of singular vs. plural table naming in SQL databases.
8+
---
9+
10+
**TL;DR:** Pick one style, document it, and stick to it. If you’re undecided, **plural tables** (`users`, `orders`) are a safe default: they read naturally in SQL and dodge some reserved words. Consistency matters more than the “right” choice.
11+
## Why it matters
12+
13+
Names ripple through SQL, ORMs, migrations, BI, and docs. A consistent convention lowers cognitive load and onboarding time.
14+
15+
## The two camps
16+
17+
### Singular (`user`, `order_item`)
18+
19+
**Pros**
20+
21+
* **OOP alignment:** maps cleanly to classes/entities (a row is a `User`).
22+
* **Language simplicity:** avoids irregular plurals for international teams.
23+
* **Master–detail reads cleanly:** `order``order_detail` can feel natural.
24+
25+
**Cons**
26+
27+
* **Reserved words:** `user`, `order`, `group`, `session` can clash.
28+
* **Query feel:** `SELECT * FROM user` reads a bit stilted.
29+
30+
### Plural (`users`, `order_items`)
31+
32+
**Pros**
33+
34+
* **Natural language in SQL:** `SELECT * FROM users WHERE age > 21`.
35+
* **Reserved-word avoidance:** `orders` > `order`.
36+
* **Framework affinity:** popular in Rails and many modern stacks.
37+
38+
**Cons**
39+
40+
* **Semantic mismatch:** a row is a user but lives in `users`.
41+
* **Irregulars:** `person/people`, `child/children` add edge cases.
42+
43+
## Industry split (rule of thumb)
44+
45+
| Approach | Common In | Key Advantage |
46+
| -------- | -------------------------------- | ------------------------------- |
47+
| Singular | Enterprise / traditional systems | OOP consistency; entity focus |
48+
| Plural | Web frameworks / modern stacks | Readability; framework defaults |
49+
50+
> There’s no universal standard; both conventions are widespread. What matters is a deliberate choice and consistency.
51+
52+
## Quick decision guide
53+
54+
* **Greenfield & undecided:** choose **plural tables**.
55+
* **Existing codebase:** **match what’s there**—consistency beats preference.
56+
* **Reserved-word risk:** prefer **plural** (`orders`, `groups`).
57+
* **Strict DDD shops / heavy OOP mapping:** singular can fit better.
58+
59+
## Practical conventions (copy-paste)
60+
61+
1. **Tables:** plural, `snake_case``users`, `orders`, `order_items`, `audit_logs`.
62+
2. **Join tables:** plural + plural, alphabetical → `orders_products`, `roles_users`.
63+
3. **Columns:** singular, `snake_case``id`, `user_id`, `created_at`, `updated_at`.
64+
4. **Views / MVs:** prefix + plural → `v_active_users`, `mv_daily_signups`.
65+
5. **Reference tables:** plural → `countries`, `currencies`, `order_statuses`.
66+
6. **Irregular nouns:** standardize once (e.g., always `people` *or* `persons`) and stick to it.
67+
68+
## Master–detail naming tips
69+
70+
* **Singular world:** `order` / `order_detail` is tidy and readable.
71+
* **Plural world (most common):** `orders` / `order_items` keeps the collection metaphor; avoid `orders_details`.
72+
Use the object’s name (`order_items`) rather than “detail(s)”.
73+
74+
## Governance (make it stick)
75+
76+
* Write the rule in your engineering handbook.
77+
* Add a schema linter/check in CI to block drift.
78+
* Provide examples for tricky cases (irregular plurals, join tables, reserved words).
79+
80+
## Examples
81+
82+
**Plural (recommended default)**
83+
84+
```sql
85+
CREATE TABLE users (
86+
id BIGSERIAL PRIMARY KEY,
87+
email TEXT UNIQUE NOT NULL,
88+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
89+
);
90+
91+
CREATE TABLE orders (
92+
id BIGSERIAL PRIMARY KEY,
93+
user_id BIGINT NOT NULL REFERENCES users(id),
94+
status TEXT NOT NULL,
95+
total_cents INTEGER NOT NULL,
96+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
97+
);
98+
99+
CREATE TABLE order_items (
100+
order_id BIGINT NOT NULL REFERENCES orders(id),
101+
product_id BIGINT NOT NULL REFERENCES products(id),
102+
quantity INTEGER NOT NULL DEFAULT 1,
103+
PRIMARY KEY (order_id, product_id)
104+
);
105+
```
106+
107+
**Singular (for strict entity alignment)**
108+
109+
```sql
110+
CREATE TABLE user (
111+
id BIGSERIAL PRIMARY KEY,
112+
email TEXT UNIQUE NOT NULL
113+
);
114+
115+
CREATE TABLE order (
116+
id BIGSERIAL PRIMARY KEY,
117+
user_id BIGINT NOT NULL REFERENCES user(id)
118+
);
119+
/* Beware: user/order can conflict with reserved words in some contexts */
120+
```
121+
122+
## Final recommendation
123+
124+
Choose **one** convention, document it, enforce it. If you don’t have strong reasons, pick **plural tables + singular columns** with `snake_case`, and don’t revisit the debate in every PR. Consistency > perfection.
30.1 KB
Loading

0 commit comments

Comments
 (0)