Sintaxis
Excel.Workbook(fileContents as binary, optional useHeaders as nullable logical, optional delayTypes as nullable logical) as table
¿Qué hace?
Lee un archivo Excel (binario) y devuelve una tabla con las hojas, tablas y rangos con nombre disponibles. Cada fila representa un objeto del libro.
Ejemplo
// Leer una hoja específica de un Excel
let
Origen = File.Contents("C:\datos\ventas.xlsx"),
Libro = Excel.Workbook(Origen, true, true),
Hoja_Ventas = Libro{[Item="Ventas",Kind="Sheet"]}[Data]
in
Hoja_Ventas
// Leer tabla con nombre "TblVentas"
let
Libro = Excel.Workbook(File.Contents("C:\datos\ventas.xlsx"), true),
Tabla = Libro{[Item="TblVentas", Kind="Table"]}[Data]
in
Tabla
💡 Tip kawaii: Usa Kind="Table" en lugar de Kind="Sheet" cuando los datos están formateados como tabla Excel. Las tablas Excel son más estables ante inserciones de filas y columnas.
Sintaxis
Csv.Document(source as any, optional columns as any, optional delimiter as any, optional extraValues as nullable number, optional encoding as nullable number) as table
¿Qué hace?
Parsea un contenido CSV (texto o binario) y lo convierte en tabla. El parámetro columns puede ser un número (de columnas) o un record con opciones completas incluyendo separador, encoding y manejo de cabecera.
Parámetros del record de opciones
Delimiter — Separador: ",", ";", "\t" (tabulador)
Encoding — Codificación: 1252 (Windows-1252), 65001 (UTF-8)
QuoteStyle — QuoteStyle.Csv (por defecto)
Ejemplo
// CSV con punto y coma (formato español)
Csv.Document(
File.Contents("C:\datos\ventas.csv"),
[Delimiter=";", Encoding=65001, QuoteStyle=QuoteStyle.Csv]
)
// Con cabecera y tipos automáticos
let
Origen = Csv.Document(File.Contents("C:\datos\ventas.csv"),
[Delimiter=";", Encoding=65001]),
ConCabecera = Table.PromoteHeaders(Origen),
ConTipos = Table.InferColumnTypes(ConCabecera)
in
ConTipos
Sintaxis
Json.Document(jsonText as any, optional encoding as nullable number) as any
¿Qué hace?
Parsea un texto o binario JSON y devuelve el valor M correspondiente: un record si es objeto {}, una lista si es array [], o un valor primitivo.
Ejemplo
// Leer JSON local
let
contenido = File.Contents("C:\datos\config.json"),
parseado = Json.Document(contenido),
servidor = parseado[servidor],
basedatos = parseado[basedatos]
in [servidor = servidor, basedatos = basedatos]
// Convertir array JSON a tabla
let
json = Json.Document("[{""id"":1,""nombre"":""Ana""},{""id"":2,""nombre"":""María""}]"),
tabla = Table.FromRecords(json)
in tabla
Sintaxis
Web.Contents(url as text, optional options as nullable record) as binary
¿Qué hace?
Hace una petición HTTP y devuelve el contenido como binario. Es el conector universal para APIs REST. Combínalo con Json.Document, Xml.Document o Csv.Document para procesar la respuesta.
Opciones principales
Headers — Record con cabeceras HTTP (Authorization, Content-Type, etc.)
Query — Record con parámetros de query string
Content — Binary para peticiones POST
RelativePath — Ruta relativa a la URL base
Timeout — Duración máxima de espera
Ejemplo
// GET básico a API REST
let
respuesta = Web.Contents("https://api.ejemplo.com/ventas"),
datos = Json.Document(respuesta)
in datos
// GET con parámetros de query y cabecera de autorización
let
respuesta = Web.Contents(
"https://api.ejemplo.com/datos",
[
Headers = [Authorization = "Bearer " & token,
#"Content-Type" = "application/json"],
Query = [anyo = "2024", region = "ES"]
]
),
datos = Json.Document(respuesta)
in datos
// POST con body JSON
let
body = Json.FromValue([filtro = "activos", limit = 100]),
respuesta = Web.Contents(
"https://api.ejemplo.com/consulta",
[Content = body,
Headers = [#"Content-Type" = "application/json"]]
),
datos = Json.Document(respuesta)
in datos
⚠️ Ojo con esto: Para que Power BI Service pueda actualizar datos de Web.Contents, la URL base debe ser fija (no dinámica). Si construyes la URL dinámicamente, usa RelativePath y Query para la parte variable — así PBI puede hacer query folding y gestionar la autenticación correctamente.
¿Qué hace?
Las APIs REST suelen devolver datos paginados. El patrón con List.Generate itera automáticamente por todas las páginas hasta obtener todos los datos.
Ejemplo
let
baseUrl = "https://api.ejemplo.com/registros",
pageSize = 100,
// Función que obtiene una página
obtenerPagina = (pagina as number) =>
let
resp = Web.Contents(baseUrl,
[Query = [page = Text.From(pagina), size = Text.From(pageSize)]]),
json = Json.Document(resp)
in json,
// Generar páginas hasta que venga vacía
todasLasPaginas = List.Generate(
() => [pagina = 1, datos = obtenerPagina(1)],
each List.Count(_[datos]) > 0,
each [pagina = _[pagina] + 1, datos = obtenerPagina(_[pagina] + 1)],
each _[datos]
),
// Combinar todo en una tabla
combinado = Table.FromRecords(List.Combine(todasLasPaginas))
in
combinado
📌 Buena práctica: Añade siempre un límite máximo de páginas para evitar bucles infinitos si la API tiene un bug: each _[pagina] <= 50 and List.Count(_[datos]) > 0.
Sintaxis
Sql.Database(server as text, database as text, optional options as nullable record) as table
Sql.Databases(server as text, optional options as nullable record) as table
¿Qué hace?
Conecta a SQL Server y devuelve una tabla con todos los objetos de la base de datos (tablas, vistas). Cada fila contiene el nombre y los datos del objeto en una columna [Data].
Ejemplo
// Conectar y leer tabla específica
let
bd = Sql.Database("servidor\instancia", "BaseDatos"),
ventas = bd{[Schema="dbo",Item="Ventas"]}[Data]
in ventas
// Con query SQL nativa
let
resultado = Sql.Database("servidor", "BaseDatos",
[Query = "SELECT * FROM dbo.Ventas WHERE Anyo = 2024"])
in resultado
// Con timeout personalizado
Sql.Database("servidor", "bd", [CommandTimeout = #duration(0,0,5,0)])
⚠️ Ojo con esto: Las queries SQL nativas (Query = "SELECT...") deshabilitan el query folding en pasos posteriores. Úsalas sólo para lógica que M no puede expresar eficientemente (CTEs complejas, funciones de ventana).
Conectores disponibles
// PostgreSQL
PostgreSQL.Database(server as text, database as text) as table
// MySQL
MySQL.Database(server as text, database as text) as table
// Oracle
Oracle.Database(server as text, optional options as nullable record) as table
// ODBC genérico
Odbc.DataSource(connectionString as text) as table
// OLE DB
OleDb.DataSource(connectionString as text) as table
¿Qué hace?
Conectores para diferentes motores de base de datos. Todos siguen el mismo patrón: devuelven una tabla navegable con los objetos de la base de datos.
Ejemplo
// PostgreSQL
let
bd = PostgreSQL.Database("localhost", "mi_bd"),
tabla = bd{[Schema="public", Item="clientes"]}[Data]
in tabla
Sintaxis
SharePoint.Files(url as text, optional options as nullable record) as table
SharePoint.Tables(url as text, optional options as nullable record) as table
¿Qué hace?
SharePoint.Files devuelve todos los archivos de una biblioteca de SharePoint como tabla (con columnas Name, Content, etc.). SharePoint.Tables devuelve las listas de SharePoint.
Ejemplo
// Leer todos los Excel de una carpeta de SharePoint
let
archivos = SharePoint.Files("https://empresa.sharepoint.com/sites/Datos/"),
soloExcel = Table.SelectRows(archivos, each Text.EndsWith([Name], ".xlsx")),
contenido = Table.AddColumn(soloExcel, "Datos",
each Excel.Workbook([Content], true)),
expandido = Table.ExpandTableColumn(contenido, "Datos",
{"Name", "Data"}, {"Hoja", "TablaHoja"}),
soloSheet = Table.SelectRows(expandido, each [Hoja] = "Datos")
in soloSheet
// Leer lista de SharePoint
SharePoint.Tables("https://empresa.sharepoint.com/sites/Datos/")
💡 Tip kawaii: El patrón "leer carpeta + expandir Excel" es uno de los más potentes de Power Query. Te permite combinar automáticamente todos los archivos Excel de una carpeta en una sola tabla, sin modificar la consulta cuando añades nuevos archivos.
Sintaxis
Folder.Files(path as text) as table
Folder.Contents(path as text, optional options as nullable record) as table
¿Qué hace?
Folder.Files devuelve todos los archivos de una carpeta (recursivo). Folder.Contents devuelve el contenido no recursivo (archivos y subcarpetas). Ambas incluyen columna Content con el binario de cada archivo.
Ejemplo
// Combinar todos los CSV de una carpeta
let
archivos = Folder.Files("C:\datos\informes\"),
soloCSV = Table.SelectRows(archivos, each [Extension] = ".csv"),
parseados = Table.AddColumn(soloCSV, "Tabla",
each Csv.Document([Content], [Delimiter=";", Encoding=65001])),
cabecera = Table.TransformColumns(parseados, {"Tabla",
each Table.PromoteHeaders(_)}),
combinado = Table.Combine(cabecera[Tabla])
in combinado
¿Qué hace?
Puedes crear parámetros de Power Query (tipo Parámetro) o leer valores de una tabla de configuración para hacer las conexiones dinámicas y fácilmente configurables sin tocar el código M.
Ejemplo — Tabla de parámetros
// 1. Crear tabla de parámetros en el modelo:
// Nombre | Valor
// Servidor | prodserver\sql2022
// BaseDatos | ventas_prod
// RutaArchivos | C:\datos\
// 2. Convertir a record
let
tablaParams = Parametros, // nombre de la consulta de parámetros
config = Record.FromTable(tablaParams)
in
// 3. Usar en conexión
Sql.Database(config[Servidor], config[BaseDatos])
📌 Buena práctica: Usa siempre una tabla de parámetros para servidores, rutas y configuración de entorno. Así puedes cambiar de entorno DEV → PRO modificando sólo una tabla, sin tocar ninguna consulta.