Database Operations
Master the core database operations in MatsushibaDB. This guide covers everything from basic CRUD operations to advanced querying techniques.Basic Operations
Creating Tables
Copy
-- Basic table creation
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
age INTEGER,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- Table with foreign key
CREATE TABLE posts (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
content TEXT,
author_id INTEGER,
published BOOLEAN DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (author_id) REFERENCES users(id)
);
-- Table with constraints
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
price DECIMAL(10,2) CHECK (price > 0),
category_id INTEGER,
stock INTEGER DEFAULT 0 CHECK (stock >= 0),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (category_id) REFERENCES categories(id)
);
Inserting Data
Copy
const MatsushibaDB = require('matsushibadb');
const db = new MatsushibaDB('app.db');
// Single insert
const result = db.run(`
INSERT INTO users (name, email, age)
VALUES (?, ?, ?)
`, ['John Doe', '[email protected]', 30]);
console.log('User created with ID:', result.lastInsertRowid);
// Multiple inserts
const users = [
['Alice Smith', '[email protected]', 25],
['Bob Johnson', '[email protected]', 35],
['Carol Davis', '[email protected]', 28]
];
users.forEach(([name, email, age]) => {
db.run('INSERT INTO users (name, email, age) VALUES (?, ?, ?)', [name, email, age]);
});
// Insert with conflict resolution
db.run(`
INSERT OR REPLACE INTO users (email, name, age)
VALUES (?, ?, ?)
`, ['[email protected]', 'John Updated', 31]);
Querying Data
Copy
// Get all records
const allUsers = db.all('SELECT * FROM users');
console.log('All users:', allUsers);
// Get single record
const user = db.get('SELECT * FROM users WHERE id = ?', [1]);
console.log('User:', user);
// Get with conditions
const activeUsers = db.all(`
SELECT * FROM users
WHERE age > ? AND email LIKE ?
ORDER BY created_at DESC
`, [25, '%@example.com']);
// Get with joins
const postsWithAuthors = db.all(`
SELECT p.*, u.name as author_name, u.email as author_email
FROM posts p
JOIN users u ON p.author_id = u.id
WHERE p.published = 1
ORDER BY p.created_at DESC
`);
// Count records
const userCount = db.get('SELECT COUNT(*) as count FROM users');
console.log('Total users:', userCount.count);
// Aggregate functions
const stats = db.get(`
SELECT
COUNT(*) as total_users,
AVG(age) as avg_age,
MIN(age) as min_age,
MAX(age) as max_age
FROM users
`);
Updating Data
Copy
// Update single record
const result = db.run(`
UPDATE users
SET name = ?, age = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
`, ['John Updated', 32, 1]);
console.log('Rows updated:', result.changes);
// Update multiple records
const updateResult = db.run(`
UPDATE users
SET updated_at = CURRENT_TIMESTAMP
WHERE created_at < date('now', '-30 days')
`);
// Update with conditions
const inactiveUsers = db.run(`
UPDATE users
SET status = 'inactive'
WHERE last_login < date('now', '-90 days')
`);
// Update with joins
const updatePosts = db.run(`
UPDATE posts
SET published = 1
WHERE author_id IN (
SELECT id FROM users WHERE status = 'active'
)
`);
Deleting Data
Copy
// Delete single record
const result = db.run('DELETE FROM users WHERE id = ?', [1]);
console.log('Rows deleted:', result.changes);
// Delete with conditions
const oldUsers = db.run(`
DELETE FROM users
WHERE created_at < date('now', '-1 year')
`);
// Delete with joins
const orphanedPosts = db.run(`
DELETE FROM posts
WHERE author_id NOT IN (SELECT id FROM users)
`);
// Soft delete (update instead of delete)
const softDelete = db.run(`
UPDATE users
SET deleted_at = CURRENT_TIMESTAMP, status = 'deleted'
WHERE id = ?
`, [1]);
Advanced Querying
Complex Joins
Copy
-- Multiple table joins
SELECT
p.id,
p.title,
p.content,
u.name as author_name,
c.name as category_name,
COUNT(com.id) as comment_count
FROM posts p
JOIN users u ON p.author_id = u.id
LEFT JOIN categories c ON p.category_id = c.id
LEFT JOIN comments com ON p.id = com.post_id
WHERE p.published = 1
GROUP BY p.id, p.title, p.content, u.name, c.name
ORDER BY p.created_at DESC;
-- Self-join example
SELECT
e.name as employee_name,
m.name as manager_name,
e.department
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id
ORDER BY e.department, e.name;
Subqueries
Copy
-- Subquery in WHERE clause
SELECT * FROM users
WHERE id IN (
SELECT DISTINCT author_id
FROM posts
WHERE published = 1
);
-- Subquery in SELECT clause
SELECT
name,
email,
(SELECT COUNT(*) FROM posts WHERE author_id = users.id) as post_count
FROM users;
-- Correlated subquery
SELECT
p.title,
p.created_at,
(SELECT name FROM users WHERE id = p.author_id) as author_name
FROM posts p
WHERE p.created_at > (
SELECT AVG(created_at)
FROM posts
WHERE author_id = p.author_id
);
Window Functions
Copy
-- Row numbering
SELECT
name,
email,
ROW_NUMBER() OVER (ORDER BY created_at) as row_num
FROM users;
-- Ranking
SELECT
name,
age,
RANK() OVER (ORDER BY age DESC) as age_rank,
DENSE_RANK() OVER (ORDER BY age DESC) as dense_age_rank
FROM users;
-- Partitioned ranking
SELECT
department,
name,
salary,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) as dept_rank
FROM employees;
-- Running totals
SELECT
date,
amount,
SUM(amount) OVER (ORDER BY date) as running_total
FROM transactions;
Data Types and Constraints
Supported Data Types
Copy
-- Numeric types
CREATE TABLE numeric_examples (
id INTEGER PRIMARY KEY,
small_int SMALLINT,
big_int BIGINT,
real_num REAL,
decimal_num DECIMAL(10,2),
numeric_num NUMERIC(8,4)
);
-- Text types
CREATE TABLE text_examples (
id INTEGER PRIMARY KEY,
short_text VARCHAR(50),
long_text TEXT,
char_text CHAR(10),
clob_text CLOB
);
-- Date and time types
CREATE TABLE datetime_examples (
id INTEGER PRIMARY KEY,
date_col DATE,
time_col TIME,
datetime_col DATETIME,
timestamp_col TIMESTAMP
);
-- Binary types
CREATE TABLE binary_examples (
id INTEGER PRIMARY KEY,
blob_data BLOB,
binary_data BINARY(16)
);
-- JSON type
CREATE TABLE json_examples (
id INTEGER PRIMARY KEY,
json_data JSON,
jsonb_data JSONB
);
Constraints
Copy
-- Primary key constraint
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
-- Foreign key constraint
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
user_id INTEGER,
amount DECIMAL(10,2),
FOREIGN KEY (user_id) REFERENCES users(id)
);
-- Check constraint
CREATE TABLE products (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
price DECIMAL(10,2) CHECK (price > 0),
stock INTEGER CHECK (stock >= 0),
status TEXT CHECK (status IN ('active', 'inactive', 'discontinued'))
);
-- Unique constraint
CREATE TABLE users (
id INTEGER PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
username TEXT UNIQUE NOT NULL
);
-- Default values
CREATE TABLE posts (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
content TEXT,
published BOOLEAN DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
Indexes and Performance
Creating Indexes
Copy
-- Single column index
CREATE INDEX idx_users_email ON users(email);
-- Composite index
CREATE INDEX idx_posts_author_date ON posts(author_id, created_at);
-- Unique index
CREATE UNIQUE INDEX idx_users_username ON users(username);
-- Partial index
CREATE INDEX idx_active_users ON users(email) WHERE status = 'active';
-- Covering index
CREATE INDEX idx_posts_covering ON posts(author_id, published, created_at)
INCLUDE (title, content);
Query Optimization
Copy
// Use prepared statements for repeated queries
const getUserStmt = db.prepare('SELECT * FROM users WHERE id = ?');
const user = getUserStmt.get(1);
// Use transactions for multiple operations
const insertMany = db.transaction((users) => {
const stmt = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');
for (const user of users) {
stmt.run(user.name, user.email);
}
});
// Use LIMIT for large result sets
const recentUsers = db.all(`
SELECT * FROM users
ORDER BY created_at DESC
LIMIT 100
`);
// Use pagination
const getUsersPage = (page, pageSize) => {
const offset = (page - 1) * pageSize;
return db.all(`
SELECT * FROM users
ORDER BY created_at DESC
LIMIT ? OFFSET ?
`, [pageSize, offset]);
};
Error Handling
Copy
try {
const result = db.run('INSERT INTO users (name, email) VALUES (?, ?)',
['John Doe', '[email protected]']);
console.log('User created with ID:', result.lastInsertRowid);
} catch (error) {
if (error.code === 'SQLITE_CONSTRAINT') {
if (error.message.includes('UNIQUE constraint failed')) {
console.error('User with this email already exists');
} else if (error.message.includes('NOT NULL constraint failed')) {
console.error('Required fields are missing');
} else {
console.error('Constraint violation:', error.message);
}
} else if (error.code === 'SQLITE_BUSY') {
console.error('Database is busy, please try again');
} else {
console.error('Database error:', error.message);
}
}
Best Practices
1
Use Prepared Statements
Always use prepared statements for repeated queries to improve performance and prevent SQL injection.
2
Create Appropriate Indexes
Create indexes on frequently queried columns and composite indexes for multi-column queries.
3
Handle Errors Gracefully
Implement proper error handling for all database operations with specific error type handling.
4
Use Transactions
Wrap related operations in transactions to maintain data consistency and atomicity.
5
Optimize Queries
Use EXPLAIN QUERY PLAN to analyze and optimize query performance.
6
Limit Result Sets
Use LIMIT and OFFSET for pagination to avoid loading large datasets into memory.
7
Use Appropriate Data Types
Choose the most appropriate data types for your data to optimize storage and performance.
8
Implement Soft Deletes
Consider using soft deletes (status flags) instead of hard deletes for important data.
Mastering database operations is fundamental to building robust applications. Always prioritize data integrity, performance, and error handling in your database operations.