Snowflake のデータメトリック関数で、毎朝取り込んだテーブルを自動で確かめる|期待値で合否を決め、違反の日だけメールで知らせる

毎朝取り込むテーブルの NULL・重複・鮮度・件数を、Snowflake のデータメトリック関数(DMF)と期待値で確かめる一式を SQL つきで書きます。測った値と合否は2つのビューに自動で残り、違反があった日だけアラートでメールを送ります。試用の Snowflake で、期待値の違反と、重複している行の取り出しを確かめました。アラートの条件を真偽値のつもりで書いて失敗したことと、テーブルを作り直すと関連付けが外れることも書きます。本番に入れる SQL は、後半に1つにまとめています。

この記事をシェア:
目次 クリックで開く

毎朝取り込んでいる注文テーブルに同じ注文番号の行が二重に入っていても、集計の数字が合わないと言われるまで気づけないことがあります。チェックの SELECT を毎朝自分で実行するのは手間です。自動のチェックにしても、問題の日に知らせが来なければ役に立ちません。

Snowflake には、テーブルの NULL・重複・件数・鮮度を測るデータメトリック関数(DMF)があります。DMF をテーブルに関連付け、合否の基準を期待値で書いておくと、決めた時刻に値と合否が自動で残ります。そこにアラートを足すと、違反があった日だけメールで知らせられます。SQL は、試すための文と、本番に入れる一式に分けて載せました。

ここに載せる SQL と結果の画面は、データ基盤の構築を支援している当社が、試用の Snowflake で架空の注文データに対して実行したものです。

DMF と期待値で毎回の値と合否を残し、違反した日だけアラートで知らせる

DMF は、列の NULL の数や重複の数のような、データの性質を1つの値で返す関数です。その値が良いか悪いかは、DMF そのものは決めません。合否を決めるのは期待値で、DMF と期待値の組み合わせを、Snowflake はデータ品質チェックと呼んでいます。使えるのは Enterprise Edition 以上です。

今回は、注文テーブル ORDERS に DMF を5つ関連付けました。金額の NULL と注文番号の重複を数え、取り込みの鮮度と、予定の時刻の前24時間に入った件数を測ります。この4つには期待値を付けました。残りの ROW_COUNT は、テーブル全体の件数を記録するだけです。

DMF の値は、テーブルごとに決めた DMF のスケジュールの時刻に、自動で測られます。測った値と期待値の合否は SNOWFLAKE データベースの2つのビューに残るので、記録用のテーブルを自分で作る必要はありません。

違反を知らせるのはアラートです。アラートは、決めた時刻に条件の SQL を実行し、結果が1行以上あれば処理を動かす Snowflake の仕組みです。今回は、毎朝6時40分に期待値を評価し、違反があればメールを送るアラートを作りました。

データ品質チェックの一式。記録する側:注文テーブル ORDERS に DMF を5つ関連付け、4つに期待値を付ける。DMF のスケジュールの時刻に測られ、測った値は DATA_QUALITY_MONITORING_RESULTS、期待値の合否は DATA_QUALITY_MONITORING_EXPECTATION_STATUS のビューに残る。知らせる側:アラート CHECK_DQ が毎朝6時40分に期待値を評価し、違反した期待値があればストアドプロシージャ NOTIFY_DQ_VIOLATIONS を呼んで、SYSTEM$SEND_EMAIL でメールを送る。宛先は同じアカウントの、メールアドレスを確認済みのユーザー。メールが届いた日は、違反した期待値を見て SYSTEM$DATA_METRIC_SCAN で該当の行を取り出す。知らせが来ない朝のために、動かし始めてからも関連付けの一覧とアラートの実行履歴を見るデータ品質チェックの一式。記録する側:注文テーブル ORDERS に DMF を5つ関連付け、4つに期待値を付ける。DMF のスケジュールの時刻に測られ、測った値は DATA_QUALITY_MONITORING_RESULTS、期待値の合否は DATA_QUALITY_MONITORING_EXPECTATION_STATUS のビューに残る。知らせる側:アラート CHECK_DQ が毎朝6時40分に期待値を評価し、違反した期待値があればストアドプロシージャ NOTIFY_DQ_VIOLATIONS を呼んで、SYSTEM$SEND_EMAIL でメールを送る。宛先は同じアカウントの、メールアドレスを確認済みのユーザー。メールが届いた日は、違反した期待値を見て SYSTEM$DATA_METRIC_SCAN で該当の行を取り出す。知らせが来ない朝のために、動かし始めてからも関連付けの一覧とアラートの実行履歴を見る
一式の全体。上が値と合否を記録する側、下が違反を知らせる側

このあと本文に出てくる SQL は、検証用のデータベース TEST_DQ の中で、問題の行をわざと入れて確かめるためのものです。本番のテーブルに入れる一式は、後半に分けて載せました。

TEST_DQ に100行の注文テーブルを作り、DMF を SELECT で呼ぶ

先に1つ断っておきます。Snowflake のドキュメントのデータ品質の紹介ページには、「トライアルアカウントはこの機能をサポートしていません」とあります。一方、トライアルアカウントのページにある制限の一覧には、データ品質は挙がっていません。

今回の試用の環境では、試した操作はすべて動きました。それでも、試用の環境で試せる前提にはせず、自社の Enterprise Edition 以上のアカウントで確かめてください。

試したのは2026年10月21日の未明で、時刻はすべて日本時間です。環境は AWS の東京リージョンの試用の Snowflake で、ロールは ACCOUNTADMIN、ウェアハウスは X-Small にしました。

まず、検証用のデータベース TEST_DQ に注文テーブル ORDERS を作り、GENERATOR 関数で作った100行を入れます。名前は大文字にしています。あとの SELECT の WHERE で、データベース名を文字列として比べるからです。自分の名前に替えるときも、WHERE の ‘…’ の中は大文字で書きます。

USE ROLE ACCOUNTADMIN;
USE SECONDARY ROLES NONE;
USE WAREHOUSE COMPUTE_WH;
CREATE DATABASE IF NOT EXISTS TEST_DQ;
CREATE SCHEMA IF NOT EXISTS TEST_DQ.RAW;
USE SCHEMA TEST_DQ.RAW;
CREATE OR REPLACE TABLE ORDERS (ORDER_ID NUMBER, ORDER_DATE DATE, STORE STRING, AMOUNT NUMBER, LOADED_AT TIMESTAMP_LTZ);
INSERT INTO ORDERS SELECT SEQ4() + 1, '2026-10-20'::DATE, DECODE(MOD(SEQ4(), 2), 0, '渋谷店', '新宿店'), 1000 + MOD((SEQ4() + 1) * 7919, 9000), CURRENT_TIMESTAMP() FROM TABLE(GENERATOR(ROWCOUNT => 100));

