← Назад к вопросам
Как разнесешь по таблицам массив автомобилей, марок и владельцев?
2.0 Middle🔥 181 комментариев
#Архитектура и паттерны#Базы данных и SQL
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Проектирование схемы БД для автомобилей
При проектировании системы управления автомобилями и их владельцами нужно следовать принципам нормализации БД для избежания дублирования и обеспечения целостности данных.
Структура таблиц
Разложу данные на три основные таблицы:
1. Таблица марок (Brands)
CREATE TABLE brands (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
2. Таблица владельцев (Owners)
CREATE TABLE owners (
id SERIAL PRIMARY KEY,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE,
phone VARCHAR(20),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
3. Таблица автомобилей (Cars)
CREATE TABLE cars (
id SERIAL PRIMARY KEY,
brand_id INT NOT NULL,
owner_id INT NOT NULL,
model VARCHAR(100) NOT NULL,
year INT,
vin VARCHAR(17) UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (brand_id) REFERENCES brands(id) ON DELETE RESTRICT,
FOREIGN KEY (owner_id) REFERENCES owners(id) ON DELETE CASCADE
);
Вставка данных из массива
Обработка входного массива с использованием Node.js и PostgreSQL:
const pool = require("./db");
async function importCars(carsData) {
const client = await pool.connect();
try {
await client.query("BEGIN");
const brandMap = new Map();
const ownerMap = new Map();
for (const car of carsData) {
if (!brandMap.has(car.brand)) {
const brandResult = await client.query(
"INSERT INTO brands (name) VALUES ($1) ON CONFLICT (name) DO UPDATE SET name = $1 RETURNING id",
[car.brand]
);
brandMap.set(car.brand, brandResult.rows[0].id);
}
const brandId = brandMap.get(car.brand);
const ownerKey = `${car.owner.firstName}_${car.owner.lastName}`;
if (!ownerMap.has(ownerKey)) {
const ownerResult = await client.query(
"INSERT INTO owners (first_name, last_name, email, phone) VALUES ($1, $2, $3, $4) RETURNING id",
[car.owner.firstName, car.owner.lastName, car.owner.email, car.owner.phone]
);
ownerMap.set(ownerKey, ownerResult.rows[0].id);
}
const ownerId = ownerMap.get(ownerKey);
await client.query(
"INSERT INTO cars (brand_id, owner_id, model, year, vin) VALUES ($1, $2, $3, $4, $5)",
[brandId, ownerId, car.model, car.year, car.vin]
);
}
await client.query("COMMIT");
console.log("Данные успешно импортированы");
} catch (error) {
await client.query("ROLLBACK");
throw error;
} finally {
client.release();
}
}
Ключевые моменты
- Нормализация: каждая сущность в отдельной таблице, связи через foreign keys
- Избежание дублирования: кэширование марок и владельцев перед вставкой
- Транзакции: гарантия консистентности при сбое
- UNIQUE констрейнты: предотвращение дублирования VIN и названий марок
- ON DELETE CASCADE/RESTRICT: правила удаления для целостности
Такая архитектура обеспечивает масштабируемость, легкий поиск и аналитику данных о транспортных средствах и их владельцах.