DQL

Vistas y Vistas Materializadas

Las vistas son una de las herramientas más potentes para la abstracción de datos y la seguridad en una arquitectura de base de datos.

Una Vista no es simplemente “una consulta guardada”. Es una tabla virtual cuya definición reside en el diccionario de datos de la base de datos, pero que no almacena datos físicamente (a diferencia de las tablas base). Actúa como una capa de interfaz que simplifica la complejidad del esquema subyacente.

¿Por qué usar Vistas?

En el diseño de sistemas avanzados, las vistas cumplen tres funciones críticas:

  • Abstracción y Simplicidad: Permiten que los usuarios finales o los desarrolladores de aplicaciones consulten resultados complejos (con múltiples JOINs y CASE WHEN) como si fueran una simple tabla.
  • Seguridad y Control de Acceso: Puedes otorgar permisos a un usuario para ver una Vista que contiene solo 3 columnas de una tabla que tiene 50, protegiendo datos sensibles (como salarios o contraseñas).
  • Independencia Lógica de Datos: Si la estructura de las tablas base cambia (por ejemplo, divides una tabla en dos), puedes actualizar la definición de la Vista para que las aplicaciones que la consultan no dejen de funcionar.

Gestión de Vistas en PostgreSQL (Procedimientos DDL)

PostgreSQL ofrece una sintaxis robusta para gestionar el ciclo de vida de las vistas.

En los siguientes ejemplos se trabaja sobre el siguiente esquema sencillo de un hospital

A. Crear una Vista (CREATE VIEW)

Para crear una vista, definimos un nombre y le asignamos la consulta DQL que queremos encapsular.

Ejemplo: Vamos a crear una vista llamada resumen_ingresos_hospital basada en nuestro esquema anterior.

CREATE VIEW resumen_ingresos_hospital AS
SELECT 
    codigo_diagnostico,
    COUNT(*) AS total_atenciones,
    SUM(costo_base) AS ingresos_brutos
FROM atenciones
GROUP BY codigo_diagnostico;

B. Actualizar o Modificar una Vista (CREATE OR REPLACE)

En PostgreSQL, no existe un comando ALTER VIEW para cambiar la consulta interna. Se utiliza CREATE OR REPLACE VIEW.

Regla Profesional: Solo puedes usar OR REPLACE si vas a añadir columnas al final o cambiar la lógica interna. No puedes cambiar el nombre de las columnas existentes, el orden, ni sus tipos de datos. Si necesitas cambios estructurales profundos, debes borrarla y recrearla.1

CREATE OR REPLACE VIEW resumen_ingresos_hospital AS
SELECT 
    codigo_diagnostico,
    COUNT(*) AS total_atenciones,
    SUM(costo_base) AS ingresos_brutos,
    ROUND(AVG(nivel_urgencia), 1) AS urgencia_promedio -- Añadimos una columna
FROM atenciones
GROUP BY codigo_diagnostico;

C. Eliminar una Vista (DROP VIEW)

Para eliminar la definición de la vista del diccionario de datos.

-- Uso básico
DROP VIEW IF EXISTS resumen_ingresos_hospital;

-- Uso avanzado (CASCADE)
-- Si otras vistas o reportes dependen de esta, CASCADE los eliminará también.
DROP VIEW resumen_ingresos_hospital CASCADE;

D. Consultar una Vista

Una vez creada, la vista se trata exactamente igual que una tabla en cualquier sentencia SELECT.

SELECT * FROM resumen_ingresos_hospital 
WHERE ingresos_brutos > 5000;

Vistas Actualizables (Simple vs. Complex)

PostgreSQL permite realizar INSERT, UPDATE o DELETE directamente sobre una vista bajo ciertas condiciones:

  1. La vista debe tener una sola tabla en la cláusula FROM.
  2. No debe contener funciones de agregación (SUM, AVG, COUNT), DISTINCT, GROUP BY o HAVING.

Para vistas complejas, se utilizan disparadores (Triggers) tipo INSTEAD OF.

Vistas Materializadas

En bases de datos con millones de registros, consultar una vista normal puede ser lento porque la consulta se ejecuta “en tiempo real”. PostgreSQL ofrece las Materialized Views, que sí guardan los datos físicamente en disco.

  • Ventaja: Velocidad de lectura instantánea.
  • Desventaja: Los datos no se actualizan solos; hay que refrescarlos manualmente.