LOADED_AT は、行を取り込んだ時刻の列です。型を TIMESTAMP_LTZ にしたのは、鮮度を測る FRESHNESS に渡すためです。ドキュメントで FRESHNESS の対象に挙がっている型は、DATE・TIMESTAMP_LTZ・TIMESTAMP_TZ の3つです。

自社のテーブルの時刻の列が TIMESTAMP_NTZ なら、渡せるかを先に確かめてください。列を渡さずに ON () とすると、FRESHNESS は最後に行が変わった時刻から測ります。

USE SECONDARY ROLES NONE は、USE ROLE で選んだロールの権限だけで試すための文です。理由は、マスキングポリシーの記事に書きました。

DMF は、SELECT の中で手で呼ぶこともできます。

USE SCHEMA TEST_DQ.RAW;
SELECT SNOWFLAKE.CORE.NULL_COUNT(SELECT AMOUNT FROM ORDERS) AS NULL_AMOUNT,
       SNOWFLAKE.CORE.DUPLICATE_COUNT(SELECT ORDER_ID FROM ORDERS) AS DUP_ORDER_ID;

結果は、NULL_AMOUNT も DUP_ORDER_ID も0でした。手で呼んだ分には DMF の料金はかからず、SELECT を実行したウェアハウスの料金だけがかかります。

テーブル全体の件数を測る ROW_COUNT は、手では呼べません。上の SELECT に、SNOWFLAKE.CORE.ROW_COUNT(SELECT ORDER_ID FROM ORDERS) を足しました。結果は次のエラーで、前後と引数の中は略しています。

too many arguments for function [ROW_COUNT$V1(...)] expected 0, got 1
ROW_COUNT を SELECT の中で呼んだときの結果。SQL compilation error で、ROW_COUNT の関数に引数が多すぎる、0個のところに1個渡された、という内容
ROW_COUNT を手で呼んだときのエラー。引数が多すぎる、という内容です

ROW_COUNT は、テーブルに関連付けるときに、列を指定せず ON () と書きます。ドキュメントにも、この関数は直接呼べないとあります。

テーブルに関連付けて、DMF のスケジュールと期待値を決める

DMF は、ALTER TABLE でテーブルの列に関連付けます。測る時刻は、テーブルの DATA_METRIC_SCHEDULE で決めます。試すときは、すぐ結果を見るために5分ごとにしました。

USE SCHEMA TEST_DQ.RAW;
ALTER TABLE ORDERS SET DATA_METRIC_SCHEDULE = '5 MINUTE';
ALTER TABLE ORDERS ADD DATA METRIC FUNCTION SNOWFLAKE.CORE.NULL_COUNT ON (AMOUNT);
ALTER TABLE ORDERS ADD DATA METRIC FUNCTION SNOWFLAKE.CORE.DUPLICATE_COUNT ON (ORDER_ID);
ALTER TABLE ORDERS ADD DATA METRIC FUNCTION SNOWFLAKE.CORE.ROW_COUNT ON ();
SELECT METRIC_NAME, REF_ENTITY_NAME, SCHEDULE, SCHEDULE_STATUS
FROM TABLE(INFORMATION_SCHEMA.DATA_METRIC_FUNCTION_REFERENCES(REF_ENTITY_NAME => 'TEST_DQ.RAW.ORDERS', REF_ENTITY_DOMAIN => 'TABLE'));

最後の SELECT は、関連付けの一覧です。3つとも SCHEDULE_STATUS が STARTED で、SCHEDULE は */5 * * * * UTC でした。5 MINUTE と書いても、一覧では cron の形になります。

関連付けの一覧。DUPLICATE_COUNT・NULL_COUNT・ROW_COUNT の3行で、どれも REF_ENTITY_NAME が ORDERS、SCHEDULE が */5 * * * * UTC、SCHEDULE_STATUS が STARTED
関連付けの一覧。3つの DMF が同じスケジュールで STARTED です

DMF のスケジュールは、テーブルに1つです。関連付けた DMF は、どれも同じ時刻に測られます。分で書くなら、5・15・30・60・720・1440 のどれかです。cron で書くなら、間隔は5分以上にします。TRIGGER_ON_CHANGES にすると、行を足したり消したりしたときに測ります。

スケジュールを決めずに関連付けると、既定の60分ごとに測られます。毎朝1回のつもりが1日24回になるので、先に DATA_METRIC_SCHEDULE を決めてから関連付けます。

ドキュメントには、スケジュールを設定してから効くまでに10分かかるとあります。ただし、新しく関連付けた DMF には、この遅れはかからないとも書いてあります。今回は 01:58 ごろに設定と関連付けをして、予定の時刻が 02:00 の測定から値が残っていました。

次に、期待値を付けます。関連付け済みの DMF には、MODIFY … ADD EXPECTATION で付けます。新しく関連付けるときは、ADD の文の後ろに EXPECTATION を続けて書けます。

USE SCHEMA TEST_DQ.RAW;
ALTER TABLE ORDERS MODIFY DATA METRIC FUNCTION SNOWFLAKE.CORE.NULL_COUNT ON (AMOUNT)
  ADD EXPECTATION AMOUNT_NOT_NULL (VALUE = 0);
ALTER TABLE ORDERS MODIFY DATA METRIC FUNCTION SNOWFLAKE.CORE.DUPLICATE_COUNT ON (ORDER_ID)
  ADD EXPECTATION ORDER_ID_UNIQUE (VALUE = 0);
ALTER TABLE ORDERS ADD DATA METRIC FUNCTION SNOWFLAKE.CORE.FRESHNESS ON (LOADED_AT)
  EXPECTATION LOADED_WITHIN_26H (VALUE < 93600);
ALTER TABLE ORDERS ADD DATA METRIC FUNCTION SNOWFLAKE.CORE.ROWS_IN_PAST_DAY_COUNT ON (LOADED_AT)
  EXPECTATION AT_LEAST_50_ROWS (VALUE >= 50);

期待値の式では、DMF が返した値を VALUE と書き、比較演算子で基準を書きます。式が TRUE なら合格、FALSE なら違反です。式からは、ほかのテーブルやビューを参照できません。前日の値と比べるような判定は、期待値では書けません。

NULL_COUNT と DUPLICATE_COUNT は、テーブル全体の行を数えます。過去の行に NULL や重複が1件でも残っていると、VALUE = 0 の期待値は、直すまで毎朝違反になります。始める前に今の値を確かめる手順は、最後の節に書きました。評価する行を条件で絞る書き方もドキュメントにありますが、今回は試していません。

DUPLICATE_COUNT は、NULL も重複として数えます。注文番号に NULL が入りうるなら、その列に NULL_COUNT も関連付けて、分けて見ます。

