Prueba técnica Power BI: modela los datos y explica por qué cambian los totales
Quick Overview
Prueba técnica Power BI con tres pedidos y tres devoluciones originales. Reproduce un JOIN que eleva el neto de 29.500 a 39.500 céntimos; concilia por pedido y tienda, distingue fecha de registro y cohorte, y compara la tasa global del 15,71% con la media simple del 30%. Incluye un libro de fórmulas y SQL con resultados ejecutados. Las medidas DAX y relaciones físicas se proponen, pero no se ejecutaron en Power BI Desktop.
Tu informe muestra 39.500 céntimos de ventas netas. Los archivos originales contienen 35.000 de ventas y 5.500 de devoluciones, así que esperabas 29.500. Cambiar el formato de la tarjeta no arreglará esa diferencia: un pedido se ha repetido al combinarlo con sus dos devoluciones.
Para preparar una prueba técnica de Power BI, practica cómo demostrar qué representa cada fila, qué fecha filtra cada importe y cómo se recalcula una tasa en el total. Aquí trabajarás con un caso original pequeño, una consulta SQL incorrecta y otra conciliada, y un libro con fórmulas editables. La meta es defender el resultado antes de diseñar el dashboard. Para practicar los fundamentos del modelo, utiliza las preguntas para Business Intelligence Engineer en PracHub.
Hechos oficiales: las referencias de Microsoft explican modelado y DAX. Resultados del ejercicio: las comprobaciones SQL y del libro se ejecutaron con datos sintéticos. Inferencias de preparación: las decisiones propuestas sirven para practicar; no describen el examen de una empresa. No usamos relatos de candidatos para afirmar duración, rondas o preguntas futuras.

