Lezione 3.5
Linguaggio M
Modulo 03 · Lezione 3.5 · Livello Base

Il linguaggio M: leggere i passaggi e l'editor avanzato

Power Query "scrive M per te". Saperlo leggere — e a volte ritoccarlo — è ciò che distingue chi usa Power BI da chi lo padroneggia. In questa lezione ti faccio capire la sintassi let…in, le variabili, le funzioni più usate, l'editor avanzato.

  • ⏱ Tempo stimato: ~30 min + esercizi
  • 🎯 Prerequisiti: L3.1, L3.2, L3.3, L3.4
  • 🛠 Software: Power BI Desktop
1

La struttura let … in

Ogni query M ha questa forma:

Forma generale di una query M
let
    NomeStep1 = espressione1,
    NomeStep2 = espressione2 ( riferisce NomeStep1 ),
    NomeStep3 = espressione3 ( riferisce NomeStep2 ),
    ...
    UltimoStep = espressioneFinale
in
    UltimoStep

Punti chiave:

  • let apre la lista delle variabili (gli step).
  • Ogni step assegna un nome a un valore o tabella.
  • Gli step sono separati da virgola (l'ultimo no).
  • in indica cosa restituire (di solito l'ultimo step).
  • I nomi possono contenere spazi se messi tra #"...": #"Filtra anni".
2

Tipi di valore in M

I tipi base:

Glossario veloce
number
Numero (intero o decimale). Es. 42, 3.14.
text
Stringa. Es. "Mario".
logical
Booleano. Es. true, false.
date / datetime / time / duration
Date e orari. Es. #date(2026,5,26), #datetime(2026,5,26,9,0,0).
null
Valore mancante.
list
Sequenza ordinata. Es. {1, 2, 3} o {"a","b","c"}.
record
Coppie chiave-valore. Es. [Nome="Mario", Eta=30].
table
Tabella tipica di righe e colonne (quella che torna dalla maggior parte delle query).
function
Funzione definita dall'utente o di sistema.
binary
Dati binari (contenuto di file, ecc.).

Esempi pratici nelle espressioni:

M
// Numero
TassaIva = 0.22

// Stringa
Saluto = "Ciao " & [Cliente]

// Data letterale
Inizio = #date(2026, 1, 1)

// Lista
AreeNord = {"Lombardia","Veneto","Piemonte"}

// Record
ConfigCliente = [TipoListino="Pro", Sconto=0.10]

// Tabella inline
Festivi = #table({"Data","Festa"},
    {{#date(2026,1,1), "Capodanno"},
     {#date(2026,4,25), "Liberazione"}})
3

Le famiglie di funzioni più usate

La libreria standard M ha centinaia di funzioni. Sono raggruppate per namespace:

  • Table.* — tutto ciò che opera su tabelle: filtra, raggruppa, joina, trasforma colonne. Esempi: Table.SelectRows, Table.AddColumn, Table.NestedJoin, Table.Group.
  • Text.* — manipolazione stringhe. Esempi: Text.Upper, Text.Trim, Text.Contains, Text.Split.
  • Number.* — operazioni numeriche. Esempi: Number.Round, Number.Abs, Number.FromText.
  • Date.* / DateTime.* / Time.* — operazioni temporali. Esempi: Date.Year, Date.AddMonths, DateTime.LocalNow.
  • List.* — operazioni su liste. Esempi: List.Sum, List.Contains, List.Distinct.
  • Record.* — operazioni su record. Esempi: Record.Field, Record.HasFields.
  • Splitter.* / Combiner.* / Replacer.* — helper per split, combine, sostituzioni (usati dentro Table.SplitColumn ecc.).
  • Sql.*, Excel.*, Csv.*, Json.*, Web.* — connettori per ciascuna sorgente.
IntelliSense in PQ Editor
Apri Advanced Editor (View → Advanced Editor): mentre scrivi, Power Query suggerisce le funzioni del namespace e i parametri. Vale come la documentazione integrata.
4

L'Advanced Editor in pratica

Dove: nel Power Query Editor → tab View → Advanced Editor. Vedi il codice M completo della query corrente. Puoi:

  • Riordinare manualmente gli step (con cautela).
  • Rinominare step.
  • Aggiungere step a mano (utili per cose che il wizard non offre).
  • Refactoring più complessi (es. estrarre logica in una funzione riusabile).
Errori comuni nell'editor
  • Dimenticare la virgola tra gli step → "Expecting comma or end of let".
  • Mettere una virgola dopo l'ultimo step → "Expecting another statement".
  • Riferirsi a uno step inesistente o errore di battitura nel nome.
  • Parentesi tonde/graffe sbilanciate.
5

Funzioni custom in M

Puoi definire una funzione assegnandola a uno step:

Funzione che converte un numero in fascia
AssegnaFascia = (importo as number) as text =>
    if importo >= 1000 then "Alto"
    else if importo >= 100 then "Medio"
    else "Basso",

// Uso della funzione su una colonna
ConFascia = Table.AddColumn(Tabella, "Fascia",
    each AssegnaFascia([Importo]), type text)

Le funzioni custom sono potenti soprattutto quando le metti come query separata (right-click sul pannello Queries → New Query → Blank Query, poi incolli il codice). Le richiami da altre query come NomeFunzione([Colonna]).

6

each, _ e [NomeColonna] — la sintassi che confonde

Quando vedi:

M
Table.SelectRows(Tabella, each [Importo] > 100)

each è zucchero sintattico per "funzione anonima a 1 parametro". È equivalente a:

M
Table.SelectRows(Tabella, (riga) => riga[Importo] > 100)

_ è il parametro implicito: dentro each, _è la riga corrente, e [NomeColonna] è il valore di quella colonna nella riga.

Three forme equivalenti per filtrare per Importo > 100
Table.SelectRows(Tabella, each [Importo] > 100)
Table.SelectRows(Tabella, each _[Importo] > 100)
Table.SelectRows(Tabella, (r) => r[Importo] > 100)
7

Errori M comuni e come leggerli

'Expression.Error: The column ... was not found'
Uno step riferisce una colonna che a quel punto della pipeline non c'è (renamed o removed prima). Verifica gli step precedenti.
'DataFormat.Error: We couldn't convert to Number'
Stai cambiando tipo a Number ma una cella ha un valore non numerico (es. "N/A"). Sostituisci prima o cambia il tipo a Text e filtra/converti selettivo.
'Expression.SyntaxError: Token Comma expected'
Hai dimenticato la virgola dopo uno step. Apri l'Advanced Editor e cerca la riga dell'errore.
Query 'fa lenta' dopo modifica
Hai messo uno step che rompe il folding. Right-click → View Native Query. Sposta o riscrivi.
8

Esercitazioni

Esercizio 1Base

Leggi una query M

Consegna

Spiega cosa fa questa query, step per step:

M
let
    Source = Csv.Document(File.Contents("C:\Dati\v.csv"), [Delimiter=";", Encoding=1252]),
    Header = Table.PromoteHeaders(Source, [PromoteAllScalars=true]),
    Tipo = Table.TransformColumnTypes(Header, {{"Data", type date},{"Importo", type number}}, "it-IT"),
    Filtro = Table.SelectRows(Tipo, each [Data] >= #date(2025,1,1)),
    Anno = Table.AddColumn(Filtro, "Anno", each Date.Year([Data]), Int64.Type)
in
    Anno
Esercizio 2Base

Rinomina gli step

Consegna

Nell'Advanced Editor della query sopra, rinomina Source CSVOrigine, TipoCambiaTipi, Filtro FiltraDal2025. Ricordati di aggiornare i riferimenti nei passi successivi.

Esercizio 3Base

Aggiungi uno step manuale

Consegna

Dopo lo step "Anno", aggiungi a mano uno step "Trimestre" che calcoli Date.QuarterOfYear([Data]) e lo metta in una colonna intera. Ricontrolla la sintassi.

Esercizio 4Intermedia

Funzione custom 'AssegnaFascia'

Consegna

Crea una funzione M in una query separata "fnAssegnaFascia" che prende un importo e restituisce "Alto" / "Medio" / "Basso". Poi usala in Table.AddColumn.

Esercizio 5Intermedia

Sostituisci each con (r) =>

Consegna

Riscrivi questa espressione usando la forma esplicita di funzione anonima:

M
Table.SelectRows(Tabella, each [Importo] > 100 and [Stato] = "OK")
Esercizio 6Intermedia

Tabella inline di Festivi

Consegna

Crea una query "Festivi" come tabella inline M con 3 festività italiane (Capodanno, Liberazione 25 aprile, Ferragosto). Poi fai Merge con una tabella "Calendario" per avere una colonna "Festa" nei giorni festivi.

Esercizio 7Avanzata

Refactoring: estrai pattern in funzione

Consegna

Hai 5 query che fanno la stessa pulizia base (PromoteHeaders + Change Type + Trim). Come estrai questo pattern in una funzione condivisa e la richiami nelle 5?

Esercizio 8Avanzata

Debug di errori M

Consegna

Questa query fallisce con "Expression.SyntaxError: Token Comma expected". Trova l'errore.

M
let
    Source = Excel.Workbook(File.Contents("vendite.xlsx"), null, true)
    Foglio = Source{[Name="Sheet1"]}[Data],
    Tipo = Table.TransformColumnTypes(Foglio, {{"Data", type date}})
in
    Tipo
9

Quick check finale

Quick check

Cosa apre 'in' in una query M?

Quick check

Cos'è 'each [Importo] > 100' in M?

Hai finito il Modulo 3 — e tutto il Livello BASE ✓✓

Hai pulito i dati, scelto le modalità di connessione, capito Get Data, Gateway, OneLake e Power Query in profondità. Sei pronto per il Livello Intermedio: nel Modulo 4 entriamo nella modellazione con star schema e relazioni.