鮮度の上限は、取り込みの時刻と評価の時刻から決めます。たとえば、毎朝6時までに取り込みが終わり、アラートが6時40分に評価する場合です。今朝の取り込みが来ていれば鮮度は40分以上で、来ていなければ前の日の取り込みから24時間40分ほどです。

上限を短くすると、取り込みが少し遅れた朝も違反になります。長くすると、取り込みが来なかった朝も合格になります。上限は、ふだんの取り込みの遅れを見込んだうえで、24時間40分より短くします。

今回の上限の93600秒、つまり26時間は、試すときの値です。6時の取り込みと6時40分の評価の組み合わせでは、今朝の取り込みが来なくても合格になります。ただし、その朝は件数の期待値が違反になります。前の日の6時の行は、6時40分の24時間前より前なので数えないからです。どちらも計算で、試してはいません。

ROWS_IN_PAST_DAY_COUNT は、時刻の列の値が、予定の時刻の前24時間に入っている行を数えます。暦の1日の件数ではありません。下限の50行も試すときの値で、今回の1日分の100行の半分にしました。本番では、ふだんの件数から決めます。

問題の行を入れ、期待値を評価して違反を確かめる

DMF のスケジュールを待たずに合否を見るときは、SYSTEM$EVALUATE_DATA_QUALITY_EXPECTATIONS を使います。テーブルの期待値を、その場で評価する関数です。使わない列が多いので、EXCLUDE で外しています。

USE SCHEMA TEST_DQ.RAW;
SELECT * EXCLUDE (METRIC_DATABASE, METRIC_SCHEMA, EXPECTATION_ID, ARGUMENTS)
FROM TABLE(SYSTEM$EVALUATE_DATA_QUALITY_EXPECTATIONS(REF_ENTITY_NAME => 'TEST_DQ.RAW.ORDERS'));

問題を入れる前は、4つの期待値がすべて合格でした。FRESHNESS の値は秒で、199なら、最後に取り込んでから199秒という意味です。

次に、わざと問題の行を入れます。入れるのは、注文番号1・2・3と同じ番号の3行と、金額が NULL の2行で、合わせて105行になります。

USE SCHEMA TEST_DQ.RAW;
INSERT INTO ORDERS VALUES
  (1, '2026-10-20', '渋谷店', 3000, CURRENT_TIMESTAMP()),
  (2, '2026-10-20', '新宿店', 4000, CURRENT_TIMESTAMP()),
  (3, '2026-10-20', '渋谷店', 5000, CURRENT_TIMESTAMP()),
  (201, '2026-10-20', '新宿店', NULL, CURRENT_TIMESTAMP()),
  (202, '2026-10-20', '渋谷店', NULL, CURRENT_TIMESTAMP());
SELECT * EXCLUDE (METRIC_DATABASE, METRIC_SCHEMA, EXPECTATION_ID, ARGUMENTS, GROUP_BY_VALUES, _CACHE_BUSTER)
FROM TABLE(SYSTEM$EVALUATE_DATA_QUALITY_EXPECTATIONS(REF_ENTITY_NAME => 'TEST_DQ.RAW.ORDERS'));

入れたあとに評価すると、NULL_COUNT が2、DUPLICATE_COUNT が3になり、この2つの期待値が違反になりました。鮮度と件数の期待値は合格のままです。2と3は、105行のテーブル全体を数えた値です。

問題の行を入れたあとの評価。NULL_COUNT の AMOUNT_NOT_NULL は VALUE 2 で EXPECTATION_VIOLATED が TRUE、DUPLICATE_COUNT の ORDER_ID_UNIQUE は 3 で TRUE、FRESHNESS は 1 で FALSE、ROWS_IN_PAST_DAY_COUNT は 105 で FALSE。EXPECTATION_VIOLATED の列名の左には、文字列の列を示す A のアイコン
問題の行を入れたあとの評価。上の2行の EXPECTATION_VIOLATED が TRUE です

DUPLICATE_COUNT の3は、重複に関わる6行の数ではありませんでした。今回はどの番号も2行ずつなので、重複がある値の数と、余分に入った行の数がどちらも3です。同じ番号が3行以上あるときの数え方は試していません。

違反が分かったら、該当の行を取り出します。SYSTEM$DATA_METRIC_SCAN に、テーブルと DMF の名前と列を渡すと、その DMF が数えた行が返ります。

USE SCHEMA TEST_DQ.RAW;
SELECT ORDER_ID, ORDER_DATE, STORE, AMOUNT
FROM TABLE(SYSTEM$DATA_METRIC_SCAN(
  REF_ENTITY_NAME => 'TEST_DQ.RAW.ORDERS',
  METRIC_NAME => 'snowflake.core.duplicate_count',
  ARGUMENT_NAME => 'ORDER_ID'))
ORDER BY ORDER_ID, AMOUNT;

返ったのは6行で、注文番号1・2・3のそれぞれに、元の行と足した行がありました。どちらを残すかは、この結果だけでは決められません。取り込み元のデータと見比べてから直します。

SYSTEM$DATA_METRIC_SCAN の結果。6行で、ORDER_ID が 1・1・2・2・3・3。ORDER_DATE はどれも 2026-10-20、店は渋谷店か新宿店、金額は行ごとに違う
SYSTEM$DATA_METRIC_SCAN の結果。注文番号ごとに2行ずつ返りました

金額が NULL の行なら、METRIC_NAME を ‘snowflake.core.null_count’ にします。ARGUMENT_NAME は ‘AMOUNT’ です。こちらは試していません。直したら、期待値をもう一度評価して、FALSE に戻ったかを見ます。直すまでは、アラートが毎朝メールを送ります。

測る DMF と期待値の一覧。金額の NULL は NULL_COUNT と AMOUNT_NOT_NULL(VALUE = 0)、問題を入れる前は0で合格、入れたあとは2で違反。注文番号の重複は DUPLICATE_COUNT と ORDER_ID_UNIQUE(VALUE = 0)、0で合格、3で違反。取り込みの鮮度は FRESHNESS と LOADED_WITHIN_26H(VALUE < 93600、試すための値)、199で合格、1で合格。予定の時刻の前24時間の件数は ROWS_IN_PAST_DAY_COUNT と AT_LEAST_50_ROWS(VALUE >= 50、試すための値)、100で合格、105で合格。鮮度と件数は、違反になる日を作って試していない。テーブル全体の件数 ROW_COUNT は期待値を付けず、02:00 の測定で100、02:05 の測定で105測る DMF と期待値の一覧。金額の NULL は NULL_COUNT と AMOUNT_NOT_NULL(VALUE = 0)、問題を入れる前は0で合格、入れたあとは2で違反。注文番号の重複は DUPLICATE_COUNT と ORDER_ID_UNIQUE(VALUE = 0)、0で合格、3で違反。取り込みの鮮度は FRESHNESS と LOADED_WITHIN_26H(VALUE < 93600、試すための値)、199で合格、1で合格。予定の時刻の前24時間の件数は ROWS_IN_PAST_DAY_COUNT と AT_LEAST_50_ROWS(VALUE >= 50、試すための値)、100で合格、105で合格。鮮度と件数は、違反になる日を作って試していない。テーブル全体の件数 ROW_COUNT は期待値を付けず、02:00 の測定で100、02:05 の測定で105
測る DMF と期待値の一覧。問題を入れる前と後の値は、SYSTEM$EVALUATE_DATA_QUALITY_EXPECTATIONS の結果です

