294 lines
9.5 KiB
PL/PgSQL
294 lines
9.5 KiB
PL/PgSQL
-- Migration: Create Automotive Vehicle Selection Database
|
|
-- Optimized for dropdown cascade queries
|
|
-- Date: 2025-11-10
|
|
|
|
-- Drop existing tables if they exist
|
|
DROP TABLE IF EXISTS vehicle_options CASCADE;
|
|
DROP TABLE IF EXISTS engines CASCADE;
|
|
DROP TABLE IF EXISTS transmissions CASCADE;
|
|
DROP INDEX IF EXISTS idx_vehicle_year;
|
|
DROP INDEX IF EXISTS idx_vehicle_make;
|
|
DROP INDEX IF EXISTS idx_vehicle_model;
|
|
DROP INDEX IF EXISTS idx_vehicle_trim;
|
|
DROP INDEX IF EXISTS idx_vehicle_composite;
|
|
|
|
-- Create engines table with detailed specifications
|
|
CREATE TABLE engines (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL,
|
|
displacement VARCHAR(50),
|
|
configuration VARCHAR(50),
|
|
horsepower VARCHAR(100),
|
|
torque VARCHAR(100),
|
|
fuel_type VARCHAR(100),
|
|
fuel_system VARCHAR(255),
|
|
aspiration VARCHAR(100),
|
|
specs_json JSONB,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
-- Prevent duplicate engine display names (case-insensitive)
|
|
CREATE UNIQUE INDEX IF NOT EXISTS uq_engines_name_lower ON engines (LOWER(name));
|
|
|
|
CREATE INDEX idx_engines_displacement ON engines(displacement);
|
|
CREATE INDEX idx_engines_config ON engines(configuration);
|
|
|
|
-- Create transmissions table
|
|
CREATE TABLE transmissions (
|
|
id SERIAL PRIMARY KEY,
|
|
type VARCHAR(100) NOT NULL,
|
|
speeds VARCHAR(50),
|
|
drive_type VARCHAR(100),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
-- Prevent duplicate transmission display names (case-insensitive)
|
|
CREATE UNIQUE INDEX IF NOT EXISTS uq_transmissions_type_lower ON transmissions (LOWER(type));
|
|
|
|
CREATE INDEX idx_transmissions_type ON transmissions(type);
|
|
|
|
-- Create denormalized vehicle_options table optimized for dropdown queries
|
|
CREATE TABLE vehicle_options (
|
|
id SERIAL PRIMARY KEY,
|
|
year INTEGER NOT NULL,
|
|
make VARCHAR(100) NOT NULL,
|
|
model VARCHAR(255) NOT NULL,
|
|
trim VARCHAR(255) NOT NULL,
|
|
engine_id INTEGER REFERENCES engines(id) ON DELETE SET NULL,
|
|
transmission_id INTEGER REFERENCES transmissions(id) ON DELETE SET NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
-- Prevent duplicate vehicle option rows
|
|
CREATE UNIQUE INDEX IF NOT EXISTS uq_vehicle_options_full ON vehicle_options (
|
|
year, make, model, trim, engine_id, transmission_id
|
|
);
|
|
|
|
-- Indexes for cascading dropdown performance
|
|
CREATE INDEX idx_vehicle_year ON vehicle_options(year);
|
|
CREATE INDEX idx_vehicle_make ON vehicle_options(make);
|
|
CREATE INDEX idx_vehicle_model ON vehicle_options(model);
|
|
CREATE INDEX idx_vehicle_trim ON vehicle_options(trim);
|
|
CREATE INDEX idx_vehicle_year_make ON vehicle_options(year, make);
|
|
CREATE INDEX idx_vehicle_year_make_model ON vehicle_options(year, make, model);
|
|
CREATE INDEX idx_vehicle_year_make_model_trim ON vehicle_options(year, make, model, trim);
|
|
CREATE INDEX idx_vehicle_year_make_model_trim_engine ON vehicle_options(year, make, model, trim, engine_id);
|
|
CREATE INDEX idx_vehicle_year_make_model_trim_trans ON vehicle_options(year, make, model, trim, transmission_id);
|
|
|
|
-- Full-text search index for admin catalog search
|
|
CREATE INDEX idx_vehicle_options_fts ON vehicle_options
|
|
USING gin(to_tsvector('english', year::text || ' ' || make || ' ' || model || ' ' || trim));
|
|
|
|
-- Index on engines.name for join performance during search
|
|
CREATE INDEX idx_engines_name ON engines(name);
|
|
|
|
-- Views for dropdown queries
|
|
|
|
-- View: Get all available years
|
|
CREATE OR REPLACE VIEW available_years AS
|
|
SELECT DISTINCT year
|
|
FROM vehicle_options
|
|
ORDER BY year DESC;
|
|
|
|
-- View: Get makes by year
|
|
CREATE OR REPLACE VIEW makes_by_year AS
|
|
SELECT DISTINCT year, make
|
|
FROM vehicle_options
|
|
ORDER BY year DESC, make ASC;
|
|
|
|
-- View: Get models by year and make
|
|
CREATE OR REPLACE VIEW models_by_year_make AS
|
|
SELECT DISTINCT year, make, model
|
|
FROM vehicle_options
|
|
ORDER BY year DESC, make ASC, model ASC;
|
|
|
|
-- View: Get trims by year, make, and model
|
|
CREATE OR REPLACE VIEW trims_by_year_make_model AS
|
|
SELECT DISTINCT year, make, model, trim
|
|
FROM vehicle_options
|
|
ORDER BY year DESC, make ASC, model ASC, trim ASC;
|
|
|
|
-- View: Get complete vehicle configurations with engine and transmission details
|
|
CREATE OR REPLACE VIEW complete_vehicle_configs AS
|
|
SELECT
|
|
vo.id,
|
|
vo.year,
|
|
vo.make,
|
|
vo.model,
|
|
vo.trim,
|
|
e.name AS engine_name,
|
|
e.displacement,
|
|
e.configuration,
|
|
e.horsepower,
|
|
e.torque,
|
|
e.fuel_type,
|
|
t.type AS transmission_type,
|
|
t.speeds AS transmission_speeds,
|
|
t.drive_type
|
|
FROM vehicle_options vo
|
|
LEFT JOIN engines e ON vo.engine_id = e.id
|
|
LEFT JOIN transmissions t ON vo.transmission_id = t.id
|
|
ORDER BY vo.year DESC, vo.make ASC, vo.model ASC, vo.trim ASC;
|
|
|
|
-- Function to get makes for a specific year
|
|
CREATE OR REPLACE FUNCTION get_makes_for_year(p_year INTEGER)
|
|
RETURNS TABLE(make VARCHAR) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT DISTINCT vehicle_options.make
|
|
FROM vehicle_options
|
|
WHERE vehicle_options.year = p_year
|
|
ORDER BY vehicle_options.make ASC;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Function to get models for a specific year and make
|
|
CREATE OR REPLACE FUNCTION get_models_for_year_make(p_year INTEGER, p_make VARCHAR)
|
|
RETURNS TABLE(model VARCHAR) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT DISTINCT vehicle_options.model
|
|
FROM vehicle_options
|
|
WHERE vehicle_options.year = p_year
|
|
AND vehicle_options.make = p_make
|
|
ORDER BY vehicle_options.model ASC;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Function to get trims for a specific year, make, and model
|
|
CREATE OR REPLACE FUNCTION get_trims_for_year_make_model(p_year INTEGER, p_make VARCHAR, p_model VARCHAR)
|
|
RETURNS TABLE(trim_name VARCHAR) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT DISTINCT vehicle_options.trim
|
|
FROM vehicle_options
|
|
WHERE vehicle_options.year = p_year
|
|
AND vehicle_options.make = p_make
|
|
AND vehicle_options.model = p_model
|
|
ORDER BY vehicle_options.trim ASC;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Function to get engine and transmission options for a specific vehicle
|
|
CREATE OR REPLACE FUNCTION get_options_for_vehicle(p_year INTEGER, p_make VARCHAR, p_model VARCHAR, p_trim VARCHAR)
|
|
RETURNS TABLE(
|
|
engine_name VARCHAR,
|
|
engine_displacement VARCHAR,
|
|
engine_horsepower VARCHAR,
|
|
transmission_type VARCHAR,
|
|
transmission_speeds VARCHAR,
|
|
drive_type VARCHAR
|
|
) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT
|
|
e.name,
|
|
e.displacement,
|
|
e.horsepower,
|
|
t.type,
|
|
t.speeds,
|
|
t.drive_type
|
|
FROM vehicle_options vo
|
|
LEFT JOIN engines e ON vo.engine_id = e.id
|
|
LEFT JOIN transmissions t ON vo.transmission_id = t.id
|
|
WHERE vo.year = p_year
|
|
AND vo.make = p_make
|
|
AND vo.model = p_model
|
|
AND vo.trim = p_trim;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
-- Helper functions for trim-level options and pair-safe filtering
|
|
CREATE OR REPLACE FUNCTION get_transmissions_for_vehicle(p_year INTEGER, p_make VARCHAR, p_model VARCHAR, p_trim VARCHAR)
|
|
RETURNS TABLE(
|
|
transmission_id INTEGER,
|
|
transmission_type VARCHAR
|
|
) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT DISTINCT
|
|
t.id,
|
|
t.type
|
|
FROM vehicle_options vo
|
|
JOIN transmissions t ON vo.transmission_id = t.id
|
|
WHERE vo.year = p_year
|
|
AND vo.make = p_make
|
|
AND vo.model = p_model
|
|
AND vo.trim = p_trim
|
|
ORDER BY t.type ASC;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE OR REPLACE FUNCTION get_engines_for_vehicle(p_year INTEGER, p_make VARCHAR, p_model VARCHAR, p_trim VARCHAR)
|
|
RETURNS TABLE(
|
|
engine_id INTEGER,
|
|
engine_name VARCHAR
|
|
) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT DISTINCT
|
|
e.id,
|
|
e.name
|
|
FROM vehicle_options vo
|
|
JOIN engines e ON vo.engine_id = e.id
|
|
WHERE vo.year = p_year
|
|
AND vo.make = p_make
|
|
AND vo.model = p_model
|
|
AND vo.trim = p_trim
|
|
ORDER BY e.name ASC;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE OR REPLACE FUNCTION get_transmissions_for_vehicle_engine(p_year INTEGER, p_make VARCHAR, p_model VARCHAR, p_trim VARCHAR, p_engine_name VARCHAR)
|
|
RETURNS TABLE(
|
|
transmission_id INTEGER,
|
|
transmission_type VARCHAR
|
|
) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT DISTINCT
|
|
t.id,
|
|
t.type
|
|
FROM vehicle_options vo
|
|
JOIN engines e ON vo.engine_id = e.id
|
|
JOIN transmissions t ON vo.transmission_id = t.id
|
|
WHERE vo.year = p_year
|
|
AND vo.make = p_make
|
|
AND vo.model = p_model
|
|
AND vo.trim = p_trim
|
|
AND e.name = p_engine_name
|
|
ORDER BY t.type ASC;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
CREATE OR REPLACE FUNCTION get_engines_for_vehicle_trans(p_year INTEGER, p_make VARCHAR, p_model VARCHAR, p_trim VARCHAR, p_trans_type VARCHAR)
|
|
RETURNS TABLE(
|
|
engine_id INTEGER,
|
|
engine_name VARCHAR
|
|
) AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
SELECT DISTINCT
|
|
e.id,
|
|
e.name
|
|
FROM vehicle_options vo
|
|
JOIN engines e ON vo.engine_id = e.id
|
|
JOIN transmissions t ON vo.transmission_id = t.id
|
|
WHERE vo.year = p_year
|
|
AND vo.make = p_make
|
|
AND vo.model = p_model
|
|
AND vo.trim = p_trim
|
|
AND t.type = p_trans_type
|
|
ORDER BY e.name ASC;
|
|
END;
|
|
$$ LANGUAGE plpgsql;
|
|
|
|
COMMENT ON TABLE vehicle_options IS 'Denormalized table optimized for cascading dropdown queries';
|
|
COMMENT ON TABLE engines IS 'Engine specifications with detailed technical data';
|
|
COMMENT ON TABLE transmissions IS 'Transmission specifications';
|
|
COMMENT ON VIEW available_years IS 'Returns all distinct years available in the database';
|
|
COMMENT ON VIEW makes_by_year IS 'Returns makes grouped by year for dropdown population';
|
|
COMMENT ON VIEW models_by_year_make IS 'Returns models grouped by year and make';
|
|
COMMENT ON VIEW trims_by_year_make_model IS 'Returns trims grouped by year, make, and model';
|
|
COMMENT ON VIEW complete_vehicle_configs IS 'Complete vehicle configurations with all details';
|