# Guía Metabase — Nexus Autoparts ## 1. Conexión a la Base de Datos ### Datos de conexión PostgreSQL | Campo | Valor | |-------|-------| | **Host** | `localhost` (o la IP del servidor: `192.168.10.198`) | | **Puerto** | `5432` | | **Base de datos** | `nexus_autoparts` | | **Usuario** | `nexus` | | **Contraseña** | `nexus_autoparts_2026` | | **SSL** | No requerido (conexión local) | ### Pasos en Metabase 1. Ir a **Admin** → **Databases** → **Add database** 2. Seleccionar **PostgreSQL** 3. Llenar los campos con los datos anteriores 4. Click **Save** 5. Metabase sincronizará las tablas automáticamente (~30 segundos) > **Tip:** Si Metabase está en otro servidor, usar la IP `192.168.10.198` en lugar de `localhost`. --- ## 2. Estructura de la Base de Datos ### Diagrama de relaciones simplificado ``` brands ──→ models ──→ model_year_engine (MYE) ←── years ↑ ↑ ↑ engines │ vehicle_parts ──→ parts │ ↑ vehicle_diagrams part_cross_references ↓ aftermarket_parts diagrams diagram_hotspots ``` ### Tablas principales (con datos) | Tabla | Registros | Descripción | |-------|-----------|-------------| | `brands` | 102 | Marcas de vehículos | | `models` | 4,031 | Modelos por marca | | `years` | 80 | Años (1946-2026) | | `engines` | 13,430 | Motores con specs | | `model_year_engine` | 47,858 | Combinación marca-modelo-año-motor | ### Tablas de piezas (vacías — para llenar) | Tabla | Descripción | |-------|-------------| | `parts` | Piezas OEM (número de parte, nombre, grupo) | | `vehicle_parts` | Relación pieza ↔ vehículo (fitments) | | `aftermarket_parts` | Piezas aftermarket por fabricante | | `part_cross_references` | Intercambios y referencias cruzadas | | `manufacturers` | 47 fabricantes ya cargados | ### Tablas lookup (catálogos de referencia) | Tabla | Valores actuales | |-------|-----------------| | `part_categories` | 12: Body, Brake, Cooling, Drivetrain, Electrical, Engine, Exhaust, Fuel, HVAC, Steering, Suspension, Transmission | | `part_groups` | 63 grupos dentro de las categorías | | `quality_tier` | economy, standard, oem, premium | | `reference_type` | competitor, interchange, oem_alternate, supersession | | `position_part` | front, rear | | `manufacture_type` | aftermarket, oem | | `materials` | (vacía — agregar según se necesite) | --- ## 3. Alta de Piezas OEM ### Orden obligatorio de carga ``` 1. materials (si aplica) 2. parts ← PRIMERO las piezas 3. vehicle_parts ← DESPUÉS los fitments 4. aftermarket_parts 5. part_cross_references ``` > **IMPORTANTE:** Respetar este orden. `vehicle_parts` y `aftermarket_parts` requieren que la pieza ya exista en `parts`. --- ### 3.1 Agregar una pieza OEM (`parts`) En Metabase: click **+ New** → **SQL query** → ejecutar: ```sql INSERT INTO parts (oem_part_number, name_part, name_es, group_id, description, description_es, weight_kg, id_material) VALUES ( '04465-06090', -- Número OEM (obligatorio, único por grupo) 'Front Brake Pad Set', -- Nombre en inglés (obligatorio) 'Juego de Balatas Delanteras', -- Nombre en español (opcional) 16, -- group_id: 16 = Brake Pads (ver tabla abajo) 'Ceramic brake pad set for front axle', -- Descripción EN (opcional) 'Juego de balatas cerámicas para eje delantero', -- Descripción ES (opcional) 1.2, -- Peso en kg (opcional) NULL -- id_material (opcional, ver tabla materials) ); ``` ### Carga masiva de piezas ```sql INSERT INTO parts (oem_part_number, name_part, name_es, group_id, description) VALUES ('04465-06090', 'Front Brake Pad Set', 'Juego Balatas Delanteras', 16, 'Ceramic front pads'), ('04465-33471', 'Front Brake Pad Set', 'Juego Balatas Delanteras', 16, 'Semi-metallic front pads'), ('43512-06150', 'Front Brake Rotor', 'Disco de Freno Delantero', 17, 'Vented front rotor 296mm'), ('19101-28491', 'Radiator', 'Radiador', 31, 'Aluminum core radiator'), ('16400-28531', 'Cooling Fan Assembly', 'Ensamble Ventilador', 35, 'Electric cooling fan') ON CONFLICT DO NOTHING; ``` ### Referencia de `group_id` (grupos de piezas) | group_id | Grupo | Categoría | |----------|-------|-----------| | **Frenos y Ruedas** | | | | 16 | Brake Pads | Brake & Wheel Hub | | 17 | Brake Rotors | Brake & Wheel Hub | | 20 | Brake Calipers | Brake & Wheel Hub | | 27 | Wheel Bearings | Brake & Wheel Hub | | 28 | Wheel Hubs | Brake & Wheel Hub | | **Motor** | | | | 70 | Oil Filters | Engine | | 71 | Air Filters | Engine | | 72 | Spark Plugs | Engine | | 73 | Belts | Engine | | 76 | Timing Components | Engine | | 91 | Engine Mounts | Engine | | **Enfriamiento** | | | | 31 | Radiators | Cooling System | | 33 | Water Pumps | Cooling System | | 34 | Thermostats | Cooling System | | 35 | Cooling Fans | Cooling System | | **Eléctrico** | | | | 55 | Alternators | Electrical & Lighting | | 56 | Starters | Electrical & Lighting | | 57 | Ignition Coils | Electrical & Lighting | | 65 | Sensors | Electrical & Lighting | | **Combustible** | | | | 110 | Fuel Pumps | Fuel & Air | | 111 | Fuel Filters | Fuel & Air | | 112 | Fuel Injectors | Fuel & Air | | **Escape** | | | | 99 | Catalytic Converters | Exhaust | | 100 | Mufflers | Exhaust | | 108 | Headers | Exhaust | | **Dirección** | | | | 141 | Power Steering Pumps | Steering | | 144 | Steering Racks | Steering | | 145 | Steering Gearboxes | Steering | | 146 | Tie Rods | Steering | | 147 | Tie Rod Ends | Steering | | 148 | Inner Tie Rods | Steering | | 151 | Pitman Arms | Steering | | 152 | Idler Arms | Steering | | 153 | Center Links | Steering | | 154 | Drag Links | Steering | | 155 | Steering Knuckles | Steering | | 191 | Steering Dampers | Steering | | **Suspensión** | | | | 156 | Shocks | Suspension | | 157 | Struts | Suspension | | 158 | Strut Mounts | Suspension | | 159 | Coil Springs | Suspension | | 160 | Leaf Springs | Suspension | | 161 | Control Arms | Suspension | | 164 | Ball Joints | Suspension | | 165 | Bushings | Suspension | | 167 | Sway Bar Links | Suspension | | 168 | Sway Bar Bushings | Suspension | | 169 | Torsion Bars | Suspension | | 170 | Trailing Arms | Suspension | | **Transmisión** | | | | 175 | Transmission Filters | Transmission | | 185 | Transmission Mounts | Transmission | | **A/C y Calefacción** | | | | 127 | AC Compressors | Heat & Air Conditioning | | 135 | Blower Motors | Heat & Air Conditioning | | 138 | Cabin Air Filters | Heat & Air Conditioning | | **Tren Motriz** | | | | 44 | CV Axles | Drivetrain | | 45 | CV Joints | Drivetrain | | 50 | Axle Shafts | Drivetrain | | **Carrocería** | | | | 15 | Moldings & Trim | Body & Lamp Assembly | --- ## 4. Alta de Fitments (Pieza ↔ Vehículo) Un fitment vincula una pieza con un vehículo específico (combinación modelo-año-motor). ### 4.1 Encontrar el `id_mye` del vehículo ```sql -- Buscar el id_mye para un vehículo específico SELECT mye.id_mye, b.name_brand, m.name_model, y.year_car, e.name_engine FROM model_year_engine mye JOIN models m ON mye.model_id = m.id_model JOIN brands b ON m.brand_id = b.id_brand JOIN years y ON mye.year_id = y.id_year JOIN engines e ON mye.engine_id = e.id_engine WHERE b.name_brand ILIKE 'Toyota' AND m.name_model ILIKE 'Camry' AND y.year_car = 2020 ORDER BY e.name_engine; ``` ### 4.2 Encontrar el `id_part` de la pieza ```sql -- Buscar pieza por número OEM SELECT id_part, oem_part_number, name_part FROM parts WHERE oem_part_number = '04465-06090'; ``` ### 4.3 Crear el fitment (`vehicle_parts`) ```sql INSERT INTO vehicle_parts (model_year_engine_id, part_id, quantity_required, id_position_part, fitment_notes) VALUES ( 12345, -- id_mye del vehículo (del paso 4.1) 67890, -- id_part de la pieza (del paso 4.2) 1, -- Cantidad requerida (1 juego) 1, -- Posición: 1 = front, 2 = rear (ver position_part) 'Fits all trim levels' -- Notas de compatibilidad (opcional) ); ``` ### 4.4 Fitment masivo (misma pieza en varios vehículos) ```sql -- Ejemplo: Balata 04465-06090 compatible con todos los Camry 2018-2023 INSERT INTO vehicle_parts (model_year_engine_id, part_id, quantity_required, id_position_part) SELECT mye.id_mye, (SELECT id_part FROM parts WHERE oem_part_number = '04465-06090'), 1, -- cantidad 1 -- posición: front FROM model_year_engine mye JOIN models m ON mye.model_id = m.id_model JOIN brands b ON m.brand_id = b.id_brand JOIN years y ON mye.year_id = y.id_year WHERE b.name_brand = 'TOYOTA' AND m.name_model = 'Camry' AND y.year_car BETWEEN 2018 AND 2023 ON CONFLICT DO NOTHING; ``` ### Valores de `position_part` | id_position_part | Nombre | |-----------------|--------| | 1 | front | | 2 | rear | > Para agregar más posiciones (left, right, upper, lower): > ```sql > INSERT INTO position_part (name_position_part) VALUES ('left'), ('right'), ('upper'), ('lower'); > ``` --- ## 5. Alta de Piezas Aftermarket Vincula una pieza aftermarket con su equivalente OEM y el fabricante. ### 5.1 Crear pieza aftermarket (`aftermarket_parts`) ```sql INSERT INTO aftermarket_parts ( oem_part_id, manufacturer_id, part_number, name_aftermarket_parts, name_es, id_quality_tier, price_usd, warranty_months ) VALUES ( 67890, -- id_part de la pieza OEM equivalente (de tabla parts) 3, -- id_manufacture del fabricante (ver manufacturers) 'CXD1293', -- Número de parte aftermarket 'Ceramic Brake Pad Set', -- Nombre EN 'Juego Balatas Cerámicas', -- Nombre ES 3, -- Calidad: 1=economy, 2=oem, 3=premium, 4=standard 45.99, -- Precio USD 24 -- Garantía en meses ); ``` ### 5.2 Carga masiva aftermarket ```sql INSERT INTO aftermarket_parts (oem_part_id, manufacturer_id, part_number, name_aftermarket_parts, id_quality_tier, price_usd, warranty_months) VALUES (67890, 3, 'CXD1293', 'Premium Ceramic Brake Pad', 3, 45.99, 24), (67890, 5, 'MKD1293', 'Economy Semi-Metallic Brake Pad', 1, 22.50, 12), (67890, 8, 'PBR1293', 'OEM Replacement Brake Pad', 2, 38.00, 18) ON CONFLICT DO NOTHING; ``` ### Referencia de `quality_tier` | id_quality_tier | Nombre | Descripción | |----------------|--------|-------------| | 1 | economy | Económica, calidad básica | | 2 | oem | Calidad equivalente al original | | 3 | premium | Calidad superior al original | | 4 | standard | Calidad estándar del mercado | ### Consultar fabricantes existentes ```sql SELECT m.id_manufacture, m.name_manufacture, mt.name_type_manu AS tipo, qt.name_quality AS calidad, c.name_country AS pais FROM manufacturers m LEFT JOIN manufacture_type mt ON m.id_type_manu = mt.id_type_manu LEFT JOIN quality_tier qt ON m.id_quality_tier = qt.id_quality_tier LEFT JOIN countries c ON m.id_country = c.id_country ORDER BY m.name_manufacture; ``` ### Agregar un nuevo fabricante ```sql INSERT INTO manufacturers (name_manufacture, id_type_manu, id_quality_tier, id_country, website) VALUES ( 'BREMBO', 1, -- 1=aftermarket, 2=oem 3, -- 1=economy, 2=oem, 3=premium, 4=standard NULL, -- id_country (buscar en tabla countries o agregar) 'https://www.brembo.com' ); ``` --- ## 6. Alta de Referencias Cruzadas / Intercambios Las cross-references vinculan una pieza OEM con números de parte alternativos. ### 6.1 Crear referencia cruzada (`part_cross_references`) ```sql INSERT INTO part_cross_references (part_id, cross_reference_number, id_ref_type, source_ref, notes) VALUES ( 67890, -- id_part de la pieza OEM 'D1293', -- Número de referencia cruzada 2, -- Tipo: 2 = interchange (ver tabla abajo) 'Wagner Catalog', -- Fuente de la referencia (opcional) 'Direct replacement' -- Notas (opcional) ); ``` ### 6.2 Carga masiva de cross-references ```sql INSERT INTO part_cross_references (part_id, cross_reference_number, id_ref_type, source_ref) VALUES (67890, 'D1293', 2, 'Wagner'), -- interchange (67890, '04465-06100', 3, 'Toyota'), -- oem_alternate (número OEM alterno) (67890, 'BC1293', 1, 'Akebono'), -- competitor (67890, '04465-06080', 4, 'Toyota') -- supersession (reemplaza a esta) ON CONFLICT DO NOTHING; ``` ### Valores de `reference_type` | id_ref_type | Nombre | Uso | |------------|--------|-----| | 1 | competitor | Número equivalente de competidor | | 2 | interchange | Intercambio directo compatible | | 3 | oem_alternate | Número OEM alterno del mismo fabricante | | 4 | supersession | El número OEM que esta pieza reemplaza | --- ## 7. Alta de Materiales Si necesitas especificar el material de una pieza: ```sql -- Agregar materiales INSERT INTO materials (name_material) VALUES ('Steel'), ('Aluminum'), ('Ceramic'), ('Rubber'), ('Cast Iron'), ('Stainless Steel'), ('Copper'), ('Plastic') ON CONFLICT (name_material) DO NOTHING; -- Luego, al crear una pieza, usar el id_material correspondiente: -- SELECT id_material FROM materials WHERE name_material = 'Ceramic'; ``` --- ## 8. Queries Útiles para Metabase (Dashboards) ### Vista completa de una pieza con todos sus datos ```sql SELECT p.oem_part_number AS "Número OEM", p.name_part AS "Nombre EN", p.name_es AS "Nombre ES", pg.name_part_group AS "Grupo", pc.name_part_category AS "Categoría", p.weight_kg AS "Peso (kg)", mat.name_material AS "Material", COUNT(DISTINCT vp.model_year_engine_id) AS "Vehículos compatibles", COUNT(DISTINCT ap.id_aftermarket_parts) AS "Opciones aftermarket", COUNT(DISTINCT pcr.id_part_cross_ref) AS "Cross-references" FROM parts p JOIN part_groups pg ON p.group_id = pg.id_part_group JOIN part_categories pc ON pg.category_id = pc.id_part_category LEFT JOIN materials mat ON p.id_material = mat.id_material LEFT JOIN vehicle_parts vp ON vp.part_id = p.id_part LEFT JOIN aftermarket_parts ap ON ap.oem_part_id = p.id_part LEFT JOIN part_cross_references pcr ON pcr.part_id = p.id_part GROUP BY p.id_part, p.oem_part_number, p.name_part, p.name_es, pg.name_part_group, pc.name_part_category, p.weight_kg, mat.name_material ORDER BY pc.name_part_category, pg.name_part_group, p.name_part; ``` ### Catálogo de piezas por vehículo ```sql SELECT b.name_brand AS "Marca", m.name_model AS "Modelo", y.year_car AS "Año", e.name_engine AS "Motor", pc.name_part_category AS "Categoría", pg.name_part_group AS "Grupo", p.oem_part_number AS "# OEM", p.name_part AS "Pieza", vp.quantity_required AS "Cantidad", pp.name_position_part AS "Posición" FROM vehicle_parts vp JOIN model_year_engine mye ON vp.model_year_engine_id = mye.id_mye JOIN models m ON mye.model_id = m.id_model JOIN brands b ON m.brand_id = b.id_brand JOIN years y ON mye.year_id = y.id_year JOIN engines e ON mye.engine_id = e.id_engine JOIN parts p ON vp.part_id = p.id_part JOIN part_groups pg ON p.group_id = pg.id_part_group JOIN part_categories pc ON pg.category_id = pc.id_part_category LEFT JOIN position_part pp ON vp.id_position_part = pp.id_position_part WHERE b.name_brand ILIKE '{{marca}}' AND m.name_model ILIKE '{{modelo}}' ORDER BY pc.display_order, pg.display_order, p.name_part; ``` > En Metabase, `{{marca}}` y `{{modelo}}` se convierten en filtros interactivos. ### Piezas aftermarket con precios ```sql SELECT p.oem_part_number AS "OEM #", p.name_part AS "Pieza OEM", mfr.name_manufacture AS "Fabricante", ap.part_number AS "# Aftermarket", ap.name_aftermarket_parts AS "Nombre", qt.name_quality AS "Calidad", ap.price_usd AS "Precio USD", ap.warranty_months AS "Garantía (meses)" FROM aftermarket_parts ap JOIN parts p ON ap.oem_part_id = p.id_part JOIN manufacturers mfr ON ap.manufacturer_id = mfr.id_manufacture LEFT JOIN quality_tier qt ON ap.id_quality_tier = qt.id_quality_tier ORDER BY p.oem_part_number, qt.name_quality DESC, ap.price_usd; ``` ### Cross-references de una pieza ```sql SELECT p.oem_part_number AS "OEM #", p.name_part AS "Pieza", pcr.cross_reference_number AS "# Referencia", rt.name_ref_type AS "Tipo", pcr.source_ref AS "Fuente", pcr.notes AS "Notas" FROM part_cross_references pcr JOIN parts p ON pcr.part_id = p.id_part LEFT JOIN reference_type rt ON pcr.id_ref_type = rt.id_ref_type WHERE p.oem_part_number = '{{numero_oem}}' ORDER BY rt.name_ref_type, pcr.cross_reference_number; ``` ### Estadísticas generales ```sql SELECT (SELECT COUNT(*) FROM parts) AS "Total piezas", (SELECT COUNT(*) FROM vehicle_parts) AS "Total fitments", (SELECT COUNT(*) FROM aftermarket_parts) AS "Total aftermarket", (SELECT COUNT(*) FROM part_cross_references) AS "Total cross-refs", (SELECT COUNT(*) FROM manufacturers) AS "Total fabricantes", (SELECT COUNT(DISTINCT model_year_engine_id) FROM vehicle_parts) AS "Vehículos con piezas"; ``` --- ## 9. Flujo Completo: Ejemplo Paso a Paso ### Dar de alta "Balata delantera Toyota Camry 2020" **Paso 1:** Agregar la pieza OEM ```sql INSERT INTO parts (oem_part_number, name_part, name_es, group_id) VALUES ('04465-06090', 'Front Brake Pad Set', 'Juego Balatas Delanteras', 16) RETURNING id_part; -- Resultado: id_part = 1 (anotar este ID) ``` **Paso 2:** Buscar los vehículos compatibles ```sql SELECT mye.id_mye, y.year_car, e.name_engine FROM model_year_engine mye JOIN models m ON mye.model_id = m.id_model JOIN brands b ON m.brand_id = b.id_brand JOIN years y ON mye.year_id = y.id_year JOIN engines e ON mye.engine_id = e.id_engine WHERE b.name_brand = 'TOYOTA' AND m.name_model = 'Camry' AND y.year_car BETWEEN 2018 AND 2023; -- Resultado: lista de id_mye para cada configuración ``` **Paso 3:** Crear los fitments ```sql INSERT INTO vehicle_parts (model_year_engine_id, part_id, quantity_required, id_position_part) SELECT mye.id_mye, 1, 1, 1 -- id_part=1, qty=1, position=front FROM model_year_engine mye JOIN models m ON mye.model_id = m.id_model JOIN brands b ON m.brand_id = b.id_brand JOIN years y ON mye.year_id = y.id_year WHERE b.name_brand = 'TOYOTA' AND m.name_model = 'Camry' AND y.year_car BETWEEN 2018 AND 2023 ON CONFLICT DO NOTHING; ``` **Paso 4:** Agregar opciones aftermarket ```sql INSERT INTO aftermarket_parts (oem_part_id, manufacturer_id, part_number, name_aftermarket_parts, id_quality_tier, price_usd, warranty_months) VALUES (1, 3, 'CXD1293', 'Premium Ceramic Pad', 3, 45.99, 24), (1, 5, 'MKD1293', 'Economy Brake Pad', 1, 22.50, 12); ``` **Paso 5:** Agregar cross-references ```sql INSERT INTO part_cross_references (part_id, cross_reference_number, id_ref_type, source_ref) VALUES (1, 'D1293', 2, 'Wagner'), (1, 'BC1293', 1, 'Akebono'), (1, '04465-06100', 3, 'Toyota OEM Alternate'); ``` --- ## 10. Notas Importantes ### Restricciones únicas (evitan duplicados) - `parts`: No tiene constraint único en `oem_part_number` (puede haber mismo OEM en diferentes grupos) - `vehicle_parts`: Único por `(model_year_engine_id, part_id, id_position_part)` - `vehicle_diagrams`: Único por `(diagram_id, model_year_engine_id)` - `model_year_engine`: Único por `(model_id, year_id, engine_id, trim_level)` ### Búsqueda full-text La tabla `parts` tiene un trigger que auto-genera `search_vector` al insertar/actualizar. Esto permite búsquedas rápidas en español: ```sql SELECT * FROM parts WHERE search_vector @@ plainto_tsquery('spanish', 'balata delantera'); ``` ### Para agregar nuevas categorías o grupos ```sql -- Nueva categoría INSERT INTO part_categories (name_part_category, name_es, display_order) VALUES ('Interior', 'Interior', 13); -- Nuevo grupo dentro de una categoría INSERT INTO part_groups (category_id, name_part_group, name_es, display_order) VALUES (1, 'Headlights', 'Faros Delanteros', 10); -- (category_id 1 = Body & Lamp Assembly) ``` ### Para agregar un país (para fabricantes) ```sql INSERT INTO countries (name_country) VALUES ('Italy') ON CONFLICT (name_country) DO NOTHING; ```