SnowflakeのWebインタフェースからデータロードする

以下の公式ドキュメントを試してみた、という記事です。Snowflakeにある程度慣れていれば公式ドキュメントを読むか、雰囲気で操作した方が早いです。  
[ウェブインターフェイスを使用したデータのロード](https://docs.snowflake.com/ja/user-guide/data-load-web-ui)

https://docs.snowflake.com/ja/user-guide/data-load-web-ui

## やりたいこと

ローカルにあるCSVファイルをSnowflakeにさっとアップロードしてデータ分析したい…というシチュエーションがあるかと思います。  
以前はSnowSQLというCLIクライアントが必須でしたが、2023年4月からSnowflakeのWebインタフェースであるSnowsightからアップロードしてデータロードできるようになりました。(2023年8月時点でPublic Preview)  

## 前提条件

以下の権限が必要です。より正確な情報は公式ドキュメントを確認してください。  

| 対象 | 権限 |
| --- | --- |
| データベース | USAGE |
| スキーマ | USAGE |
| テーブル | OWNERSHIP  |

## 試してみる：下準備

今回は構造化データ(CSVのような表形式のデータ)で試してみましょう。  

権限を確認しておきたいのでお試し用のデータベースやユーザを作っておきます。  

```sql:SQLワークシート
-- ウェアハウスを選択
USE WAREHOUSE COMPUTE_WH;
-- データベースを作成
CREATE OR REPLACE DATABASE UPLOAD_TEST;
-- スキーマを作成
CREATE OR REPLACE SCHEMA UPLOAD_TEST.UPLOAD_TEST;
-- テーブルを作成。今回は最初からデータ型が分かっている想定
-- やることは変わらないはずだが念のためにファイル形式別にテーブルを作る
CREATE OR REPLACE TABLE UPLOAD_TEST.UPLOAD_TEST.WORK_CSV (
    id int primary key,
    name varchar(16),
    value1 int,
    value2 int,
    dt date
);
CREATE OR REPLACE TABLE UPLOAD_TEST.UPLOAD_TEST.WORK_TSV (
    id int primary key,
    name varchar(16),
    value1 int,
    value2 int,
    dt date
);
CREATE OR REPLACE TABLE UPLOAD_TEST.UPLOAD_TEST.WORK_PARQUET (
    id int primary key,
    name varchar(16),
    value1 int,
    value2 int,
    dt date
);
-- ロールを作成してユーザに割り当て
CREATE ROLE UPLOAD_TEST;
GRANT ROLE UPLOAD_TEST TO USER SAKATOKU;
-- データベースとスキーマの権限を作成したロールに付与
GRANT USAGE ON DATABASE UPLOAD_TEST TO ROLE UPLOAD_TEST;
GRANT USAGE ON SCHEMA UPLOAD_TEST.UPLOAD_TEST TO ROLE UPLOAD_TEST;
GRANT MODIFY ON SCHEMA UPLOAD_TEST.UPLOAD_TEST TO ROLE UPLOAD_TEST;
GRANT OWNERSHIP ON TABLE UPLOAD_TEST.UPLOAD_TEST.WORK_CSV TO ROLE UPLOAD_TEST;
GRANT OWNERSHIP ON TABLE UPLOAD_TEST.UPLOAD_TEST.WORK_TSV TO ROLE UPLOAD_TEST;
GRANT OWNERSHIP ON TABLE UPLOAD_TEST.UPLOAD_TEST.WORK_PARQUET TO ROLE UPLOAD_TEST;
-- データロードにはウェアハウスが必須
GRANT USAGE ON WAREHOUSE COMPUTE_WH TO ROLE UPLOAD_TEST;
-- 作成したユーザに切り替え
USE ROLE UPLOAD_TEST;
USE DATABASE UPLOAD_TEST;
USE SCHEMA UPLOAD_TEST;
```

今回は構造化データとしてランダム値を数万行並べたCSVファイル、TSVファイル、Parquetファイルを用意しました。 
 
https://github.com/Sakatoku/gen-dummy 

## 試してみる：Snowsightからデータロードする

ここからはGUIをポチポチしていきます。  
なお、データロードするときはコンピューティングリソースを使うのでウェアハウスを選択しておく必要があります。  

1\. データロード先のテーブルを選択して「データをロード」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/7dc5eb69-50c4-41e5-e87a-0fe0e4ec5a1a.png)