DMF のスケジュールで測った値と合否は、2つのビューに残る

DMF のスケジュールで測った値は、SNOWFLAKE.LOCAL.DATA_QUALITY_MONITORING_RESULTS に残ります。この記事では、結果のビューと書きます。

USE SCHEMA TEST_DQ.RAW;
SELECT METRIC_NAME, VALUE,
       TO_CHAR(CONVERT_TIMEZONE('Asia/Tokyo', SCHEDULED_TIME), 'HH24:MI:SS') AS SCHEDULED_JST,
       TO_CHAR(CONVERT_TIMEZONE('Asia/Tokyo', MEASUREMENT_TIME), 'HH24:MI:SS') AS MEASURED_JST
FROM SNOWFLAKE.LOCAL.DATA_QUALITY_MONITORING_RESULTS
WHERE TABLE_DATABASE = 'TEST_DQ' AND TABLE_NAME = 'ORDERS'
ORDER BY MEASUREMENT_TIME DESC, METRIC_NAME
LIMIT 20;

02:00 の測定は、5つの DMF がどれも 02:00:15 に測っていました。問題を入れる前の測定で、NULL_COUNT と DUPLICATE_COUNT は0、FRESHNESS は192です。02:05 の測定では NULL_COUNT が2、DUPLICATE_COUNT が3になり、2つの件数は105に増えました。

結果のビュー。10行。上の5行は予定の時刻 02:05:00 の測定で、ROW_COUNT 105、DUPLICATE_COUNT 3、FRESHNESS 212、NULL_COUNT 2、ROWS_IN_PAST_DAY_COUNT 105、測った時刻は 02:05:14 から 02:05:50。下の5行は 02:00:00 の測定で、ROW_COUNT 100、NULL_COUNT 0、ROWS_IN_PAST_DAY_COUNT 100、DUPLICATE_COUNT 0、FRESHNESS 192、測った時刻はどれも 02:00:15
結果のビュー。枠の5行が 02:05 の測定、その下が 02:00 の測定です

02:05 の測定は、02:05:14 から 02:05:50 にかけて行われ、02:06 ごろには結果のビューで見られました。

測った順に並べるときは、予定の時刻の SCHEDULED_TIME ではなく、測った時刻の MEASUREMENT_TIME を使います。予定の時刻と測った時刻の間にも、行が入ることがあるからです。

期待値の合否は、SNOWFLAKE.LOCAL.DATA_QUALITY_MONITORING_EXPECTATION_STATUS に残ります。こちらは合否のビューと書きます。

USE SCHEMA TEST_DQ.RAW;
SELECT * EXCLUDE (TABLE_DATABASE, TABLE_SCHEMA)
FROM SNOWFLAKE.LOCAL.DATA_QUALITY_MONITORING_EXPECTATION_STATUS
WHERE TABLE_DATABASE = 'TEST_DQ' AND TABLE_NAME = 'ORDERS'
ORDER BY MEASUREMENT_TIME DESC
LIMIT 10;

合否のビューは、4つの期待値の2回分で8行でした。違反を示す TRUE だったのは、02:05 の測定の ORDER_ID_UNIQUE と AMOUNT_NOT_NULL です。

合否のビュー。8行。1行目 ORDER_ID_UNIQUE と3行目 AMOUNT_NOT_NULL の EXPECTATION_VIOLATED が TRUE、ほかの6行は FALSE。EXPECTATION_VIOLATED の列名の左には、真偽値の列を示す 0|1 のアイコン。EXPECTATION_ID の値は灰色で隠してある
合否のビュー。上の4行が 02:05 の測定です。EXPECTATION_ID の値は隠しています

2つのビューを見るには、アプリケーションロールを GRANT APPLICATION ROLE で付与します。見るだけなら、SNOWFLAKE.DATA_QUALITY_MONITORING_VIEWER です。データベースロールの SNOWFLAKE.GOVERNANCE_VIEWER では、結果のビューは見られないとドキュメントにあります。

アラートの条件では、EXPECTATION_VIOLATED を ‘TRUE’ と文字列で比べる

メールの宛先にできるのは、同じアカウントの Snowflake ユーザーで、メールアドレスを確認済みの人だけです。送るには、通知インテグレーションも要ります。Snowflake からメールなどで外へ知らせるための設定で、送ってよい宛先を ALLOWED_RECIPIENTS に書きます。

試すときは、受け取り用のユーザーと通知インテグレーションを、2つの SQL に分けて作ります。名前は、タスクで取り込みを自動にする記事とそろえました。その記事の片付けまで済ませた場合、この2つは消えているので、ここで作り直します。

次の2つの塊は、その記事の試しで実行した文です。ユーザーの COMMENT の文は、試したときの文から置き換えています。まず、受け取り用のユーザーを作り、確認メールを送ります。

USE ROLE ACCOUNTADMIN;
CREATE USER IF NOT EXISTS DATA_TEAM_NOTIFY
  TYPE = PERSON
  EMAIL = 'data-team@example.com'
  COMMENT = 'email recipient only, no password';
CALL SYSTEM$START_USER_EMAIL_VERIFICATION('DATA_TEAM_NOTIFY');

受け取る人が確認メールのリンクを開き、アドレスが確認済みになってから、次を実行します。確認していないアドレスを ALLOWED_RECIPIENTS に入れると、CREATE が失敗するとドキュメントにあります。ユーザー自身が Snowsight で確認することもできます。

USE ROLE ACCOUNTADMIN;
CREATE NOTIFICATION INTEGRATION IF NOT EXISTS LOAD_EMAIL_INT
  TYPE = EMAIL
  ENABLED = TRUE
  ALLOWED_RECIPIENTS = ('data-team@example.com');

宛先の data-team@example.com は説明用のアドレスなので、自社の確認済みのアドレスに替えます。IF NOT EXISTS なので、同じ名前の通知インテグレーションがすでにあると、何も作られず、宛先も足されません。ALLOWED_RECIPIENTS に入っていない宛先が1つでもあると、メールは送られないとドキュメントにあります。すでにある場合は、宛先が入っているかを確かめます。

