📊 Arquitectura del Modelo Analítico
Componentes principales:
1. Tabla de Hechos (Fact Table)
Datos operacionales granulares. Ejemplo: cada venta realizada con cantidad, precio, fecha, cliente.
Campos típicos: ID de venta, ID cliente, ID producto, fecha, cantidad, precio unitario, descuento.
2. Tablas de Dimensiones (Dimensions)
Contexto descriptivo de la venta. Se unen con la tabla de hechos mediante claves foráneas.
Ejemplos: Dimensión Cliente (nombre, ciudad, país), Dimensión Producto (nombre, categoría, precio lista), Dimensión Tiempo (año, mes, trimestre).
3. Medidas Calculadas (Measures)
Agregaciones y ratios que responden preguntas de negocio.
Ejemplos: Total vendido (SUM), promedio de descuento (AVG), margen % (SUM(ganancia)/SUM(ingresos)).
4. Variables & Parámetros (Input Parameters)
Filtros dinámicos que el usuario selecciona en reportes/dashboards.
Ejemplos: Rango de fechas, país seleccionado, categoría de producto, vendedor.
Flujo de datos en la Calculation View:
Tabla de Hechos (Sales)
↓
[Join] Dimensión Cliente
[Join] Dimensión Producto
[Join] Dimensión Tiempo
↓
Medidas Calculadas (SUM, AVG, Ratios)
↓
Atributos Agrupados (por Cliente, Producto, Mes)
↓
Variables de Filtrado (p/ej: País = 'ES', Año = 2026)
↓
Resultado: Dataset optimizado para Analytics
📋 Tabla de Hechos: Sales (Ventas)
Definición en .hdbtable:
namespace logali.sales;
@AbapCatalog.sqlViewName: 'SALES'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Ventas Realizadas'
define table Sales {
key ID: String; // ID única de venta
CUSTOMER_ID: String; // FK a Dimensión Cliente
PRODUCT_ID: String; // FK a Dimensión Producto
SALE_DATE: Date; // Fecha de venta
QUANTITY: Integer; // Cantidad vendida
UNIT_PRICE: Decimal(10,2);// Precio unitario
DISCOUNT_PCT: Decimal(5,2);// % descuento aplicado
TOTAL_BEFORE_DISC: Decimal(15,2); // Subtotal
TOTAL_AFTER_DISC: Decimal(15,2); // Total con descuento
};
Datos de ejemplo:
| ID |
CUSTOMER_ID |
PRODUCT_ID |
SALE_DATE |
QUANTITY |
UNIT_PRICE |
DISCOUNT_PCT |
TOTAL_AFTER_DISC |
| SAL-001 |
CUST-123 |
PROD-456 |
2026-05-01 |
5 |
100.00 |
10% |
450.00 |
| SAL-002 |
CUST-789 |
PROD-123 |
2026-05-02 |
2 |
250.00 |
5% |
475.00 |
| SAL-003 |
CUST-123 |
PROD-789 |
2026-05-03 |
10 |
50.00 |
15% |
425.00 |
🔗 Dimensiones Relacionadas
Dimensión Cliente:
define table Customer {
key CUSTOMER_ID: String;
NAME: String;
CITY: String;
COUNTRY: String;
SEGMENT: String; // 'Premium', 'Standard', 'Basic'
};
Dimensión Producto:
define table Product {
key PRODUCT_ID: String;
NAME: String;
CATEGORY: String; // 'Electrónica', 'Software', 'Servicios'
LIST_PRICE: Decimal(10,2);
COST: Decimal(10,2); // Costo de venta
MARGIN_PCT: Decimal(5,2); // Margen típico
};
Dimensión Tiempo:
define table Time {
key DATE_ID: Date;
YEAR: Integer;
MONTH: Integer;
QUARTER: Integer;
WEEK: Integer;
DAY_NAME: String;
};
Joins en la Calculation View:
Sales (Tabla de Hechos)
↓
[Inner Join] Sales.CUSTOMER_ID = Customer.CUSTOMER_ID
↓
[Inner Join] Sales.PRODUCT_ID = Product.PRODUCT_ID
↓
[Inner Join] Sales.SALE_DATE = Time.DATE_ID
↓
Resultado: Un registro por venta con todos los atributos
💡 Nota sobre Joins:
Los joins se hacen en memoria en HANA. Aunque haya millones de ventas, la velocidad de join es extremadamente rápida porque todo está en RAM. Sin HANA, tendrías que hacer estas búsquedas en disco (lentísimo).
📈 Medidas Calculadas
Tipos de medidas en la Calculation View:
Suma (SUM)
Ingresos Totales: SUM(Sales.TOTAL_AFTER_DISC)
Suma de todos los totales de venta.
Promedio (AVG)
Ticket Promedio: AVG(Sales.TOTAL_AFTER_DISC)
Promedio del valor de cada transacción.
Ratios (Divisiones)
Margen %: SUM(Product.COST) / SUM(Sales.TOTAL_AFTER_DISC) * 100
Porcentaje de utilidad respecto a ingresos.
Conteos (COUNT)
Total de Transacciones: COUNT(Sales.ID)
Número de ventas realizadas.
Máximo/Mínimo
Venta Mayor: MAX(Sales.TOTAL_AFTER_DISC)
Descuento Mínimo: MIN(Sales.DISCOUNT_PCT)
Ejemplo: Medidas en Cálculo View XML:
<measure name="TOTAL_SALES">
<measureColumns>
<measureColumn columnName="TOTAL_AFTER_DISC"/>
</measureColumns>
<aggregationType>SUM</aggregationType>
</measure>
<measure name="AVG_TRANSACTION">
<measureColumns>
<measureColumn columnName="TOTAL_AFTER_DISC"/>
</measureColumns>
<aggregationType>AVG</aggregationType>
</measure>
<measure name="MARGIN_RATIO">
<measureColumns>
<measureColumn columnName="COST"/>
<measureColumn columnName="TOTAL_AFTER_DISC"/>
</measureColumns>
<aggregationType>SUM</aggregationType>
</measure>
🏷️ Atributos de Agrupación
Los atributos definen las dimensiones por las cuales se agrupan las medidas. Ejemplo:
Resultado agrupado por Cliente:
| CUSTOMER_ID |
CUSTOMER_NAME |
CUSTOMER_COUNTRY |
TOTAL_SALES |
AVG_TRANSACTION |
TX_COUNT |
| CUST-123 |
Tech Corp |
ES |
875.00 |
437.50 |
2 |
| CUST-789 |
Solutions Ltd |
UK |
475.00 |
475.00 |
1 |
Resultado agrupado por Producto y Mes:
| PRODUCT_NAME |
CATEGORY |
YEAR-MONTH |
TOTAL_SALES |
QUANTITY_SOLD |
AVG_DISCOUNT |
| CloudSuite |
Software |
2026-05 |
450.00 |
5 |
10% |
| Enterprise Suite |
Software |
2026-05 |
475.00 |
2 |
5% |
| Support Services |
Servicios |
2026-05 |
425.00 |
10 |
15% |
Atributos disponibles para agrupar:
- Por Cliente: CUSTOMER_NAME, CUSTOMER_COUNTRY, CUSTOMER_SEGMENT
- Por Producto: PRODUCT_NAME, PRODUCT_CATEGORY
- Por Tiempo: YEAR, MONTH, QUARTER, WEEK
- Combinaciones: Cliente + Mes, Producto + País, etc.
⚙️ Variables y Parámetros de Entrada
Las variables permiten que usuarios/dashboards filtren dinámicamente sin modificar la Calculation View.
Tipos de variables:
Variable Simple (Rango de fechas)
<variable name="START_DATE" datatype="DATE">
<defaultValue>2026-01-01</defaultValue>
</variable>
<variable name="END_DATE" datatype="DATE">
<defaultValue>2026-12-31</defaultValue>
</variable>
-- Uso en WHERE:
WHERE Sales.SALE_DATE BETWEEN :START_DATE AND :END_DATE
Variable de Selección Única (País)
<variable name="COUNTRY" datatype="NVARCHAR" length="2">
<defaultValue>ES</defaultValue>
</variable>
-- Uso en WHERE:
WHERE Customer.COUNTRY = :COUNTRY
-- El usuario selecciona 'ES', 'UK', 'DE', etc.
Variable de Selección Múltiple (Categorías)
<variable name="CATEGORIES" datatype="NVARCHAR" length="50">
<defaultValue>'Software','Servicios'</defaultValue>
<multiSelect>true</multiSelect>
</variable>
-- Uso en WHERE:
WHERE Product.CATEGORY IN (:CATEGORIES)
-- Usuario selecciona una o varias categorías
Variable de Segmento (Filtro de negocio)
<variable name="CUSTOMER_SEGMENT" datatype="NVARCHAR">
<defaultValue>Premium</defaultValue>
<allowedValues>
<value>Premium</value>
<value>Standard</value>
<value>Basic</value>
</allowedValues>
</variable>
WHERE Customer.SEGMENT = :CUSTOMER_SEGMENT
Flujo de filtrado dinámico:
Usuario en SAP Analytics Cloud
↓
[Selecciona] País = 'ES', Fechas: 01/05 - 31/05
↓
Dashboard envía parámetros a Calculation View
↓
WHERE COUNTRY='ES' AND SALE_DATE BETWEEN 2026-05-01 AND 2026-05-31
↓
Resultado: Solo ventas de España en Mayo 2026
↓
[Actualiza] Medidas en Dashboard (dinámicas)
💡 Ventaja de variables:
Sin tocar el código, el usuario puede cambiar filtros en la UI. Los parámetros se reemplazan en la query automáticamente, haciendo que el resultado sea dinámico y rápido.
🎯 Caso Práctico: Dashboard de Ventas Regional
Requisito de negocio:
El VP de Ventas necesita ver ingresos, margen y ticket promedio por país y mes, con la opción de filtrar por rango de fechas y categoría de producto.
Estructura de la Calculation View:
┌─ Sales (Tabla de Hechos)
│ ├─ ID, QUANTITY, UNIT_PRICE, DISCOUNT_PCT, TOTAL_AFTER_DISC
│
├─ [Join] Customer Dimension
│ ├─ CUSTOMER_ID, COUNTRY, SEGMENT
│
├─ [Join] Product Dimension
│ ├─ PRODUCT_ID, CATEGORY, COST
│
└─ [Join] Time Dimension
├─ DATE_ID, YEAR, MONTH, QUARTER
MEDIDAS:
├─ Total_Revenue = SUM(TOTAL_AFTER_DISC)
├─ Total_Cost = SUM(COST)
├─ Margin = (SUM(TOTAL_AFTER_DISC) - SUM(COST)) / SUM(TOTAL_AFTER_DISC)
├─ Avg_Ticket = AVG(TOTAL_AFTER_DISC)
└─ Transaction_Count = COUNT(Sales.ID)
ATRIBUTOS:
├─ COUNTRY
├─ MONTH
├─ CATEGORY
└─ SEGMENT
VARIABLES:
├─ START_DATE (default: 2026-01-01)
├─ END_DATE (default: 2026-12-31)
└─ SELECTED_CATEGORY (default: todas)
Query SQL generada en HANA:
SELECT
Customer.COUNTRY,
Time.MONTH,
Product.CATEGORY,
SUM(Sales.TOTAL_AFTER_DISC) as Total_Revenue,
SUM(Product.COST) as Total_Cost,
SUM(Product.COST) / SUM(Sales.TOTAL_AFTER_DISC) as Margin_Ratio,
AVG(Sales.TOTAL_AFTER_DISC) as Avg_Ticket,
COUNT(Sales.ID) as Transaction_Count
FROM Sales
INNER JOIN Customer ON Sales.CUSTOMER_ID = Customer.CUSTOMER_ID
INNER JOIN Product ON Sales.PRODUCT_ID = Product.PRODUCT_ID
INNER JOIN Time ON Sales.SALE_DATE = Time.DATE_ID
WHERE Sales.SALE_DATE BETWEEN :START_DATE AND :END_DATE
AND Product.CATEGORY IN (:SELECTED_CATEGORY)
GROUP BY Customer.COUNTRY, Time.MONTH, Product.CATEGORY
ORDER BY Customer.COUNTRY, Time.MONTH
Resultado en Dashboard SAP Analytics Cloud:
| COUNTRY |
MONTH |
CATEGORY |
Total_Revenue |
Margin_Ratio |
Avg_Ticket |
Tx_Count |
| ES |
May-2026 |
Software |
925,000 |
35% |
450 |
2,055 |
| ES |
May-2026 |
Servicios |
425,000 |
42% |
380 |
1,118 |
| UK |
May-2026 |
Software |
1,250,000 |
33% |
520 |
2,404 |
| UK |
May-2026 |
Servicios |
675,000 |
38% |
445 |
1,516 |
Interacción del usuario:
- Usuario cambia filtro: "Mostrar solo Junio 2026" → Variables :START_DATE y :END_DATE se actualizan → Dashboard recalcula en <2 segundos (gracias a HANA in-memory)
- Usuario selecciona: "Solo categoría Software" → Variable :SELECTED_CATEGORY cambia → Resultados filtrados en tiempo real
- Usuarios ven tendencias: "España baja en Software pero sube en Servicios" → Actionable insights
✅ Checklist de Implementación
- □ Tabla de Hechos: Crear Sales con claves foráneas (CUSTOMER_ID, PRODUCT_ID, DATE_ID)
- □ Dimensiones: Customer, Product, Time completamente pobladas
- □ Cálculo View: Crear en Business Application Studio con joins correctos
- □ Medidas: Definir SUM, AVG, ratios según KPIs de negocio
- □ Atributos: Marcar campos como Attribute (COUNTRY, MONTH, CATEGORY)
- □ Variables: Crear para fechas y categorías dinámicas
- □ Exposición OData: Crear servicio CDS para consumir desde Analytics Cloud
- □ Testing: Validar joins con millones de registros (debería ser < 2seg)
- □ Dashboard: Conectar en SAP Analytics Cloud con visualizaciones interactivas
🚀 Resultado final:
Un modelo de datos listo para que usuarios no-técnicos creen dashboards interactivos, cambien filtros dinámicamente, y tomen decisiones en tiempo real basadas en datos de millones de registros procesados en RAM.