SELECTSELECT

SELECT

SnowflakeのSELECT *で列を除外・リネーム

By Ian WhitestoneDec 17, 20225 min read

このページはEnglishDeutschEspañolFrançaisItalianoPortuguêsでもご覧いただけます。

なぜEXCLUDEとRENAMEが必要なのか?

Snowflakeは2022年11月のリリースで、EXCLUDERENAMEという新しいSQL構文をひっそりと追加しました。これにより、SELECT 形式のクエリで特定の列を除外したりリネームしたりできるようになります。本番外のSQLワークフローでは、以下のような `SELECT ` の探索的クエリを実行する場面が非常に多いため、これは特に嬉しいアップデートです。

select *
from table
where id = 5

特定のレコードや一部のレコードを調べるためにこうしたクエリがよく使われます。しかし、特定の列(たとえばサイズの大きいテキスト列)を除外したい、あるいは列名を変えたい場合はどうでしょうか。これまでは、必要な列をすべて書き出した上で、リネームしたい列には従来通りAS構文を使うしかありませんでした。

select
  column_1,
  column_2,
  column_3 as column_3_renamed,
  column_4,
  column_5,
  column_6,
  column_7,
  column_8,
  column_9, -- columns 10 and 11 are intentionally left out
  column_12
from table
where id = 5

素早く答えを得たいときには、なかなか面倒です。

SnowflakeのSELECT \*文で列を除外する方法

列を一つひとつ書き出す代わりに、テーブルから除外したい列だけを指定したい——これはユーザーからよく寄せられる要望の一つです¹。多くの場合、含めたい列より除外したい列の方がはるかに少ないため、こちらの書き方の方がずっと効率的です。Snowflakeのバージョン6.37以降、SELECT *形式のクエリにEXCLUDE句を加えて、テーブルから取得したくない列を1つ以上指定できるようになりました。

select
  *
  exclude(column_10, column_11)
from table
where id = 5

単一の列を除外することもできます。

select
  *
  exclude (column_10)
from table
where id = 5

単一列の場合、括弧は省略可能です。上記のSQLは次のようにも書けます。

select
  *
  exclude column_10
from table
where id = 5

SnowflakeのEXCLUDEを複数テーブルで使う

列を除外したくなるもう一つの典型例が、複数テーブルを結合するケースです。次のようなクエリを思い浮かべてください²。

select
  orders.*,
  customers.* exclude customer_id,
  items.* exclude order_id
from orders
join customers
  on orders.customer_id=customers.customer_id
join items
  on orders.order_id=items.order_id

この例では、order_idcustomer_idが複数のテーブルに存在するため、出力にそれぞれ2つずつ含まれてしまいます。SQLを次のように書き換えれば、これらを簡単に除外できます。

select
  orders.*,
  customers.* exclude customer_id,
  items.* exclude order_id
from orders
join customers
  on orders.customer_id=customers.customer_id
join items
  on orders.order_id=items.order_id

BigQueryやDatabricksのEXCEPTに相当するSnowflakeの構文

SnowflakeのEXCLUDE構文は、BigQueryDatabricksEXCEPT構文に似ています。

-- Snowflake
select
  *
  exclude(column_10, column_11)
from table

-- BigQuery/Databricks
select
  *
  except(column_10, column_11)
from table

DuckDBに馴染みがある方ならお気づきの通り、SnowflakeはDuckDBと同じEXCLUDE構文を採用しています。両者ともこの機能にEXCEPTキーワードを使わなかったのは、EXCEPTすでに集合演算で使われているためと考えられます。

本番のSQLコードでEXCLUDEを使うべきか?

この新しい構文はアドホックなワークフローを効率化するうえでは非常に便利ですが、本番のSQLコードでの使用はおすすめしません。本番では、選択する列を明示的に書き出す方が安全です。すべての列名を書き出すことで可読性や監査性が高まり、コードを読む人はどのテーブルからどの列を使っているのかを一目で把握できます。エラーの内容も明確になります。テーブルから列が突然削除された場合、SQLコードはその時点で失敗してくれます。これは、欠落した列のせいで下流のアプリケーションが予期せずエラーになるよりも、はるかに望ましい挙動です。

SnowflakeのEXCLUDEはクエリプランやパフォーマンスに影響するか?

いいえ、影響しません。EXCLUDEキーワードで一部の列を除外しても、すべての列を明示的に書き出した場合とクエリプランやパフォーマンスは変わりません。実際にSnowflakeアカウント上のデータセットで両方のクエリを実行し、それぞれのクエリプロファイルを比較すれば確認できます。

SnowflakeのSELECT \*文で列をリネームする方法

これまではSELECT *クエリで列を一つでもリネームしたい場合、すべての列名を書き出す必要がありました。新しいRENAME機能を使えば、全列を選択しつつ、必要な列だけを手軽にリネームできます。

select
  *
  rename (column_3 as column_3_renamed, column_5 as column_5_renamed)
from table
where id = 5

1〜2列をリネームするためだけに全フィールドを列挙するより、ずっとスマートです。

-- old method 👎
select
  column_1,
  column_2,
  column_3 as column_3_renamed,
  column_4,
  column_5 as column_5_renamed,
  column_6,
  ...
  column_12
from table
where id = 5

EXCLUDEと同様、単一列に対しても使え、括弧は省略可能です。

select
  *
  rename (column_3 as column_3_renamed)
from table
where id = 5

EXCLUDEとRENAMEを組み合わせる

EXCLUDERENAMEは、次のように組み合わせて使うこともできます。

select
  *
  exclude(column_10, column_11)
  rename column_3 as column_3_renamed
from table
where id = 5

記事冒頭のコードと比べると、見違えるほどすっきりします。

select
  column_1,
  column_2,
  column_3 as column_3_renamed,
  column_4,
  column_5,
  column_6,
  column_7,
  column_8,
  column_9, -- columns 10 and 11 are intentionally left out
  column_12
from table
where id = 5

注釈

  1. 需要の大きさを示す一例として、約14年前に投稿されたこのStack Overflowの質問は、130万回以上閲覧され、1,000を超える賛成票を集めています。

  2. この例のきっかけをくれたNate Sooterさんの最近のツイートに感謝します!

Ian Whitestone・Co-founder & CEO of SELECT

Ianは、Snowflakeのコスト管理・最適化を提供するSaaSプラットフォームSELECTのCo-founder兼CEOです。SELECTを立ち上げる以前は、ShopifyとCapital Oneでフルスタックのデータサイエンス・エンジニアリングチームを6年間率いていました。Shopifyでは、データウェアハウスの最適化とコスト可視性の向上を主導しました。