メールを送るのは、ストアドプロシージャの NOTIFY_DQ_VIOLATIONS です。ストアドプロシージャは、SQL で書いた処理の手順を保存したものです。期待値を評価し、違反した期待値の数と一覧を本文にして、SYSTEM$SEND_EMAIL で送ります。

アラート CHECK_DQ は、毎朝6時40分に同じ関数で期待値を評価し、違反した期待値が1つでもあれば、このストアドプロシージャを呼びます。最後の EXECUTE ALERT は、予定の時刻を待たずに一度だけ実行する文です。件名と本文は、試したときのままです。

USE SCHEMA TEST_DQ.RAW;
CREATE OR REPLACE PROCEDURE NOTIFY_DQ_VIOLATIONS()
RETURNS STRING
LANGUAGE SQL
AS
$$
DECLARE
  n NUMBER;
  detail STRING;
  body STRING;
BEGIN
  SELECT COUNT(*), LISTAGG(METRIC_NAME || ' / ' || EXPECTATION_NAME || ' の値 ' || VALUE, ' | ')
    INTO :n, :detail
    FROM TABLE(SYSTEM$EVALUATE_DATA_QUALITY_EXPECTATIONS(REF_ENTITY_NAME => 'TEST_DQ.RAW.ORDERS'))
    WHERE EXPECTATION_VIOLATED = 'TRUE';
  body := 'これはブログ記事の検証用のテスト送信です。' || CHR(10) ||
          '注文テーブルのデータ品質の期待値に違反があります: ' || n || ' 件' || CHR(10) ||
          COALESCE(detail, '');
  CALL SYSTEM$SEND_EMAIL(
    'LOAD_EMAIL_INT',
    'data-team@example.com',
    '[テスト送信] Snowflake データ品質の違反(ブログ検証)',
    :body);
  RETURN n;
END;
$$;
CREATE OR REPLACE ALERT CHECK_DQ
  WAREHOUSE = COMPUTE_WH
  SCHEDULE = 'USING CRON 40 6 * * * Asia/Tokyo'
  IF (EXISTS (
    SELECT 1 FROM TABLE(SYSTEM$EVALUATE_DATA_QUALITY_EXPECTATIONS(REF_ENTITY_NAME => 'TEST_DQ.RAW.ORDERS'))
    WHERE EXPECTATION_VIOLATED = 'TRUE'
  ))
  THEN
    CALL NOTIFY_DQ_VIOLATIONS();
EXECUTE ALERT CHECK_DQ;

最初は、条件を WHERE EXPECTATION_VIOLATED と書きました。違反なら TRUE が入る真偽値の列だと思ったからです。アラートもストアドプロシージャも、作るときはエラーになりませんでした。

ところが EXECUTE ALERT で実行すると、アラートの実行履歴の STATE は CONDITION_FAILED でした。SQL_ERROR_CODE は2034で、エラー文は次のとおりです。途中は略しています。

SQL compilation error: Invalid data type [VARCHAR(5)] for predicate [… EXPECTATIONS.EXPECTATION_VIOLATED]

期待値を評価する関数が返す EXPECTATION_VIOLATED は、真偽値ではなく VARCHAR(5) の文字列でした。’TRUE’ か ‘FALSE’ の文字が入ります。

写真で見比べると、列名の左に出る型のアイコンが違います。期待値を評価する関数の結果では、文字列を示す A でした。合否のビューでは、真偽値を示す 0|1 です。リファレンスの戻り値の一覧では、この関数の EXPECTATION_VIOLATED も BOOLEAN と書かれていて、今回の結果と食い違います。型が BOOLEAN に変わったときに = ‘TRUE’ の比較が通るかは、試していません。

条件を WHERE EXPECTATION_VIOLATED = 'TRUE' に直しました。実行すると、アラートの実行履歴は TRIGGERED になり、送信の記録の STATUS は SUCCESS でした。上の SQL は、直したあとの文です。

アラートの実行履歴と送信の記録を並べた結果。3行。下の行は CHECK_DQ の CONDITION_FAILED で SQL compilation error、その上は CHECK_DQ の TRIGGERED(02:04:39)、いちばん上は送信の記録の SUCCESS(02:04:42)
下から、直す前の CONDITION_FAILED、直したあとの TRIGGERED、メールの SUCCESS です。見た SQL は、知らせが来ない朝の節に載せました

SUCCESS は、Snowflake がメールを送り出したという記録で、受信箱に届いたことまでは示しません。同じ通知インテグレーションで送ったメールは、取り込みを自動にする記事のときに、受信箱に届いたことを確かめています。今回のメールは、送信の記録までしか見ていません。

今回のように、作るときにエラーにならなくても、実行すると失敗することがあります。アラートを作ったら、一度 EXECUTE ALERT で実行し、アラートの実行履歴の STATE を見ます。違反がある状態で実行すると、そのときメールが送られます。

作った直後のアラートは、一時停止の状態です。毎朝の予定で動かすには、ALTER ALERT … RESUME を実行します。今回は RESUME していないので、6時40分に動くところは見ていません。

アラートの条件は、DMF のスケジュールで残った合否ではなく、アラートが動いた時点のテーブルを評価して決まります。そのため、鮮度のように時刻で変わる値は、ビューの記録とアラートの評価で一致しません。合否のビューを条件にする形も考えられますが、試していません。

CREATE OR REPLACE TABLE のあと、関連付けの一覧は0件だった

取り込みのたびに CREATE OR REPLACE TABLE でテーブルを作り直しているなら、気をつけることがあります。テーブルを同じ中身で作り直してから、関連付けの一覧を数えました。

USE SCHEMA TEST_DQ.RAW;
CREATE OR REPLACE TABLE ORDERS AS SELECT * FROM ORDERS;
SELECT COUNT(*) AS DMF_BINDINGS_AFTER_RECREATE
FROM TABLE(INFORMATION_SCHEMA.DATA_METRIC_FUNCTION_REFERENCES(REF_ENTITY_NAME => 'TEST_DQ.RAW.ORDERS', REF_ENTITY_DOMAIN => 'TABLE'));
作り直したあとの関連付けの件数を数えた結果。DMF_BINDINGS_AFTER_RECREATE が 0
作り直したあとの関連付けの件数。0件になりました

結果は0件でした。ドキュメントには、作るときに DMF を関連付ける書き方の説明があります。その中に、CREATE OR REPLACE は関連付けを一から置き換える、とあります。

毎朝テーブルを作り直す取り込みでは、関連付けた DMF と期待値が毎朝外れ、何も測られなくなります。アラートが呼ぶ評価の関数も失敗する見込みで、違反がある日でもメールは来ないはずです。

作り直す取り込みのままにするなら、CREATE 文の中に WITH DATA METRIC FUNCTION を書く方法があります。作るときに、DMF と期待値を関連付ける書き方です。作り直したあとに DMF のスケジュールが残るかは、確かめていません。テーブルを作り直さず、TRUNCATE してから INSERT する形や、MERGE で入れ替える形もあります。WITH の書き方も、作り直さない形も、今回は試していません。