-- Crear vista materializada
CREATE MATERIALIZED VIEW estadisticas_historicas AS
SELECT ... (consulta pesada) ...;

-- Refrescar los datos (por ejemplo, cada noche)
REFRESH MATERIALIZED VIEW estadisticas_historicas;

Práctica: Implementación de una “Capa de Privacidad” (Security View)

1. El Escenario

La dirección del hospital desea compartir datos con el departamento de estadística para analizar costos y urgencias. Sin embargo, por ley, está prohibido que el personal de estadística vea nombres completos o fechas exactas de nacimiento.

2. Requerimientos Técnicos

Debes crear una vista llamada v_metricas_anonimas que cumpla con:

  1. Ofuscación de Identidad: El nombre del paciente no debe aparecer. En su lugar, debe mostrarse la inicial del nombre seguido de asteriscos y el ID (ej: J******* (ID: 45)).
  2. Anonimización de Edad: No mostrar la fecha de nacimiento. Calcular la edad actual.
  3. Seguridad de Diagnóstico: Mostrar el código del diagnóstico y el nivel de urgencia.
  4. Cálculos Financieros: Mostrar el costo final de la atención (aplicando la lógica de recargos/subsidios que vimos antes).
  5. Filtro de Privacidad: Solo incluir registros de pacientes que tengan más de 18 años para evitar el manejo de datos de menores en esta vista.

3. Solución Propuesta

Esta consulta utiliza funciones de texto, matemáticas, fechas y lógica condicional dentro de la definición de la vista.

CREATE OR REPLACE VIEW v_metricas_anonimas AS
SELECT 
    -- 1. Ofuscación del nombre (Muestra la primera letra y oculta el resto)
    LEFT(TRIM(p.nombre_completo), 1) || '******* (ID: ' || p.id_paciente || ')' AS paciente_anonimo,
    
    -- 2. Transformación de fecha a edad (Dato menos sensible)
    EXTRACT(YEAR FROM AGE(p.fecha_nacimiento)) AS edad_paciente,
    
    p.genero,
    a.fecha_atencion::DATE AS fecha_servicio,
    a.codigo_diagnostico,
    
    -- 3. Lógica de negocio embebida
    CASE 
        WHEN a.nivel_urgencia <= 2 THEN 'CRÍTICO'
        WHEN a.nivel_urgencia BETWEEN 3 AND 4 THEN 'ESTABLE'
        ELSE 'CONTROL'
    END AS categoria_urgencia,
    
    -- 4. Cálculo financiero protegido
    ROUND(
        CASE 
            WHEN a.nivel_urgencia <= 2 THEN a.costo_base * 0.5
            WHEN a.nivel_urgencia = 5 THEN a.costo_base * 1.2
            ELSE a.costo_base
        END, 2
    ) AS costo_final

FROM pacientes p
JOIN atenciones a ON p.id_paciente = a.id_paciente
-- 5. Filtro de cumplimiento (Compliance)
WHERE EXTRACT(YEAR FROM AGE(p.fecha_nacimiento)) >= 18;

4. Ejercicios Complementarios

Una vez creada la vista, resuelver estos retos sobre la vista:

  1. Análisis de Costos por Edad: “Utilizando la vista, determinar cuál es el costo promedio de atención para el segmento de pacientes entre 30 y 50 años”.
  2. Verificación de Seguridad: “Realizar un SELECT * sobre la vista y explicar por qué es imposible identificar quién es el paciente que más gastó en el mes de marzo”.
  3. Prueba de Integridad: “¿Qué sucede con la vista si el departamento de sistemas añade una nueva columna llamada telefono a la tabla pacientes? ¿Se actualiza la vista automáticamente?”

  1. La razón no es un capricho de diseño, sino que se fundamenta en la integridad de las dependencias y la estructura del catálogo del sistema: Tuple Descriptor, la Cascada de Dependencias y Rules System. Comparativa para usar OR REPLACE:
    Sí – Cambiar la lógica de WHERE; no altera las columnas de salida
    Sí – Añadir columnas al final; no desplaza ni inválida las posiciones de las columnas anteriores
    No – Cambiar el nombre de columna; Rempe las referencias de objetos dependientes
    No – Cambiar el tipo de dato: Inválida el Tuple Descriptor registrado en el catálogo
    No – Cambiar el orden de columnas: PostgreSQL referencia columnas por posición interna en ciertos contextos ↩︎

Un comentario en “Vistas y Vistas Materializadas

Los comentarios están cerrados.