Define el grano antes de combinar archivos
Hecho oficial: la guía de Microsoft sobre esquema en estrella distingue dimensiones para filtrar y agrupar, y hechos para resumir. También explica que la granularidad depende de las claves y valores de la tabla. Esa orientación no convierte cualquier archivo llamado «ventas» en una tabla lista para sumar.
En este ejercicio, orders contiene una fila por pedido. refunds contiene una fila por operación de devolución. Dos operaciones pueden pertenecer al mismo pedido. Guardamos los importes en céntimos enteros; las fechas son de 2026. No hay impuestos, descuentos, divisas, cancelaciones ni devoluciones rechazadas. Es un contrato limitado que permite comprobar cada suma a mano.
| Pedido | Tienda | Fecha del pedido | Venta, céntimos |
|---|---|---|---|
| o1 | Norte | 30 de agosto | 10.000 |
| o2 | Norte | 31 de agosto | 20.000 |
| o3 | Sur | 31 de agosto | 5.000 |
| Devolución | Pedido | Fecha de registro | Importe, céntimos |
|---|---|---|---|
| r1 | o1 | 1 de septiembre | 1.000 |
| r2 | o1 | 2 de septiembre | 2.000 |
| r3 | o3 | 2 de septiembre | 2.500 |
Antes de importar, comprueba la unicidad de order_id y refund_id, y que cada devolución encuentre su pedido. «La tabla tiene tres filas» no demuestra que tenga tres pedidos diferentes. Una clave duplicada, un identificador vacío y una devolución huérfana requieren decisiones explícitas; no los conviertas silenciosamente en una venta inexistente.
En una evaluación real, pregunta si la devolución es un movimiento, un estado actualizado o un acumulado. Si los archivos contienen instantáneas repetidas, sumar todas las versiones puede duplicar una operación incluso antes del JOIN. La granularidad se determina leyendo el contrato y contrastándolo con los datos.
Reproduce el error con un pedido concreto
Este JOIN conserva las ventas sin devolución, pero repite la venta de o1:
SELECT SUM(o.cents) AS gross_cents,
SUM(COALESCE(r.cents, 0)) AS refund_cents,
SUM(o.cents) - SUM(COALESCE(r.cents, 0)) AS net_cents
FROM orders o
LEFT JOIN refunds r ON r.order_id = o.order_id;
Resultado ejecutado en SQLite: ventas 45.000, devoluciones 5.500 y neto 39.500. La fila de o1 participa dos veces porque encuentra r1 y r2. Su venta de 10.000 aparece dos veces; las otras ventas aparecen una vez. El exceso del neto es exactamente 10.000.
Inspecciona las filas intermedias antes de cambiar la medida. Esta explicación localiza el problema: el importe de cabecera pertenece al pedido, mientras que el resultado combinado tiene una fila por devolución, más una fila para el pedido sin devolución. Un LEFT JOIN evita cierta pérdida de filas, pero no garantiza que una suma conserve su significado.
Tampoco uses SUM(DISTINCT o.cents) como arreglo general. Dos pedidos legítimos pueden tener el mismo importe. Eliminar valores monetarios iguales no equivale a recuperar pedidos únicos. Añadir una venta de 10.000 a otro cliente ofrece un contraejemplo inmediato: ese importe debería contarse de nuevo.
Concilia devoluciones al nivel del pedido
Una solución para esta pregunta es sumar las devoluciones por pedido antes de combinarlas:
WITH refund_by_order AS (
SELECT order_id, SUM(cents) AS refund_cents
FROM refunds
GROUP BY order_id
)
SELECT o.store,
SUM(o.cents) AS gross_cents,
SUM(COALESCE(r.refund_cents, 0)) AS refund_cents,
SUM(o.cents) - SUM(COALESCE(r.refund_cents, 0)) AS net_cents
FROM orders o
LEFT JOIN refund_by_order r ON r.order_id = o.order_id
GROUP BY o.store
ORDER BY o.store;
Resultado ejecutado: Norte tiene ventas de 30.000, devoluciones de 3.000 y neto de 27.000. Sur tiene 5.000, 2.500 y 2.500. El total neto vuelve a 29.500. El pedido o2 permanece aunque no tenga devolución.
Esta agregación responde al neto por tienda y pedido dentro del conjunto completo. No conserva el detalle individual de r1 y r2 en su resultado. Si después necesitas analizar el día de cada devolución, conserva también el archivo de movimientos; una tabla agregada por pedido no contiene esa distribución temporal.
El libro de ventas y devoluciones incluye entradas identificadas, devoluciones agregadas por pedido, el cálculo deliberadamente incorrecto y resultados por tienda. Cambia una devolución y observa los totales que dependen de ella. Las fórmulas usan rangos de las tres filas del caso; para ampliar el ejercicio, amplía también los rangos. No presentes este archivo acotado como una plantilla de producción con crecimiento automático.
Diseña el modelo para la pregunta que necesitas responder
Hecho oficial: Microsoft documenta que las relaciones de modelo propagan filtros; no garantizan por sí mismas la integridad de los datos. Cardinalidad y dirección deben corresponder a las claves y al recorrido del filtro.
Propuesta para este caso: conserva dos hechos, pedidos y devoluciones. Una dimensión de tienda con una fila por tienda puede filtrar ambos. La tienda de cada devolución se obtiene del pedido correspondiente durante la preparación, mediante una búsqueda validada. Un identificador sin correspondencia debe generar una incidencia visible.
Para movimientos por fecha de registro, una dimensión de fecha puede filtrar OrderDate en pedidos y RefundDate en devoluciones. Así, agosto incluye las ventas de agosto y septiembre incluye los reembolsos registrados en septiembre. Mantén claros los nombres de los campos que utiliza cada relación.
Para seguir la cohorte de pedidos de agosto, la selección debe incluir sus devoluciones posteriores. Una propuesta distinta incorpora la fecha del pedido en la tabla de devoluciones y utiliza una dimensión de fecha de pedido para filtrar ambos hechos. Si también necesitas filtrar simultáneamente por fecha de devolución, distingue ese papel con otra dimensión de fecha. La guía de relaciones activas e inactivas explica las opciones según los papeles de una dimensión.
No actives filtros bidireccionales por ensayo hasta obtener 29.500. Dibuja primero qué selección debe llegar a cada hecho y comprueba una tienda y un mes cuyo resultado conozcas. Estas configuraciones son diseños propuestos: no creamos un PBIX ni ejecutamos sus relaciones en Power BI Desktop.
Separa el mes de registro de la cohorte