差分を MERGE で足していく組み方は、ストリームとタスクで集計テーブルを更新する記事に書きました。

知らせが来ない朝は、関連付けの件数とアラートの実行履歴で確かめる

アラートが鳴らなかった朝に、問題が無かったとは限りません。この一式が何も知らせなくなる朝が、少なくとも3つあるからです。

  • テーブルを作り直して、関連付けが0件になった朝。
  • アラートそのものが失敗した朝。今回の CONDITION_FAILED のように、メールは送られません。
  • アラートを RESUME する前か、一時停止になったままの朝。アラートは動きません。

1つ目は、今のアラートでは拾えない見込みです。期待値を評価する関数の引数は、期待値の付いた DMF を1つ以上持つテーブル、とドキュメントにあります。関連付けが0件の朝はこの関数が失敗し、アラートは CONDITION_FAILED になると考えられます。

そこで、この関数を呼ばない別のアラートを置きます。条件は、関連付けの一覧の件数が0であることです。処理では、ストアドプロシージャを通さずにメールを送ります。次の SQL は、今回は実行していません。関連付けの一覧を数える関数の引数は、試したときの SELECT と同じです。

-- 関連付けが0件の朝に知らせる、もう1つのアラート(今回は実行していない)
CREATE OR REPLACE ALERT CHECK_DQ_BINDINGS
  WAREHOUSE = <ウェアハウス>
  SCHEDULE = 'USING CRON <アラートの分> <アラートの時> * * * <タイムゾーン>'
  IF (EXISTS (
    SELECT 1
    FROM (SELECT COUNT(*) AS N
          FROM TABLE(<データベース>.INFORMATION_SCHEMA.DATA_METRIC_FUNCTION_REFERENCES(REF_ENTITY_NAME => '<データベース>.<スキーマ>.<テーブル>', REF_ENTITY_DOMAIN => 'TABLE')))
    WHERE N = 0
  ))
  THEN
    CALL SYSTEM$SEND_EMAIL(
      '<通知インテグレーション>',
      '<宛先>',
      '<関連付けが外れたときの件名>',
      '<テーブルの呼び名>に関連付けた DMF が0件です。期待値は評価されていません。');

INFORMATION_SCHEMA の前にデータベース名を付けたのは、アラートとテーブルが別のデータベースにあっても、テーブルの側を読むためです。このアラートも、作ったあとは一時停止の状態なので、EXECUTE ALERT で一度確かめてから RESUME します。

2つ目と3つ目は、アラートの中では拾えません。人が毎朝、次の2つの SELECT を1つずつ実行して見ます。関連付けの一覧が0件になっていないかと、アラートの実行履歴に今朝の行があるかです。

USE SCHEMA TEST_DQ.RAW;
SELECT METRIC_NAME, REF_ENTITY_NAME, SCHEDULE, SCHEDULE_STATUS
FROM TABLE(INFORMATION_SCHEMA.DATA_METRIC_FUNCTION_REFERENCES(REF_ENTITY_NAME => 'TEST_DQ.RAW.ORDERS', REF_ENTITY_DOMAIN => 'TABLE'));
SELECT 'ALERT' AS SRC, NAME AS VALUE1, STATE AS VALUE2, COALESCE(SQL_ERROR_MESSAGE, '') AS VALUE3,
       TO_CHAR(CONVERT_TIMEZONE('Asia/Tokyo', SCHEDULED_TIME), 'HH24:MI:SS') AS AT_JST
FROM TABLE(INFORMATION_SCHEMA.ALERT_HISTORY(SCHEDULED_TIME_RANGE_START => DATEADD(MINUTE, -30, CURRENT_TIMESTAMP())))
WHERE NAME = 'CHECK_DQ'
UNION ALL
SELECT 'MAIL', '(送信の記録)', STATUS, '', TO_CHAR(CONVERT_TIMEZONE('Asia/Tokyo', CREATED), 'HH24:MI:SS')
FROM TABLE(INFORMATION_SCHEMA.NOTIFICATION_HISTORY(START_TIME => DATEADD(MINUTE, -10, CURRENT_TIMESTAMP())))
ORDER BY AT_JST DESC;

SRC が ALERT の行はアラートの実行履歴、MAIL の行は送信の記録です。STATE が TRIGGERED なら違反があってメールを送った朝で、CONDITION_FALSE なら違反が無かった朝です。試したときは30分前と10分前からを見たので、毎朝見るときは、DATEADD の幅を前の朝まで届くように広げます。

アラートの実行履歴に今朝の行が無ければ、アラートが一時停止のままになっていないかを確かめます。CONDITION_FAILED か ACTION_FAILED の行があれば、エラー文を見て、条件か処理を直します。直したら、EXECUTE ALERT で一度実行します。

失敗した朝と一時停止の朝は、動かし始めて何日たっても起こりえます。そのため、この2つの SELECT は、動かし始めてからも続けて見ます。続けて失敗したアラートを自動で一時停止する SUSPEND_ALERT_AFTER_NUM_FAILURES という設定も、ドキュメントにあります。この設定で一時停止になった朝も、実行履歴に今朝の行が無いことで気づけます。

期待値で書けない判定と、料金のかかり方

期待値は、DMF の値を決まった値と比べることしかできません。件数が前日より大きく減った日、のような判定は書けません。

こうした判定には、2つの方法があります。1つは、結果のビューから前日の値を引いて比べる SQL を自分で書き、アラートの条件にする形です。もう1つは、DMF の異常検出です。

異常検出は、過去の値から予測した範囲を外れた日を見つける機能で、プレビューです。対象は、件数の ROW_COUNT と鮮度の FRESHNESS だけです。頻繁に測る DMF では、検出を始めるまでに少なくとも2週間分の値が要ります。60日分で学習させることが勧められています。

次の図は、自分で書く SQL と DMF を、書ける判定・記録・料金・作り直したときなどで比べたものです。