2\. (日本語設定だと表示がズレていますが…)「閲覧」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/49662b5e-dfac-14ae-df44-a1a607eb725a.png)

3\. ファイルダイアログでファイルを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/0c005253-a8c1-c6d8-137d-b5c954ab22e5.png)

4\. 選択したファイルのファイル名とファイルサイズが表示されるので確認したら「次へ」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/5421e47b-a03a-e55f-b711-403664195416.png)

プログレスバーが表示されてアップロードが始まるのでしばらく待ちましょう。  
なお、Snowsightからデータロードするとき、最大50MBのファイルに対応しているそうです。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/7700e485-6660-2e10-cc39-c19bba3aa682.png)

5\. ファイル形式とエラーが発生したときの挙動を指定します。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/a91cedcb-b453-425e-686a-8aa9805def70.png)

対応しているファイル形式は以下の通りだそうです。  
- CSV or TSV
- JSON
- Avro
- ORC
- Parquet
- XML

また、エラーが発生したときの挙動は```ABORT_STATEMENT```と```CONTINUE```が選択可能でした。  
これらのオプションについての詳細は```COPY INTO```の```ON_ERROR```オプションを参照してください。  

参考：[COPY INTO <テーブル> | Snowflake Documentation](https://docs.snowflake.com/ja/sql-reference/sql/copy-into-table)

https://docs.snowflake.com/ja/sql-reference/sql/copy-into-table

6\. データロード
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/f9f6a169-1b22-167d-53a6-2769c1173d30.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/82c24c30-c2b9-2991-8e1c-dad1e645ec32.png)

100万行、37MBのCSVファイルは最小のウェアハウスで10秒くらいでデータロードできました。  
データロード先のテーブルに試しにクエリを実行してみると、問題なさそうです！  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/6bd104c6-6a04-ed2c-f92e-355f29c61085.png)

## ファイル形式による差異

TSVファイルの場合はCSVファイルとほとんど差異はありません。  
フィールド区切り文字を適切なものに変更するだけ。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/881f6e49-484c-64c6-079f-e91e411dca84.png)

Parquetファイルの場合はCSVファイルとはファイル固有のオプションが色々違います。こちらの方がシンプルですね。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/8661e76c-fce4-a754-078f-0b15e742e8d3.png)

ParquetファイルがGZIP圧縮されていても問題なくデータロードできます。オプションを指定する必要なし。  
手元にgz.parquetのファイルがあることはあまりないかもしれませんが、GZIP圧縮するとたいてい4割くらいファイルサイズが小さくなるのでお得感ありますね。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/72226527-3a91-f094-2cae-abc30f89770c.png)


## その他

ファイル形式を指定するダイアログで「SQLを表示」というボタンを押してみると、以下のようなSQLを確認できました。  
アップロードしたファイルはこういう場所に置かれているみたいです。　　

```sql
COPY INTO "UPLOAD_TEST"."UPLOAD_TEST"."WORK_CSV"
FROM '@"UPLOAD_TEST"."UPLOAD_TEST"."%WORK_CSV"'
FILES = ('__snowflake_temp_import_files__/dummy.csv')
FILE_FORMAT = (
    TYPE=CSV,
    SKIP_HEADER=1,
    FIELD_DELIMITER=',',
    TRIM_SPACE=FALSE,
    FIELD_OPTIONALLY_ENCLOSED_BY=NONE,
    DATE_FORMAT=AUTO,
    TIME_FORMAT=AUTO,
    TIMESTAMP_FORMAT=AUTO
)
ON_ERROR=ABORT_STATEMENT
PURGE=TRUE
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2917580/2ecb5136-5947-e8ba-5f3b-011bd1b07fa9.png)