実務で使えるPower Query小技・テクニック | @ で前のステップを参照する

Excel VBA Power Query M Formula Language
スポンサーリンク
スポンサーリンク

「@ で前のステップを参照する」とは何か

Power Query(M言語)で使われる @ は、「同じ名前のステップが“関数”として再定義されてしまったときに、元のステップ(値)を明示的に参照するための記号」です。 もう少し噛み砕くと、

「名前がかぶってしまったときに、“元のステップの値のほう”を指し示すための特別なラベル」

だと理解すると分かりやすくなります。

通常のクエリではあまり登場しませんが、

  • ステップ名と関数名が同じになったとき
  • 自動生成されたコードで「@ステップ名」が出てきたとき などに、「これ何?」となりがちなポイントです。

ここでは、初心者向けにステップバイステップで、 @ がどういう場面で使われ、何をしているのかを丁寧に解説していきます。

M言語の「ステップ」と「名前」の関係を整理する

let ~ in の中でステップは「名前付きの値」

Power Query の Mコードは、基本的に次のような形になっています。

let
    Source = Excel.CurrentWorkbook(){[Name="売上"]}[Content],
    Filtered = Table.SelectRows(Source, each [金額] > 1000),
    Result = Table.Sort(Filtered, {{"金額", Order.Descending}})
in
    Result
Power Query

ここでの

  • Source
  • Filtered
  • Result

は、それぞれ「名前付きの値」です。 M言語では、「名前=ステップ名」と「その中身の値」が1対1で対応していると考えてよいです。

通常は、この名前をそのまま後続のステップで参照します。

Table.SelectRows(Source, …)
Table.Sort(Filtered, …)
Power Query

このときは、まだ @ は登場しません。

名前が「関数」として再定義されるとややこしくなる

問題が起きるのは、同じ名前を「関数」としても使ってしまったときです。

例として、次のようなコードを考えます。

let
    Source = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    // ここで Source という名前を「関数」として再定義してしまう
    Source = (t as table) as table =>
        Table.SelectRows(t, each [金額] > 1000),

    Filtered = Source(Excel.CurrentWorkbook(){[Name="売上"]}[Content])
in
    Filtered
Power Query

ここでは、

  1. 最初の Source は「売上テーブル」という値
  2. その後の Source は「テーブルを受け取ってフィルタする関数」

という、同じ名前に別の意味を持たせてしまっている状態です。

このようなときに、「元の Source(売上テーブルのほう)を参照したい」となったらどうするか――そこで @ が登場します。

@ を使って「元のステップ」を参照する

@ステップ名 で「元の値」を指す

先ほどの例を、@ を使って書き直してみます。

let
    Source = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    // Source という名前を関数として再定義
    Source = (t as table) as table =>
        Table.SelectRows(t, each [金額] > 1000),

    // @Source で「元のステップの Source(売上テーブル)」を参照
    Filtered = Source(@Source)
in
    Filtered
Power Query

ここでのポイントは、

  • Source:今は「関数」
  • @Source:元のステップの Source(売上テーブル)

という役割分担になっていることです。

@ステップ名 は、「関数として再定義される前の、そのステップ名が指していた元の値」を参照するための記号だと理解していただくと、挙動がスッと入ってきます。

ステップバイステップで「@ の必要になる場面」を理解する

ステップ1:名前の“上書き”が起きる状況をイメージする

M言語では、同じ let ブロックの中で同じ名前を再定義すると、 後から書いたほうが優先されます。

let
    X = 1,
    X = 2
in
    X   // 結果は 2
Power Query

この「上書き」が、

  • ステップ名(値)
  • 関数名

の両方にまたがって起きると、 「元のステップを参照したいのに、今の名前は関数を指している」という状況になります。

そこで、「元のステップを指すための特別なラベル」として @ が用意されている、という流れです。

ステップ2:@ がないとどう困るか

先ほどの例で、@Source を使わずに書くとこうなります。

let
    Source = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    Source = (t as table) as table =>
        Table.SelectRows(t, each [金額] > 1000),

    Filtered = Source(Source)
