--- name: metabase_smartscalar_kpi_sql kind: function lang: py domain: infra version: "1.0.0" purity: pure signature: "def metabase_smartscalar_kpi_sql(*, act_expr: str, n1_expr: str, body_sql: str, date_expr: str = 'MIN(fecha)') -> str" description: "Envuelve agregaciones actual+n-1 en el patron de 2 filas (periodo, valor) que el display smartscalar de Metabase v0.59 requiere para mostrar comparacion vs ano anterior sin pedir breakout temporal. Genera SQL nativo BigQuery con UNION ALL d_min/d_min-52w." tags: [metabase, smartscalar, kpi, sql, bigquery, pure, builder] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "" imports: [] params: - name: act_expr desc: "Expresion SQL de agregado para el periodo actual, ej. 'ROUND(SUM(v.venta_n), 2)' o 'SAFE_DIVIDE(SUM(a), NULLIF(SUM(b),0))'" - name: n1_expr desc: "Expresion SQL para el mismo agregado del ano anterior, ej. 'ROUND(SUM(v.venta_n1), 2)'" - name: body_sql desc: "Cuerpo SQL desde 'FROM' que define las tablas/CTEs y filtros con template-tags Metabase ([[AND {{tag}}]])" - name: date_expr desc: "Expresion para extraer la fecha minima del periodo; usada como periodo en la fila actual y ancla para DATE_SUB de la fila n-1. Default 'MIN(fecha)'" output: "string con SQL nativo BigQuery que devuelve 2 filas con columnas periodo (DATE) y valor (numero); fila 1 = periodo n-1, fila 2 = periodo actual" tested: false tests: [] test_file_path: "" file_path: "python/functions/metabase/smartscalar.py" --- ## Por que existe El display ``smartscalar`` de Metabase v0.59.4 con ``previousValue`` requiere una serie temporal para mostrar comparacion. Si el query devuelve un solo numero el frontend muestra el error "Agrupa solo por un campo de tiempo para ver como ha cambiado con el tiempo". El truco probado en el dashboard ``Informe Lean`` (cards 9340-9373) es producir 2 filas sinteticas: una para el periodo actual (``d_min``, ``act``) y otra para n-1 (``d_min - 52 weeks``, ``n1``). Smartscalar lo interpreta como serie de 2 puntos y compara naturalmente. Esta funcion automatiza ese patron: el caller solo provee el cuerpo SQL con sus filtros y las dos expresiones de agregado. ## Ejemplo ```python body = """ FROM `proj.ds.base_margenes_aa` `proj.ds.base_margenes_aa` v LEFT JOIN `proj.ds.Objeto_productos` p ON p.nav_id = v.prod_nav_id WHERE 1=1 [[AND {{fecha}}]] [[AND {{categoria}}]] [[AND {{tipo}}]] """ sql = metabase_smartscalar_kpi_sql( act_expr="ROUND(SUM(v.venta_n), 2)", n1_expr="ROUND(SUM(v.venta_n1), 2)", body_sql=body, date_expr="MIN(v.fecha)", ) # sql tiene UNION ALL con periodo y valor ``` ## Notas - Por convencion los template-tags estan envueltos en ``[[ ]]`` para que sean opcionales: si el dashboard no aplica el filtro la clausula desaparece. - Para que los field-filters de Metabase resuelvan correctamente las tablas dentro de CTEs, alias cada tabla con la cadena ``schema.table`` exacta que Metabase usa al expandir el template-tag (ej. ``\`proj.ds.tabla\` \`ds.tabla\``). - El SQL generado usa ``DATE_SUB(d_min, INTERVAL 52 WEEK)`` (BigQuery dialect). Para Postgres adaptar a ``d_min - INTERVAL '52 weeks'``.