← Назад к вопросам

Как разнесешь по таблицам массив автомобилей, марок и владельцев?

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: правила удаления для целостности

Такая архитектура обеспечивает масштабируемость, легкий поиск и аналитику данных о транспортных средствах и их владельцах.