自分で書く SQL とアラート、DMF と期待値の比べ方。書ける判定:SQL は条件に SELECT などを書ける。前日の値と比べる SELECT は書いていない。DMF は VALUE と決まった値の比較だけ。値と合否の記録:SQL は自分のテーブルに行を書く。DMF は2つのビューに自動で残った。測る時刻:SQL はアラートごと。DMF はテーブルに1つ。料金:アラートにウェアハウスを指定すると、メールを送るだけでも最低1分ぶん。DMF は DMF のスケジュールで測るたびにサーバーレスで、手で呼ぶ分はかからない。テーブルを作り直したとき:SQL は同じ条件で動くはずで試していない。DMF は関連付けが0件になった。違反を知らせる:SQL はアラートでメールを送る。DMF は期待値を評価する関数を条件にしたアラートで TRIGGERED と SUCCESS自分で書く SQL とアラート、DMF と期待値の比べ方。書ける判定:SQL は条件に SELECT などを書ける。前日の値と比べる SELECT は書いていない。DMF は VALUE と決まった値の比較だけ。値と合否の記録:SQL は自分のテーブルに行を書く。DMF は2つのビューに自動で残った。測る時刻:SQL はアラートごと。DMF はテーブルに1つ。料金:アラートにウェアハウスを指定すると、メールを送るだけでも最低1分ぶん。DMF は DMF のスケジュールで測るたびにサーバーレスで、手で呼ぶ分はかからない。テーブルを作り直したとき:SQL は同じ条件で動くはずで試していない。DMF は関連付けが0件になった。違反を知らせる:SQL はアラートでメールを送る。DMF は期待値を評価する関数を条件にしたアラートで TRIGGERED と SUCCESS
自分で書く SQL と DMF の比べ方。ドキュメントにあること、今回確かめたこと、試していないことを印で分けています

料金は、DMF のスケジュールで測るたびにかかります。DMF はサーバーレスで動き、請求では Data Quality Monitoring に入ります。結果を残す分は、Logging として別に請求に出ます。DMF を作るだけでは、料金はかかりません。

単価は、ドキュメントでは Service Consumption Table という資料を見るよう案内されています。日ごとの使用量を見るビューは、DATA_QUALITY_MONITORING_USAGE_HISTORY です。SNOWFLAKE.ACCOUNT_USAGE のスキーマにあり、反映は最大180分遅れます。

アラートは、違反の無い朝も毎朝条件を評価します。ウェアハウスを指定すると、メールを送るだけの処理でも、最低1分ぶんのウェアハウスの料金がかかります。Snowflake の料金がどこでかかるかは、料金とコストの記事にまとめています。

スケジュールは、細かくしすぎないようにします。今回の5分ごとは、すぐ結果を見るための試しの設定です。毎朝1回の取り込みなら、cron で1日1回にします。DMF のスケジュールでの評価をやめるときは、SET DATA_METRIC_SCHEDULE = '' にします。UNSET DATA_METRIC_SCHEDULE では評価は続き、既定の60分ごとに戻ります。

今回、試していないことと見ていないことは、次のとおりです。

  • 前日比の SQL、異常検出、データベース単位の通知の設定
  • Snowsight のデータ品質の画面、TRIGGER_ON_CHANGES、自作の DMF、評価する行を絞る書き方
  • 合否のビューを条件にしたアラート、6時40分の予定で動くところ、2通目以降の受信
  • 作り直したあとの DMF のスケジュール、鮮度と件数の期待値が違反になる日
  • DMF の使用量と料金、権限を絞ったロールでの運用

読んだドキュメントからは、結果のビューに値が出るまでの時間と、何日分残るかは分かりませんでした。アラートの中で期待値を評価した分が、DMF の料金に入るかどうかも分かりませんでした。

本番のテーブルに入れる一式は、試した文から本番に要る文だけを残す

本番のテーブルに入れるときは、次の一式を上から順に実行します。最後の RESUME だけは、アラートを一度確かめてからにします。わざと問題を入れる INSERT と、予定の時刻を待たずに実行する EXECUTE ALERT は外しました。DMF のスケジュールは、5分ごとから毎朝の時刻に変えています。

<…> は、本番の値に書き換える所です。

  • <データベース>.<スキーマ>.<テーブル> と <ウェアハウス> は、本番のテーブルとウェアハウスの名前にします。REF_ENTITY_NAME の文字列の中にもあります。
  • <NULL を許さない列>・<重複を許さない列>・<取り込んだ時刻の列> は、自社の列名にします。
  • <NULL の期待値> などの4つは期待値の名前で、<鮮度の上限の秒数> と <件数の下限> は基準です。どちらも、基準の決め方に合わせて付けます。
  • <DMFの分> <DMFの時> は取り込みが終わったあとに、<アラートの分> <アラートの時> はそれより後にします。<タイムゾーン> は、両方の cron に使います。
  • <通知インテグレーション>・<宛先>・<件名>・<本文の書き出し>・<テーブルの呼び名> は、本番で送るメールの内容にします。
-- 本番用。試した文のうち本番に要るものを残し、名前・列・基準・時刻・宛先を <…> にした(この形のまとまりでは実行していない)
USE ROLE ACCOUNTADMIN;
USE WAREHOUSE <ウェアハウス>;
USE SCHEMA <データベース>.<スキーマ>;
-- DMF のスケジュール(試したときは '5 MINUTE'。この cron の形は実行していない)
ALTER TABLE <テーブル> SET DATA_METRIC_SCHEDULE = 'USING CRON <DMFの分> <DMFの時> * * * <タイムゾーン>';
-- 5つの DMF と4つの期待値
ALTER TABLE <テーブル> ADD DATA METRIC FUNCTION SNOWFLAKE.CORE.NULL_COUNT ON (<NULL を許さない列>);
ALTER TABLE <テーブル> ADD DATA METRIC FUNCTION SNOWFLAKE.CORE.DUPLICATE_COUNT ON (<重複を許さない列>);
ALTER TABLE <テーブル> ADD DATA METRIC FUNCTION SNOWFLAKE.CORE.ROW_COUNT ON ();
ALTER TABLE <テーブル> MODIFY DATA METRIC FUNCTION SNOWFLAKE.CORE.NULL_COUNT ON (<NULL を許さない列>)
  ADD EXPECTATION <NULL の期待値> (VALUE = 0);
ALTER TABLE <テーブル> MODIFY DATA METRIC FUNCTION SNOWFLAKE.CORE.DUPLICATE_COUNT ON (<重複を許さない列>)
  ADD EXPECTATION <重複の期待値> (VALUE = 0);
ALTER TABLE <テーブル> ADD DATA METRIC FUNCTION SNOWFLAKE.CORE.FRESHNESS ON (<取り込んだ時刻の列>)
  EXPECTATION <鮮度の期待値> (VALUE < <鮮度の上限の秒数>);
ALTER TABLE <テーブル> ADD DATA METRIC FUNCTION SNOWFLAKE.CORE.ROWS_IN_PAST_DAY_COUNT ON (<取り込んだ時刻の列>)
  EXPECTATION <件数の期待値> (VALUE >= <件数の下限>);
-- SCHEDULE_STATUS が STARTED になったか
SELECT METRIC_NAME, REF_ENTITY_NAME, SCHEDULE, SCHEDULE_STATUS
FROM TABLE(INFORMATION_SCHEMA.DATA_METRIC_FUNCTION_REFERENCES(REF_ENTITY_NAME => '<データベース>.<スキーマ>.<テーブル>', REF_ENTITY_DOMAIN => 'TABLE'));
-- 通知インテグレーション。同じ名前がすでにあると作られず、宛先も足されない
CREATE NOTIFICATION INTEGRATION IF NOT EXISTS <通知インテグレーション>
  TYPE = EMAIL
  ENABLED = TRUE
  ALLOWED_RECIPIENTS = ('<宛先>');