Hay dos preguntas válidas: «¿Qué movimientos se registraron en agosto?» y «¿Cuánto dejaron los pedidos de agosto después de sus devoluciones?». El nombre «neto de agosto» no permite distinguirlas. Confirma la definición antes de demostrar un resultado.
| Definición del periodo | Ventas | Devoluciones incluidas | Neto, céntimos |
|---|---|---|---|
| Registro en agosto | 35.000 | 0 | 35.000 |
| Registro en septiembre | 0 | 5.500 | −5.500 |
| Pedidos de agosto, con todas las devoluciones del caso | 35.000 | 5.500 | 29.500 |
Los tres resultados se comprobaron en SQLite y en el libro. Un neto mensual negativo en septiembre no es un error aritmético: en este conjunto solo hay devoluciones registradas durante ese mes. Tampoco significa que una tienda real pierda dinero; no tenemos costes ni una contabilidad completa.
En el caso completo, todas las devoluciones conocidas están incluidas. Con datos reales necesitas una fecha de corte: una cohorte reciente todavía puede recibir devoluciones. Etiqueta «hasta el 2 de septiembre», por ejemplo, si esa es la última fecha cargada. Mezclar cohortes con distinta madurez puede alterar una comparación aunque las medidas estén bien escritas.
Al filtrar fechas, fija límites inequívocos. El SQL del ejercicio usa inicio incluido y comienzo del mes siguiente excluido. Si recibes marcas de tiempo, confirma también zona horaria y conversión a fecha. No atribuyas una diferencia de un día a DAX antes de comprobar la preparación de los datos.
Recalcula la tasa desde sus componentes
Norte devuelve 3.000 sobre 30.000: 10%. Sur devuelve 2.500 sobre 5.000: 50%. La media simple de esas tasas es 30%. Pero la tasa del conjunto es 5.500 dividido entre 35.000, aproximadamente 15,71%. Las tiendas tienen volúmenes diferentes.
Hecho oficial: SUM suma números de una columna. DIVIDE divide dos expresiones y permite definir un resultado alternativo cuando el denominador es cero; sin alternativa devuelve BLANK. Para el modelo físico propuesto, las medidas básicas serían:
Ventas Céntimos = SUM ( FactOrders[AmountCents] )
Devoluciones Céntimos = SUM ( FactRefunds[AmountCents] )
Neto Céntimos = [Ventas Céntimos] - [Devoluciones Céntimos]
Tasa de Devolución = DIVIDE ( [Devoluciones Céntimos], [Ventas Céntimos] )
La medida de tasa debe evaluarse con el filtro de tienda y periodo acordado. Sumar porcentajes o promediar las filas visibles cambia la ponderación. Si la pregunta fuera «media de tasas de tiendas, dando igual peso a cada una», 30% sí respondería a esa definición. Dale un nombre diferente.
Hecho oficial: CALCULATE evalúa una expresión en un contexto de filtro modificado. No hace falta añadirlo a cada medida para que un visual aplique su contexto. Úsalo cuando el cálculo necesite una modificación concreta y explica qué filtro cambia.
En septiembre, la razón por fecha de registro tiene denominador cero. Decide si mostrar BLANK, «no aplicable» u otra salida acordada. No prometas 0% como solución automática: ocultaría la diferencia entre ausencia de ventas y ausencia de devoluciones. Las medidas físicas anteriores son propuestas documentadas; aquí se ejecutó su aritmética en SQL y en el libro, no esas medidas dentro del motor DAX.
Entrega pruebas que permitan repetir el diagnóstico
El ejercicio reproducible incluye los CSV originales, las dos consultas, el libro y un script de comprobación. Ejecuta python3 reconcile.py desde la carpeta extraída con Python 3.9 o posterior. Solo utiliza la biblioteca estándar y una base SQLite en memoria. Las entradas son sintéticas; no conectes este ejercicio a una base empresarial.
Las 15 comprobaciones cubren el JOIN incorrecto, subtotales, neto, tasas, dos definiciones de fecha, pedidos sin devolución, devoluciones vacías, conjunto vacío y rechazo de devoluciones duplicadas, devoluciones huérfanas e importes inválidos. También rechazan devoluciones acumuladas mayores que la venta, según el contrato de este caso. Otro negocio podría necesitar reglas distintas.
El libro pasó 15 comparaciones de resultados y una modificación de entrada seguida de restauración. Su motor de generación recalculó las fórmulas; no ejecutamos Excel de escritorio. Tampoco probamos relaciones físicas, segmentadores, RLS, actualización del servicio ni rendimiento con grandes volúmenes. Esas pruebas pertenecen al siguiente paso del modelo real.
Presenta primero el error con o1, después el control de 29.500 y finalmente las dos fechas. Una explicación breve útil sería: «La venta de o1 se repetía por dos devoluciones. Agregué por pedido y concilié Norte y Sur. El mes de registro y la cohorte responden a preguntas distintas; antes de cerrar el informe necesito confirmar cuál espera el negocio». Puedes señalar el archivo, la consulta y el resultado que respaldan cada frase.
Practica las decisiones de datos que sostienen el informe
Estos destinos de PracHub se verificaron con sus títulos completos. Son ejercicios de SQL y razonamiento sobre datos; no los presentamos como pruebas Power BI de una empresa ni como predicciones del próximo examen. Conservamos los títulos originales para facilitar la búsqueda.
| Pregunta verificada de PracHub | Qué comprobar |
|---|---|
| Aggregate User Events and Check Join Uniqueness | Cuenta claves y filas antes y después de combinar dos granos. |
| Write SQL to compute campaign net revenue | Define qué movimientos entran en el neto y concilia sus componentes. |
| Compute Total Spent in 2023 Excluding Refunds | Aclara qué fecha selecciona ventas y qué devoluciones deben descontarse. |
| Write SQL to backtest refund policy | Comprueba la población y las reglas antes de comparar políticas. |
| Reason About Composite Join Keys and Predicate Placement | Revisa si la clave y el lugar del filtro conservan las filas esperadas. |
Continúa con las preguntas para Business Intelligence Engineer en PracHub. En cada solución, explica el grano, el periodo y un contraejemplo que cambiaría el total. Esa respuesta conecta el cálculo con una definición que otra persona puede revisar.
Comments (0)