init
This commit is contained in:
216
.opencode/skills/databases/stacks/mysql.md
Normal file
216
.opencode/skills/databases/stacks/mysql.md
Normal file
@@ -0,0 +1,216 @@
|
||||
# MySQL Rules
|
||||
|
||||
Guidelines for designing schemas specific to MySQL / MariaDB.
|
||||
|
||||
---
|
||||
|
||||
## Data Types
|
||||
|
||||
| Use case | Type | Notes |
|
||||
|----------|------|-------|
|
||||
| Primary key | `BIGINT UNSIGNED AUTO_INCREMENT` | For large tables |
|
||||
| Primary key (small) | `INT UNSIGNED AUTO_INCREMENT` | Tables < 2 billion rows |
|
||||
| Foreign key | Match with PK type | |
|
||||
| Money/Price | `DECIMAL(18,2)` | **Do NOT use FLOAT/DOUBLE** |
|
||||
| Quantity | `INT` or `DECIMAL(18,4)` | |
|
||||
| Boolean | `TINYINT(1)` or `BOOLEAN` | |
|
||||
| Short text | `VARCHAR(n)` | n ≤ 255 for indexing |
|
||||
| Long text | `TEXT` | Cannot index directly |
|
||||
| JSON | `JSON` | MySQL 5.7+ |
|
||||
| Timestamp | `DATETIME` or `TIMESTAMP` | |
|
||||
| Date | `DATE` | |
|
||||
| UUID | `CHAR(36)` or `BINARY(16)` | |
|
||||
|
||||
### TIMESTAMP vs DATETIME
|
||||
- `TIMESTAMP`: Auto-converts timezone, range 1970-2038
|
||||
- `DATETIME`: No timezone conversion, range 1000-9999
|
||||
|
||||
---
|
||||
|
||||
## Comments (NO metadata tables needed)
|
||||
|
||||
MySQL supports comments directly in DDL:
|
||||
|
||||
### Table comment
|
||||
```sql
|
||||
CREATE TABLE orders (
|
||||
...
|
||||
) COMMENT='Table storing customer orders';
|
||||
```
|
||||
|
||||
### Column comment
|
||||
```sql
|
||||
CREATE TABLE orders (
|
||||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT
|
||||
COMMENT 'Primary key, auto increment',
|
||||
order_number VARCHAR(50) NOT NULL
|
||||
COMMENT 'Unique order code, format: ORD-YYYYMMDD-XXXXX',
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'pending'
|
||||
COMMENT 'Status: pending|confirmed|shipped|cancelled',
|
||||
total_amount DECIMAL(18,2) NOT NULL
|
||||
COMMENT 'Total value including tax'
|
||||
);
|
||||
```
|
||||
|
||||
### Query comments
|
||||
```sql
|
||||
-- Table comment
|
||||
SELECT TABLE_COMMENT FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'orders';
|
||||
|
||||
-- Column comments
|
||||
SELECT COLUMN_NAME, COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'orders';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Index Types
|
||||
|
||||
### B-Tree (default)
|
||||
```sql
|
||||
CREATE INDEX idx_orders_status ON orders(status);
|
||||
CREATE INDEX idx_orders_user_status_created ON orders(user_id, status, created_at DESC);
|
||||
CREATE UNIQUE INDEX idx_orders_number ON orders(order_number);
|
||||
```
|
||||
|
||||
### FULLTEXT (text search)
|
||||
```sql
|
||||
CREATE FULLTEXT INDEX idx_products_search ON products(name, description);
|
||||
|
||||
-- Query
|
||||
SELECT * FROM products
|
||||
WHERE MATCH(name, description) AGAINST('gaming laptop' IN NATURAL LANGUAGE MODE);
|
||||
```
|
||||
|
||||
### Notes
|
||||
- **Partial index**: Not natively supported in MySQL
|
||||
- Index prefix for TEXT: `CREATE INDEX idx ON table(col(255))`
|
||||
|
||||
---
|
||||
|
||||
## Auto Increment
|
||||
|
||||
```sql
|
||||
CREATE TABLE users (
|
||||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT
|
||||
);
|
||||
|
||||
-- Set starting value
|
||||
ALTER TABLE users AUTO_INCREMENT = 1000;
|
||||
|
||||
-- Get last inserted ID
|
||||
SELECT LAST_INSERT_ID();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Auto update timestamp
|
||||
|
||||
```sql
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ENUM vs VARCHAR
|
||||
|
||||
### Use ENUM when values are fixed and rarely change
|
||||
```sql
|
||||
status ENUM('pending', 'confirmed', 'shipped', 'cancelled') NOT NULL DEFAULT 'pending'
|
||||
```
|
||||
|
||||
### Use VARCHAR + CHECK when flexibility needed
|
||||
```sql
|
||||
status VARCHAR(32) NOT NULL DEFAULT 'pending',
|
||||
CONSTRAINT chk_orders_status CHECK (status IN ('pending', 'confirmed', 'shipped'))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Foreign Keys
|
||||
|
||||
```sql
|
||||
CREATE TABLE order_items (
|
||||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
|
||||
order_id BIGINT UNSIGNED NOT NULL,
|
||||
product_id BIGINT UNSIGNED NOT NULL,
|
||||
|
||||
CONSTRAINT fk_orderitems_order
|
||||
FOREIGN KEY (order_id) REFERENCES orders(id)
|
||||
ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
|
||||
CONSTRAINT fk_orderitems_product
|
||||
FOREIGN KEY (product_id) REFERENCES products(id)
|
||||
ON DELETE RESTRICT
|
||||
);
|
||||
|
||||
-- IMPORTANT: Index for FK
|
||||
CREATE INDEX idx_orderitems_order ON order_items(order_id);
|
||||
CREATE INDEX idx_orderitems_product ON order_items(product_id);
|
||||
```
|
||||
|
||||
**Note:** FK only works with **InnoDB** engine.
|
||||
|
||||
---
|
||||
|
||||
## Partitioning
|
||||
|
||||
### Range partitioning (by date)
|
||||
```sql
|
||||
CREATE TABLE fact_orders (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
order_date DATE NOT NULL,
|
||||
...
|
||||
PRIMARY KEY (id, order_date)
|
||||
) PARTITION BY RANGE (YEAR(order_date)) (
|
||||
PARTITION p2023 VALUES LESS THAN (2024),
|
||||
PARTITION p2024 VALUES LESS THAN (2025),
|
||||
PARTITION pmax VALUES LESS THAN MAXVALUE
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example DDL
|
||||
|
||||
```sql
|
||||
CREATE TABLE orders (
|
||||
id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT
|
||||
COMMENT 'Primary key',
|
||||
order_number VARCHAR(50) NOT NULL
|
||||
COMMENT 'Unique order code',
|
||||
user_id BIGINT UNSIGNED NOT NULL
|
||||
COMMENT 'FK to users.id',
|
||||
status ENUM('pending', 'confirmed', 'shipped', 'cancelled', 'completed')
|
||||
NOT NULL DEFAULT 'pending'
|
||||
COMMENT 'Order status',
|
||||
subtotal DECIMAL(18,2) NOT NULL DEFAULT 0,
|
||||
discount_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
|
||||
total_amount DECIMAL(18,2) NOT NULL DEFAULT 0,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
UNIQUE KEY uk_orders_number (order_number),
|
||||
KEY idx_orders_user (user_id),
|
||||
KEY idx_orders_status (status),
|
||||
KEY idx_orders_user_status_created (user_id, status, created_at DESC),
|
||||
|
||||
CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT
|
||||
) ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_unicode_ci
|
||||
COMMENT='Table storing order information';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Engine: `InnoDB` (required for FK)
|
||||
- [ ] Charset: `utf8mb4` + `utf8mb4_unicode_ci`
|
||||
- [ ] Comments for tables and columns
|
||||
- [ ] All FKs have indexes
|
||||
- [ ] Use `DECIMAL` for money, not `FLOAT`
|
||||
- [ ] `ON UPDATE CURRENT_TIMESTAMP` for `updated_at`
|
||||
Reference in New Issue
Block a user