Controla el flujo de tus consultas M con if/then/else, try/otherwise, operadores lógicos y patrones avanzados.
PrincipianteIntermedioAvanzado
🔍
🧠
if / then / else
Expresión if / then / else
Principiante
Sintaxis
if condicion then valor_si_verdadero else valor_si_falso
¿Qué hace?
La expresión condicional fundamental de M. Evalúa condicion y devuelve el resultado de then o else según sea true o false. En M, if es una expresión (devuelve un valor), no una instrucción.
Ejemplo
// Básico
if [Ventas] > 1000 then "Alto" else "Bajo"
// Anidado (equivalente a IFS de Excel)
if [Nota] >= 9 then "Sobresaliente"
else if [Nota] >= 7 then "Notable"
else if [Nota] >= 5 then "Aprobado"
else "Suspenso"
// En una columna calculada
Table.AddColumn(tabla, "Categoria",
each if [Importe] > 10000 then "Premium"
else if [Importe] > 1000 then "Estándar"
else "Básico"
)
💡 Tip kawaii: M no tiene switch ni case. Para muchas condiciones, considera usar un Record como tabla de lookup en lugar de largas cadenas de if/else if.
if dentro de expresiones let
Intermedio
¿Qué hace?
Puedes usar if en cualquier posición donde se espera un valor: dentro de let, como argumento de función, en definición de funciones, etc.
Ejemplo
let
umbral = 500,
datos = Table.FromRows({{1, 300}, {2, 700}, {3, 500}}),
// if dentro de una función anónima
clasificados = Table.AddColumn(datos, "Estado",
each if _[Column2] > umbral then "Supera"
else if _[Column2] = umbral then "Exacto"
else "No supera"
)
in
clasificados
🧠
Operadores Lógicos
and / or / not
Principiante
Sintaxis
expresion1 and expresion2 // Ambas deben ser true
expresion1 or expresion2 // Al menos una debe ser true
not expresion // Niega el valor lógico
¿Qué hace?
Operadores booleanos estándar. En M se escriben en minúsculas (and, or, not), no como &&, ||, !.
Ejemplo
// Múltiples condiciones
if [Edad] >= 18 and [Pais] = "ES" then "Elegible" else "No elegible"
// OR para categorías
if [Departamento] = "Ventas" or [Departamento] = "Marketing"
then "Comercial" else "Otro"
// NOT para invertir
Table.SelectRows(tabla, each not ([Estado] = "Cancelado"))
// Combinación compleja
Table.SelectRows(tabla, each
[Importe] > 1000 and
([Pais] = "ES" or [Pais] = "PT") and
not ([Estado] = "Borrador")
)
⚠️ Ojo con esto: M evalúa ambas partes de and y or aunque el resultado ya esté determinado (no hay short-circuit garantizado). Si una parte puede fallar, usa try/otherwise para protegerla.
🛡️
try / otherwise — Manejo de Errores
try / otherwise
Intermedio
Sintaxis
try expresion otherwise valor_por_defecto
// Con acceso al error
try expresion
// Devuelve un record: [HasError = true/false, Value = ..., Error = ...]
¿Qué hace?
Evalúa expresion y si produce un error, devuelve valor_por_defecto. Sin otherwise, devuelve un record con información del error.
Ejemplo
// Conversión segura a número
try Number.FromText([Precio]) otherwise 0
// División segura
try [Numerador] / [Denominador] otherwise null
// Con información del error
let resultado = try Number.FromText("abc")
in if resultado[HasError]
then "Error: " & resultado[Error][Message]
else resultado[Value]
// Conversión de fecha robusta
try Date.FromText([FechaTexto], "es-ES") otherwise null
📌 Buena práctica: Usa try ... otherwise null cuando importes datos de fuentes poco fiables. Es mejor tener un null controlado que un error que corte toda la actualización.
Lanza un error de forma explícita. Útil en funciones personalizadas para validar parámetros y proporcionar mensajes claros al usuario.
Ejemplo
// Función con validación
let
DividirSeguro = (numerador as number, denominador as number) as number =>
if denominador = 0
then error [
Reason = "DivisionPorCero",
Message = "El denominador no puede ser cero",
Detail = [Numerador = numerador]
]
else numerador / denominador
in
DividirSeguro(10, 0)
⭕
Manejo de Nulos
null y el operador ??
Intermedio
Sintaxis
// Comprobar nulo
valor = null
valor <> null
// Coalescencia nula (M no tiene ?? nativo, usar if/then/else)
if valor = null then valor_por_defecto else valor
¿Qué hace?
En M, null representa la ausencia de valor. La mayoría de las funciones propagan el null (si la entrada es null, la salida es null). Es importante manejarlos explícitamente.
Ejemplo
// Reemplazar null por valor por defecto
if [Descripcion] = null then "Sin descripción" else [Descripcion]
// Contar no-nulos en una lista
List.Count(List.RemoveNulls([MiLista]))
// Filtrar nulos de una tabla
Table.SelectRows(tabla, each [Nombre] <> null)
// Cadena de nulos: si [A] es null, intenta [B], si no "N/A"
if [A] <> null then [A]
else if [B] <> null then [B]
else "N/A"
💡 Tip kawaii: Las operaciones aritméticas con null devuelven null (ej. null + 5 = null). Las comparaciones con null devuelven null, no false. ¡Esto puede provocar comportamientos inesperados en filtros!
✅
Funciones Logical.*
Logical.From / Logical.FromText
Principiante
Sintaxis
Logical.From(value as any) as nullable logical
Logical.FromText(text as nullable text) as nullable logical
Logical.ToText(logical as nullable logical) as nullable text
¿Qué hace?
Convierte valores a tipo lógico (true/false). Logical.From acepta números (0=false, cualquier otro=true) y textos. Logical.FromText acepta "true"/"false" en cualquier capitalización.
Como M no tiene switch, puedes simular un mapeo de valores usando un Record como diccionario, con Record.Field o acceso por campo. Es mucho más limpio que largas cadenas if/else if.
Ejemplo
// Mapa de códigos a nombres
let
meses = [
#"1" = "Enero", #"2" = "Febrero", #"3" = "Marzo",
#"4" = "Abril", #"5" = "Mayo", #"6" = "Junio",
#"7" = "Julio", #"8" = "Agosto", #"9" = "Septiembre",
#"10" = "Octubre", #"11" = "Noviembre", #"12" = "Diciembre"
],
obtenerMes = (num as number) as text =>
if Record.HasFields(meses, Text.From(num))
then Record.Field(meses, Text.From(num))
else "Desconocido"
in
obtenerMes(7) // "Julio"
📌 Buena práctica: El patrón Record-como-diccionario es más mantenible que 12 ramas if/else if. Si el mapa de valores puede cambiar, guárdalo en una tabla de parámetros en lugar de hardcodearlo en M.
Evaluación diferida con funciones
Avanzado
¿Qué hace?
M usa evaluación diferida: las expresiones en let sólo se calculan cuando se necesitan. Puedes aprovechar esto para condiciones de cortocircuito seguro envolviendo ramas peligrosas en funciones () =>.
Ejemplo
// Problema: esto puede fallar si [Texto] es null
// Text.Length([Texto]) > 5 -- error si null
// Solución: guardar en variable primero
let
texto = [Texto],
longitud = if texto = null then 0 else Text.Length(texto)
in
longitud > 5
// O con try/otherwise
try Text.Length([Texto]) > 5 otherwise false
🚀 ¡Lógica dominada! Ahora explora las Funciones de Record para trabajar con estructuras de datos clave-valor.