in
    Filtered
Power Query

ここでの Source(Source) は、

  • 関数 Source
  • 引数として「関数 Source」を渡している

というおかしな状態になります。

本来やりたいのは、

  • 関数 Source
  • 引数として「元のステップの Source(売上テーブル)」を渡す

ことなので、@Source が必要になるわけです。

ステップ3:自動生成コードで @ が出てきたときの読み方

Power Query が自動生成したコードの中に、 @ステップ名 が出てくることがあります。

そのときは、

「このステップ名は、どこかで関数としても使われていて、 @ステップ名 は“元のステップの値のほう”を指しているんだな」

と読み解いていただくと、コードの意図が理解しやすくなります。

@ は「名前の衝突を解決するための安全装置」だと捉えると、 怖がらずに付き合えるようになります。

実務での @ の使いどころと注意点

1. 自分で積極的に使う場面は多くない

正直なところ、通常の実務クエリでは、 自分から積極的に @ を書く場面はあまり多くありません。

理由はシンプルで、

  • ステップ名と関数名を同じにしない
  • 名前の再定義を避ける

という方針で書いていけば、 そもそも @ が必要な状況を作らずに済むからです。

実務では、

  • Source は「元データ」
  • FilterSales は「フィルタ関数」
  • TransformSales は「変換関数」

というように、役割ごとに名前を分けておくほうが安全で読みやすいです。

2. それでも @ を理解しておくべき理由

それでも @ を理解しておくべきなのは、

  • 自動生成されたコードに @ が出てくることがある
  • 他の人が書いた高度な Mコードで @ が使われていることがある
  • ライブラリ的な関数を作るときに、名前の衝突を避けるための知識として役立つ

といった理由からです。

「@ は、同じ名前の“元のステップ”を指すための記号」 という理解を持っているだけで、 コードを読むときの不安がかなり減ります。

3. セキュリティ・品質の観点からの注意

名前の再定義は、セキュリティや品質の観点からも注意が必要です。

  • 元のステップ(生データ)と、加工後の関数が同じ名前だと、 どちらを参照しているのか分かりづらくなる
  • 誤って関数のほうを参照してしまい、意図しない処理が走る可能性がある
  • セキュリティチェック用の関数と、チェック対象のデータが同じ名前だと、レビューが難しくなる

そのため、

  • ステップ名と関数名は意図的に分ける
  • @ が必要になるような名前の衝突は、基本的に避ける

という方針が、実務では安全です。

@ は「最後の手段」であり、設計としては「使わなくて済むように名前を分ける」ほうが望ましいと考えていただくとよいです。

実務で使える @ の理解テンプレート

テンプレ1:元のステップと関数が同名になった例

let
    Source = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    Source = (t as table) as table =>
        Table.SelectRows(t, each [金額] > 1000),

    Filtered = Source(@Source)
in
    Filtered
Power Query

テンプレ2:名前を分けて @ を不要にした例

let
    Source = Excel.CurrentWorkbook(){[Name="売上"]}[Content],

    FilterSales =
        (t as table) as table =>
            Table.SelectRows(t, each [金額] > 1000),

    Filtered = FilterSales(Source)
in
    Filtered
Power Query

まとめ:@ を理解することは「名前と値の関係」を理解すること

M言語で @ で前のステップを参照する というのは、 「同じ名前が“値”と“関数”の両方に使われてしまったときに、元のステップの値を明示的に指し示すための仕組み」だと整理できます。

ポイントは、

  • ステップ名は「名前付きの値」
  • 同じ名前を関数として再定義すると、元の値と関数が同名になる
  • @ステップ名 は、そのうち「元のステップの値」のほうを参照するための記号
  • 実務では、名前を分けて設計することで、@ が必要な状況を避けるのが安全

ということです。

@ 自体を多用する必要はありませんが、 「@が出てきたら、名前の衝突が起きていて、元のステップを参照しているんだな」 と読み解けるようになっておくことは、 Power Query を深く理解し、他者のコードも安心して読めるようになるうえで、とても大きな意味があります。

タイトルとURLをコピーしました