Base de Datos Servicios
-- =================================================
-- Tipos de datos enumerados
-- =================================================
CREATE TYPE property_type AS ENUM ('casa', 'departamento', 'garaje', 'trastero', 'local', 'oficina');
CREATE TYPE service_type AS ENUM ('fontanería', 'electricidad', 'albañilería', 'pintura', 'carpintería', 'limpieza', 'jardinería', 'otros');
CREATE TYPE role_type AS ENUM ('inquilino', 'propietario', 'empresa', 'técnico', 'gestor');
CREATE TYPE doc_type AS ENUM ('foto', 'pdf', 'factura', 'contrato', 'certificado');
CREATE TYPE request_status AS ENUM ('abierto', 'asignado', 'en_proceso', 'completado', 'cancelado');
-- =================================================
-- Tablas principales
-- =================================================
CREATE TABLE persons (
person_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE,
phone VARCHAR(20),
role role_type NOT NULL,
nif VARCHAR(20) UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE properties (
property_id SERIAL PRIMARY KEY,
type property_type NOT NULL,
address TEXT NOT NULL,
city VARCHAR(50),
postal_code VARCHAR(10),
description TEXT,
area_m2 NUMERIC(8,2),
purchase_date DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- =================================================
-- Tablas de gestión
-- =================================================
CREATE TABLE managers (
manager_id SERIAL PRIMARY KEY,
person_id INT NOT NULL UNIQUE REFERENCES persons(person_id),
department VARCHAR(50),
work_phone VARCHAR(20),
active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE manager_services (
manager_id INT REFERENCES managers(manager_id) ON DELETE CASCADE,
service_type service_type NOT NULL,
PRIMARY KEY (manager_id, service_type)
);
CREATE TABLE service_companies (
company_id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
service_types service_type[] NOT NULL,
contact_person_id INT REFERENCES persons(person_id),
hourly_rate NUMERIC(8,2),
certification_number VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE technicians (
technician_id SERIAL PRIMARY KEY,
person_id INT NOT NULL REFERENCES persons(person_id),
company_id INT REFERENCES service_companies(company_id),
specialty service_type NOT NULL,
certification_number VARCHAR(50),
active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- =================================================
-- Tablas de relaciones y operaciones
-- =================================================
CREATE TABLE insurances (
insurance_id SERIAL PRIMARY KEY,
property_id INT NOT NULL REFERENCES properties(property_id) ON DELETE CASCADE,
company_name VARCHAR(100) NOT NULL,
policy_number VARCHAR(50) UNIQUE NOT NULL,
coverage_details TEXT,
start_date DATE NOT NULL,
end_date DATE NOT NULL,
annual_premium NUMERIC(10,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CHECK (start_date < end_date)
);
CREATE TABLE leases (
lease_id SERIAL PRIMARY KEY,
property_id INT NOT NULL REFERENCES properties(property_id) ON DELETE CASCADE,
tenant_id INT NOT NULL REFERENCES persons(person_id),
owner_id INT NOT NULL REFERENCES persons(person_id),
start_date DATE NOT NULL,
end_date DATE NOT NULL,
monthly_rent NUMERIC(8,2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CHECK (start_date < end_date)
);
CREATE TABLE maintenance_requests (
request_id SERIAL PRIMARY KEY,
property_id INT NOT NULL REFERENCES properties(property_id) ON DELETE CASCADE,
reported_by INT NOT NULL REFERENCES persons(person_id),
service_type service_type NOT NULL,
description TEXT NOT NULL,
urgency_level INT NOT NULL CHECK (urgency_level BETWEEN 1 AND 5),
status request_status DEFAULT 'abierto',
assigned_manager INT REFERENCES managers(manager_id),
assignment_date TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
closed_at TIMESTAMP
);
CREATE TABLE assignment_history (
assignment_id SERIAL PRIMARY KEY,
request_id INT NOT NULL REFERENCES maintenance_requests(request_id) ON DELETE CASCADE,
manager_id INT NOT NULL REFERENCES managers(manager_id),
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
unassigned_at TIMESTAMP,
assignment_notes TEXT
);
CREATE TABLE work_orders (
order_id SERIAL PRIMARY KEY,
request_id INT NOT NULL REFERENCES maintenance_requests(request_id) ON DELETE CASCADE,
company_id INT REFERENCES service_companies(company_id),
technician_id INT REFERENCES technicians(technician_id),
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
estimated_cost NUMERIC(10,2),
actual_cost NUMERIC(10,2),
start_time TIMESTAMP,
end_time TIMESTAMP,
notes TEXT,
CHECK (estimated_cost >= 0 AND actual_cost >= 0)
);
CREATE TABLE documents (
document_id SERIAL PRIMARY KEY,
request_id INT REFERENCES maintenance_requests(request_id) ON DELETE CASCADE,
order_id INT REFERENCES work_orders(order_id) ON DELETE CASCADE,
insurance_id INT REFERENCES insurances(insurance_id) ON DELETE CASCADE,
lease_id INT REFERENCES leases(lease_id) ON DELETE CASCADE,
document_type doc_type NOT NULL,
file_path TEXT NOT NULL,
description TEXT,
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE service_history (
history_id SERIAL PRIMARY KEY,
property_id INT NOT NULL REFERENCES properties(property_id) ON DELETE CASCADE,
request_id INT REFERENCES maintenance_requests(request_id) ON DELETE SET NULL,
event_description TEXT NOT NULL,
event_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
responsible_person_id INT REFERENCES persons(person_id)
);
-- =================================================
-- Índices para optimización
-- =================================================
CREATE INDEX idx_properties_type ON properties(type);
CREATE INDEX idx_requests_status ON maintenance_requests(status);
CREATE INDEX idx_requests_urgency ON maintenance_requests(urgency_level);
CREATE INDEX idx_work_orders_company ON work_orders(company_id);
CREATE INDEX idx_technicians_specialty ON technicians(specialty);
CREATE INDEX idx_documents_type ON documents(document_type);
CREATE INDEX idx_service_history_date ON service_history(event_date);
CREATE INDEX idx_manager_services_type ON manager_services(service_type);
Estructura Completa Explicada
1. Entidades Principales:
persons: Todas las personas del sistema (inquilinos, propietarios, técnicos, gestores)properties: Todas las propiedades inmobiliariasmanagers: Gestores especializados (relación 1:1 conpersons)service_companies: Empresas de servicios con sus especialidadestechnicians: Técnicos especializados (relación conpersonsy empresas)
2. Gestión de Gestores:
manager_services: Asociación de gestores con tipos de servicioassignment_history: Historial completo de asignación de gestores- Campo
assigned_managerenmaintenance_requestspara el gestor actual
3. Ciclo de Averías:
maintenance_requests: Reporte inicial de averíawork_orders: Asignación a empresa/técnicodocuments: Evidencia fotográfica/documentalservice_history: Registro histórico de eventos
4. Relaciones Clave:
leases: Vincula propiedades con inquilinos y propietariosinsurances: Seguros asociados a propiedadesdocuments: Soporta múltiples relaciones (averías, seguros, contratos)
5. Optimizaciones:
- Índices en campos de búsqueda frecuente
- Enumerados para valores predefinidos
- Restricciones de integridad (CHECK, FK)
- ON DELETE CASCADE para mantener consistencia
Ejemplo de Flujo Completo
1. Reporte de Avería:
-- Insertar reporte
INSERT INTO maintenance_requests (
property_id,
reported_by,
service_type,
description,
urgency_level)
VALUES (
101,
202,
'fontanería',
'Fuga de agua en baño principal',
4)
RETURNING request_id;
2. Asignar Gestor:
-- Asignar gestor especializado
UPDATE maintenance_requests
SET assigned_manager = (
SELECT manager_id
FROM manager_services
WHERE service_type = 'fontanería'
LIMIT 1),
assignment_date = NOW()
WHERE request_id = 305;
-- Registrar en historial
INSERT INTO assignment_history (request_id, manager_id)
VALUES (305, 15);
3. Asignar Técnico:
INSERT INTO work_orders (
request_id,
company_id,
technician_id,
estimated_cost)
VALUES (
305,
42,
78,
150.00);
4. Registrar Documentos:
INSERT INTO documents (
request_id,
document_type,
file_path,
description)
VALUES
(305, 'foto', 's3://bucket/fuga_antes.jpg', 'Estado inicial de la fuga'),
(305, 'foto', 's3://bucket/fuga_despues.jpg', 'Reparación finalizada'),
(305, 'factura', 's3://bucket/factura_rep.pdf', 'Factura de reparación');
5. Cerrar Incidencia:
UPDATE maintenance_requests
SET status = 'completado', closed_at = NOW()
WHERE request_id = 305;
UPDATE work_orders
SET actual_cost = 145.50, end_time = NOW()
WHERE request_id = 305;
INSERT INTO service_history (
property_id,
request_id,
event_description,
responsible_person_id)
VALUES (
101,
305,
'Reparación de fuga completada con éxito',
78);
Ventajas de este Diseño
Trazabilidad Completa:
- Historial de asignación de gestores
- Registro temporal en todas las etapas
- Documentación vinculada a cada paso
Gestión Especializada:
- Gestores asignados por tipo de servicio
- Técnicos con especialidades definidas
- Empresas con múltiples servicios
Integridad de Datos:
- Relaciones con ON DELETE CASCADE
- Restricciones de dominio (enumerados)
- Validación de rangos y fechas
Rendimiento Optimizado:
- Índices en campos críticos
- Tipos de datos apropiados
- Normalización balanceada
Flexibilidad Documental:
- Soporte múltiples tipos de archivos
- Vinculación con diferentes entidades
- Metadatos descriptivos
Este diseño permite gestionar todo el ciclo de vida de los servicios inmobiliarios: desde el reporte inicial de averías hasta la solución final, incluyendo la gestión de gestores, documentación asociada y seguimiento histórico.
Datos de Ejemplo Completos para la Base de Datos
Aquí tienes un conjunto de datos de prueba que cubre todas las tablas y relaciones:
-- 1. Insertar personas
INSERT INTO persons (name, email, phone, role, nif) VALUES
('Laura Martínez', 'laura@example.com', '600111222', 'propietario', 'Y1234567A'),
('Carlos Rodríguez', 'carlos@example.com', '600222333', 'inquilino', 'Z7654321B'),
('Tecnirep S.L.', 'info@tecnirep.com', '910001122', 'empresa', 'A12345678'),
('Juan García', 'juan@tecnirep.com', '655000111', 'técnico', 'X11222333'),
('Sofía López', 'sofia@example.com', '677888999', 'gestor', 'B44555666'),
('Marta Jiménez', 'marta@example.com', '699000111', 'inquilino', 'C99888777'),
('Electroserv S.A.', 'contacto@electroserv.com', '915550000', 'empresa', 'B87654321'),
('Pedro Sánchez', 'pedro@electroserv.com', '622333444', 'técnico', 'D55444666'),
('Ana Ruiz', 'ana@example.com', '688777666', 'propietario', 'E11222333'),
('David Torres', 'david@example.com', '666999000', 'gestor', 'F44555666');
-- 2. Insertar propiedades
INSERT INTO properties (type, address, city, postal_code, area_m2) VALUES
('casa', 'Calle Principal 123', 'Madrid', '28001', 120.5),
('departamento', 'Avenida Libertad 45', 'Barcelona', '08001', 75.0),
('garaje', 'Calle Secundaria 8', 'Madrid', '28002', 15.0),
('trastero', 'Plaza Central 3', 'Valencia', '46001', 5.5);
-- 3. Insertar gestores
INSERT INTO managers (person_id, department, work_phone) VALUES
((SELECT person_id FROM persons WHERE name = 'Sofía López'), 'Mantenimiento', '910222333'),
((SELECT person_id FROM persons WHERE name = 'David Torres'), 'Emergencias', '910444555');
-- 4. Especialidades de gestores
INSERT INTO manager_services (manager_id, service_type) VALUES
(1, 'fontanería'),
(1, 'albañilería'),
(1, 'pintura'),
(2, 'electricidad'),
(2, 'fontanería');
-- 5. Empresas de servicios
INSERT INTO service_companies (name, service_types, contact_person_id, hourly_rate) VALUES
('Tecnirep S.L.', '{fontanería,albañilería,pintura}',
(SELECT person_id FROM persons WHERE name = 'Tecnirep S.L.'), 45.00),
('Electroserv S.A.', '{electricidad,carpintería}',
(SELECT person_id FROM persons WHERE name = 'Electroserv S.A.'), 50.00);
-- 6. Técnicos
INSERT INTO technicians (person_id, company_id, specialty) VALUES
((SELECT person_id FROM persons WHERE name = 'Juan García'), 1, 'fontanería'),
((SELECT person_id FROM persons WHERE name = 'Pedro Sánchez'), 2, 'electricidad'),
((SELECT person_id FROM persons WHERE name = 'Carlos Rodríguez'), 1, 'pintura');
-- 7. Seguros
INSERT INTO insurances (property_id, company_name, policy_number, start_date, end_date, annual_premium) VALUES
(1, 'Seguros Total', 'POL-2023-001', '2023-01-01', '2024-01-01', 350.00),
(2, 'Aseguradora Global', 'POL-2023-002', '2023-02-15', '2024-02-15', 220.00);
-- 8. Contratos de alquiler
INSERT INTO leases (property_id, tenant_id, owner_id, start_date, end_date, monthly_rent) VALUES
(1, (SELECT person_id FROM persons WHERE name = 'Carlos Rodríguez'),
(SELECT person_id FROM persons WHERE name = 'Laura Martínez'),
'2023-01-01', '2024-12-31', 850.00),
(2, (SELECT person_id FROM persons WHERE name = 'Marta Jiménez'),
(SELECT person_id FROM persons WHERE name = 'Ana Ruiz'),
'2023-03-01', '2024-03-01', 650.00);
-- 9. Reportes de averías
INSERT INTO maintenance_requests (property_id, reported_by, service_type, description, urgency_level) VALUES
(1, (SELECT person_id FROM persons WHERE name = 'Carlos Rodríguez'), 'fontanería',
'Fuga de agua en cocina', 4) RETURNING request_id;
INSERT INTO maintenance_requests (property_id, reported_by, service_type, description, urgency_level) VALUES
(2, (SELECT person_id FROM persons WHERE name = 'Marta Jiménez'), 'electricidad',
'Luz del baño no funciona', 3) RETURNING request_id;
-- 10. Asignar gestores a reportes
UPDATE maintenance_requests
SET assigned_manager = 1, assignment_date = NOW()
WHERE request_id = 1;
UPDATE maintenance_requests
SET assigned_manager = 2, assignment_date = NOW()
WHERE request_id = 2;
-- 11. Historial de asignaciones
INSERT INTO assignment_history (request_id, manager_id, assignment_notes) VALUES
(1, 1, 'Asignado por turno matutino'),
(2, 2, 'Asignado por especialidad eléctrica');
-- 12. Órdenes de trabajo
INSERT INTO work_orders (request_id, company_id, technician_id, estimated_cost) VALUES
(1, 1, 1, 120.00),
(2, 2, 2, 85.00);
-- 13. Documentos
INSERT INTO documents (request_id, document_type, file_path, description) VALUES
(1, 'foto', 's3://bucket/fuga_cocina.jpg', 'Foto inicial de la fuga'),
(1, 'factura', 's3://bucket/factura_fontaneria.pdf', 'Factura de reparación'),
(2, 'foto', 's3://bucket/luz_bano.jpg', 'Lámpara defectuosa');
-- 14. Historial de servicio
INSERT INTO service_history (property_id, request_id, event_description, responsible_person_id) VALUES
(1, 1, 'Reporte de fuga creado', (SELECT person_id FROM persons WHERE name = 'Carlos Rodríguez')),
(1, 1, 'Reparación completada', (SELECT person_id FROM persons WHERE name = 'Juan García'));
Consultas de Verificación
Para comprobar los datos insertados:
- Ver todas las averías con su estado:
SELECT
mr.request_id,
p.address AS propiedad,
per_reporter.name AS reportado_por,
mr.service_type,
mr.status,
per_manager.name AS gestor_asignado
FROM maintenance_requests mr
JOIN properties p ON mr.property_id = p.property_id
JOIN persons per_reporter ON mr.reported_by = per_reporter.person_id
LEFT JOIN managers m ON mr.assigned_manager = m.manager_id
LEFT JOIN persons per_manager ON m.person_id = per_manager.person_id;
- Ver documentos asociados a una avería:
SELECT
d.document_id,
d.document_type,
d.file_path,
d.description,
d.uploaded_at
FROM documents d
WHERE d.request_id = 1;
- Costo real vs estimado de reparaciones:
SELECT
wo.order_id,
p.address AS propiedad,
sc.name AS empresa,
t.person_id AS tecnico_id,
per_tech.name AS tecnico,
wo.estimated_cost,
wo.actual_cost
FROM work_orders wo
JOIN maintenance_requests mr ON wo.request_id = mr.request_id
JOIN properties p ON mr.property_id = p.property_id
LEFT JOIN service_companies sc ON wo.company_id = sc.company_id
LEFT JOIN technicians t ON wo.technician_id = t.technician_id
LEFT JOIN persons per_tech ON t.person_id = per_tech.person_id;
- Gestores y sus especialidades:
SELECT
p.name AS gestor,
m.department,
ms.service_type
FROM managers m
JOIN persons p ON m.person_id = p.person_id
JOIN manager_services ms ON m.manager_id = ms.manager_id;
Datos Generados
Este conjunto de datos incluye:
- 4 propiedades: 1 casa, 1 departamento, 1 garaje, 1 trastero
- 10 personas: 2 propietarios, 2 inquilinos, 2 gestores, 2 empresas, 3 técnicos
- 2 empresas de servicios con diferentes especialidades
- 2 reportes de averías (fontanería y electricidad)
- 2 órdenes de trabajo asignadas
- 3 documentos (fotos y facturas)
- 2 seguros para propiedades
- 2 contratos de alquiler
- Historial completo de asignaciones y eventos
Ejecutar estas sentencias en orden para tener una base de datos de prueba completamente funcional que refleje todos los aspectos del sistema.