Trabaja con estructuras clave-valor en Power Query M. Los records son la base de las filas de una tabla.
IntermedioAvanzado
🔍
🆕
Crear y Acceder a Records
Record literal — [ ]
Principiante
Sintaxis
[ campo1 = valor1, campo2 = valor2, ... ]
// Acceso por campo
record[NombreCampo]
record[#"Campo Con Espacios"]
¿Qué hace?
Un record en M es una colección ordenada de pares clave-valor, similar a un objeto JSON o una fila de tabla. Se crea con [ ] y se accede con record[campo].
Ejemplo
// Crear un record
let persona = [Nombre = "Sara", Edad = 30, Ciudad = "Madrid"]
in persona[Nombre] // "Sara"
// Campos con espacios o caracteres especiales
let config = [#"Tasa de IVA" = 0.21, #"Año Fiscal" = 2024]
in config[#"Tasa de IVA"] // 0.21
// El contexto de fila _ es un record de la fila actual
Table.AddColumn(tabla, "NombreCompleto",
each _[Nombre] & " " & _[Apellido]
)
💡 Tip kawaii: En Power Query, cuando usas each, el _ implícito es el record de la fila actual. Por eso each [Columna] es lo mismo que each _[Columna].
Record.Field / Record.HasFields
Intermedio
Sintaxis
Record.Field(record as record, field as text) as any
Record.HasFields(record as record, fields as any) as logical
¿Qué hace?
Record.Field accede a un campo cuyo nombre se conoce en tiempo de ejecución (dinámico). Record.HasFields comprueba si el record tiene uno o varios campos.
Ejemplo
let r = [A = 1, B = 2, C = 3]
in Record.Field(r, "B") // 2
// Acceso dinámico (útil cuando el nombre de campo viene de una variable)
let
campoDeseado = "Ciudad",
persona = [Nombre = "Ana", Ciudad = "Barcelona"]
in Record.Field(persona, campoDeseado) // "Barcelona"
// Comprobar existencia de campo
Record.HasFields([A=1, B=2], "C") // false
Record.HasFields([A=1, B=2], {"A","B"}) // true (comprueba varios a la vez)
🗂️
Campos y Valores
Record.FieldNames / Record.FieldValues
Intermedio
Sintaxis
Record.FieldNames(record as record) as list
Record.FieldValues(record as record) as list
Record.FieldCount(record as record) as number
¿Qué hace?
Extraen los nombres de campo, los valores o el número de campos de un record, respectivamente. Útiles para introspección y procesamiento dinámico.
Ejemplo
let r = [Nombre = "Ana", Edad = 25, Ciudad = "BCN"]
in [
nombres = Record.FieldNames(r), // {"Nombre", "Edad", "Ciudad"}
valores = Record.FieldValues(r), // {"Ana", 25, "BCN"}
cantidad = Record.FieldCount(r) // 3
]
// Obtener nombres de columnas de la primera fila de una tabla
Record.FieldNames(tabla{0})
Record.ToList / Record.ToTable
Intermedio
Sintaxis
Record.ToList(record as record) as list
Record.ToTable(record as record) as table
¿Qué hace?
Record.ToList convierte los valores del record a lista. Record.ToTable convierte el record a una tabla de dos columnas: Name y Value.
Ejemplo
let r = [A = 10, B = 20, C = 30]
in Record.ToList(r) // {10, 20, 30}
Record.ToTable([Pais = "ES", Año = 2024])
// Tabla:
// Name | Value
// ------+------
// Pais | "ES"
// Año | 2024
🧠
Modificar Records
Record.AddFields / Record.RemoveFields
Intermedio
Sintaxis
Record.AddFields(record as record, fields as record) as record
Record.RemoveFields(record as record, fields as any) as record
Record.RenameFields(record as record, renames as list) as record
¿Qué hace?
Añade, elimina o renombra campos de un record sin modificar el original (M es inmutable). Devuelve un nuevo record con los cambios aplicados.
Ejemplo
let base = [Nombre = "Ana", Edad = 25]
in [
// Añadir campo
conCiudad = Record.AddFields(base, [Ciudad = "Madrid"]),
// [Nombre = "Ana", Edad = 25, Ciudad = "Madrid"]
// Eliminar campo
sinEdad = Record.RemoveFields(base, "Edad"),
// [Nombre = "Ana"]
// Renombrar campo
renombrado = Record.RenameFields(base, {{"Nombre", "Name"}, {"Edad", "Age"}})
// [Name = "Ana", Age = 25]
]
Record.TransformFields
Avanzado
Sintaxis
Record.TransformFields(record as record, transformOperations as list, optional missingField as nullable number) as record
¿Qué hace?
Aplica transformaciones a campos específicos de un record. Cada operación es un par {nombreCampo, función}.
Fusiona una lista de records en uno solo. Si hay campos con el mismo nombre, el último valor prevalece.
Ejemplo
Record.Combine({
[Nombre = "Ana", Edad = 25],
[Ciudad = "Madrid", Pais = "ES"],
[Edad = 26] // sobreescribe Edad
})
// [Nombre = "Ana", Edad = 26, Ciudad = "Madrid", Pais = "ES"]
// Patrón: record de configuración por defecto + sobrescribir con parámetros
let
defaults = [Timeout = 30, Reintentos = 3, Debug = false],
params = [Timeout = 60, Debug = true]
in Record.Combine({defaults, params})
// [Timeout = 60, Reintentos = 3, Debug = true]
💡 Tip kawaii: El patrón "defaults + overrides" con Record.Combine es muy útil para funciones personalizadas con muchos parámetros opcionales. Defines los valores por defecto y sólo el usuario sobrescribe los que necesita cambiar.
🔄
Convertir Records
Record.FromList / Record.FromTable
Intermedio
Sintaxis
Record.FromList(list as list, fields as any) as record
Record.FromTable(table as table) as record
¿Qué hace?
Record.FromList crea un record desde una lista de valores y una lista de nombres de campo. Record.FromTable crea un record desde una tabla con columnas Name y Value.
Ejemplo
// Desde lista
Record.FromList({"Ana", 25, "Madrid"}, {"Nombre", "Edad", "Ciudad"})
// [Nombre = "Ana", Edad = 25, Ciudad = "Madrid"]
// Desde tabla de parámetros (patrón muy usado en PQ)
let
tablaParams = #table({"Name", "Value"}, {
{"Servidor", "prodserver"},
{"BaseDatos", "ventas"},
{"Puerto", 1433}
}),
config = Record.FromTable(tablaParams)
in config[Servidor] // "prodserver"
📌 Buena práctica: El patrón de tabla de parámetros + Record.FromTable es la forma estándar de gestionar configuración en Power Query. Crea una tabla llamada "Parametros" con columnas Name/Value y conviértela a record para acceder a los valores por nombre.
🔮
Patrones Prácticos
Filas como Records — tabla{n} y Table.First
Intermedio
¿Qué hace?
En M, cada fila de una tabla es un record. Puedes acceder a una fila específica con tabla{indice} (base 0) o con Table.First. Esto es muy útil para leer valores de tablas de parámetros.
Ejemplo
let tabla = #table({"Nombre","Valor"}, {{"IVA", 0.21}, {"IRPF", 0.15}})
in [
// Acceder a la primera fila como record
primeraFila = tabla{0}, // [Nombre = "IVA", Valor = 0.21]
// Acceder a un campo de la primera fila
iva = tabla{0}[Valor], // 0.21
// Buscar por condición
irpf = tabla{[Nombre = "IRPF"]}[Valor] // 0.15 (búsqueda por campo)
]
💡 Tip kawaii: La sintaxis tabla{[Campo = "valor"]}[OtroCampo] es como un BUSCARV de M: busca la fila donde Campo = "valor" y devuelve el valor de OtroCampo. ¡Mucho más limpio que un join completo!
🚀 ¡Records dominados! Ahora explora las Funciones de Transformación para combinadores, comparadores y separadores avanzados.