-- 違反を知らせるストアドプロシージャ
CREATE OR REPLACE PROCEDURE NOTIFY_DQ_VIOLATIONS()
RETURNS STRING
LANGUAGE SQL
AS
$$
DECLARE
  n NUMBER;
  detail STRING;
  body STRING;
BEGIN
  SELECT COUNT(*), LISTAGG(METRIC_NAME || ' / ' || EXPECTATION_NAME || ' の値 ' || VALUE, ' | ')
    INTO :n, :detail
    FROM TABLE(SYSTEM$EVALUATE_DATA_QUALITY_EXPECTATIONS(REF_ENTITY_NAME => '<データベース>.<スキーマ>.<テーブル>'))
    WHERE EXPECTATION_VIOLATED = 'TRUE';
  body := '<本文の書き出し>' || CHR(10) ||
          '<テーブルの呼び名>のデータ品質の期待値に違反があります: ' || n || ' 件' || CHR(10) ||
          COALESCE(detail, '');
  CALL SYSTEM$SEND_EMAIL(
    '<通知インテグレーション>',
    '<宛先>',
    '<件名>',
    :body);
  RETURN n;
END;
$$;
-- アラート
CREATE OR REPLACE ALERT CHECK_DQ
  WAREHOUSE = <ウェアハウス>
  SCHEDULE = 'USING CRON <アラートの分> <アラートの時> * * * <タイムゾーン>'
  IF (EXISTS (
    SELECT 1 FROM TABLE(SYSTEM$EVALUATE_DATA_QUALITY_EXPECTATIONS(REF_ENTITY_NAME => '<データベース>.<スキーマ>.<テーブル>'))
    WHERE EXPECTATION_VIOLATED = 'TRUE'
  ))
  THEN
    CALL NOTIFY_DQ_VIOLATIONS();
-- 毎朝の予定で動かし始める。先に EXECUTE ALERT CHECK_DQ; で STATE を確かめてから実行する(今回は実行していない)
ALTER ALERT CHECK_DQ RESUME;

実行したら、関連付けの一覧で SCHEDULE_STATUS が STARTED かを見ます。最後の RESUME の前に、EXECUTE ALERT CHECK_DQ; を一度実行し、アラートの実行履歴の STATE を見ます。そのとき違反があれば、メールが送られます。関連付けが0件の朝にも知らせたいなら、知らせが来ない朝の節の、関連付けを数えるアラートを足します。

今回は、どれも ACCOUNTADMIN で試しました。ほかのロールで組むときに要る権限は、ドキュメントでは次のとおりです。

  • DMF を関連付けるには、アカウントの EXECUTE DATA METRIC FUNCTION と、テーブルの OWNERSHIP が要ります。DMF のスケジュールを設定するのも、テーブルの OWNERSHIP を持つロールです。
  • 2つのビューを見るロールには、SNOWFLAKE.DATA_QUALITY_MONITORING_VIEWER を付与します。
  • アラートを作るロールには、アカウントの EXECUTE ALERT が要り、付与できるのは ACCOUNTADMIN のロールだけです。スキーマの USAGE と CREATE ALERT、ウェアハウスの USAGE も要ります。
  • アラートとストアドプロシージャは、所有するロールの権限で動きます。そのロールには、期待値を評価するためのテーブルの SELECT と、通知インテグレーションの USAGE を付与します。
  • 通知インテグレーションを作るには、CREATE NOTIFICATION INTEGRATION の権限が要ります。CREATE INTEGRATION でも作れます。

TEST_DQ のほかに、データベースの外に作った2つも消す

試し終えたら、アラートを一時停止してから TEST_DQ を消します。データ保持期間を0にしてから消すのは、保持期間の分のストレージ料金を残さないためです。データ保持期間は、Time Travel と UNDROP の記事で説明しています。

DMF の関連付けはテーブルに付いているので、テーブルと一緒に消え、別に外す必要はありません。受け取り用のユーザーと通知インテグレーションはデータベースの外にあるので、DROP で消します。本番でも使うなら、この2行は実行しません。

USE ROLE ACCOUNTADMIN;
ALTER ALERT TEST_DQ.RAW.CHECK_DQ SUSPEND;
ALTER DATABASE TEST_DQ SET DATA_RETENTION_TIME_IN_DAYS = 0;
DROP DATABASE TEST_DQ;
-- 下の2行は、本番でも使うなら実行しない
DROP USER IF EXISTS DATA_TEAM_NOTIFY;
DROP INTEGRATION IF EXISTS LOAD_EMAIL_INT;

消したあと、TEST_DQ、受け取り用のユーザー、通知インテグレーションが残っていないことを、それぞれの件数が0になったことで確かめました。

期待値を付ける前に、今のテーブルの NULL と重複を数える

期待値を付けた翌朝から違反のメールが続くかどうかは、今のテーブルの NULL と重複の数で決まります。毎朝取り込んでいるテーブルで、NULL_COUNT と DUPLICATE_COUNT を SELECT の中で呼んでみてください。呼ぶのは、NULL を許さない列と、重複を許さない列です。手で呼ぶ分は、DMF の料金がかかりません。

0なら、VALUE = 0 の期待値をそのまま付けられます。0でなければ、期待値を付ける前に過去の行を直すか、VALUE の基準を今の値に合わせて決めます。

dbt は、SQL で書いた変換をまとめて管理し、実行するツールです。dbt のテストは、取り込んだテーブルにも変換したテーブルにも書けて、dbt を実行したときに確かめます。DMF は、Snowflake の中で、決めた時刻にテーブルを測ります。当社は Snowflake 導入支援の中で、dbt のテストの整備をお手伝いしています。

データ分析・データ基盤支援

Snowflake・BigQuery・Treasure Dataといったデータ基盤の選定から、基幹・SaaS・広告・POSに散らばったデータの集約、dbtでの指標統一、Lookerなどでのダッシュボード化までを支援します。

AT
aurant technologies 編集

上場企業からスタートアップまで、数多くのデータ分析基盤構築・AI導入プロジェクトを主導。単なる技術提供にとどまらず、MA/CRM(Salesforce, Hubspot, kintone, LINE)導入によるマーケティング最適化やバックオフィス業務の自動化など、常に「事業数値(売上・利益)」に直結する改善実績多数。

この記事が役に立ったらシェア:

データ基盤・データ分析の資料

「BIツール選定チェックリスト&4社比較」

データ分析・データ基盤支援の内容を見る