オブジェクトの問い合わせ先を目的別に管理できる Contact を試してみた #SnowflakeDB

オブジェクトの問い合わせ先を目的別に管理できる Contact を試してみた #SnowflakeDB

Clock Icon2025.07.08

はじめに

2025年5月のアップデートで、データベースやテーブルなどのオブジェクトに連絡先を関連付けることができる機能がパブリックプレビューとなりました。

https://docs.snowflake.com/en/release-notes/2025/other/2025-05-20-contacts

こちらの機能を試してみたので、本記事で内容をまとめてみます。

機能概要

本機能の主な特徴は以下の通りです。

  • 新たにスキーマレベルのオブジェクトである CONTACT が追加された
    • CONTACT はユーザーやユーザーグループとのコミュニケーション方法に関する詳細(Snowflake ユーザー名、メールアドレス、URLのいずれか)を含む
  • CONTACT はデータベースやテーブルなど対応するオブジェクトに関連付けることができる
    • オブジェクトに関連付ける際は、そのプロパティとして「目的」を設定する

CONTACT をオブジェクトに関連付けることで、ユーザーがオブジェクトに関するサポートが必要な際に誰に連絡すればよいかを把握できます。
主に GUI(Snowsight)で使用できる機能で、本アップデートに伴い「Data > Darabase」メニュー内の対応するオブジェクトについて、下図の項目が追加されています。

image

図のように、オブジェクトには目的ごとに異なる連絡先を設定できます。

CONTACT の関連付け

既存のオブジェクトに関連付ける際は ALTER 文を使用します。

ALTER <object_type> <object_name>
  SET CONTACT <purpose> = <contact_name> [ , <purpose> = <contact_name> ... ]

特徴として、対象の CONTACT の目的(purpose)を指定します。この目的は事前定義済みのもので、以下の3種類が用意されています。※定義は公式ドキュメントより引用

  • スチュワード(Steward)
    • データの正確性、一貫性、信頼性に関する情報を提供
    • 例:「このデータの意味は?」など、データがどういう意味を持つのか、品質はどうか、といったビジネス的な側面に責任を持つ人やチーム。データオーナーやデータ管理者とも呼ばれる
  • サポート(Support)
    • データセットに関連する技術サポートを提供
    • 例:「データに接続できない」など技術的な問題が発生した際に最初に問い合わせを行う連絡先など
  • 承認者(Approver)
    • データへのアクセス要求を承認または拒否
    • 例:「このテーブルへの編集権限がほしい」などデータやオブジェクトへのアクセス権限の承認する責任を持つ人やチーム

役割を分けて連絡先を設定しておくことで、何か問題や質問が発生した際に、誰に連絡すればよいかが明確になり、データガバナンスの運用がスムーズになることが期待できます。

https://docs.snowflake.com/en/user-guide/contacts-using#associate-a-contact-with-an-object

アクセス制御

オブジェクト管理に関係する主な権限は以下の通りです。

  • CONTACT を作成する際は、CREATE CONTACT を使用します
  • スキーマレベルのオブジェクトなので、作成には以下の権限が必要です
    • 作成先のスキーマに対する CREATE CONTACT 権限
    • 親データベースおよびスキーマに対する USAGE 権限
  • オブジェクトに CONTACT を関連付け/関連付けの解除には、以下のいずれかの権限が必要です
    • アカウントに対する APPLY CONTACT 権限
    • CONTACT に対する APPLY 権限と、オブジェクトに対する OWNERSHIP 権限
  • オブジェクトの CONTACT を表示
    • 対象のオブジェクトに対する何らかの権限があれば可能
  • 既存の CONTACT を変更するには、以下のいずれかの権限が必要です
    • CONTACT に対する OWNERSHIP 権限
    • CONTACT に対する MODIFY 権限

https://docs.snowflake.com/en/user-guide/contacts-using#access-control-privileges

試してみる

事前準備

以下のコマンドを実行しオブジェクトを作成しておきました。このうち MART_DB とその配下のオブジェクトで試してみます。

環境用意
-- SYSADMIN で実行
USE ROLE SYSADMIN;
-- データベースの作成
CREATE DATABASE raw_db;
CREATE DATABASE stg_db;
CREATE DATABASE mart_db;

-- raw_db のスキーマ作成
CREATE SCHEMA raw_db.shop_schema;
CREATE SCHEMA raw_db.customer_schema;

-- stg_db のスキーマ作成
CREATE SCHEMA stg_db.shop_schema;
CREATE SCHEMA stg_db.customer_schema;

-- mart_db のスキーマ作成
CREATE SCHEMA mart_db.analytics;

/*テーブル・ビューの作成ロール*/

USE ROLE USERADMIN;
CREATE ROLE data_editor;

-- 権限付与
USE ROLE SECURITYADMIN;

-- raw_db の各スキーマに CREATE TABLE 権限を付与
GRANT USAGE ON DATABASE raw_db TO ROLE data_editor;
GRANT USAGE ON SCHEMA raw_db.shop_schema TO ROLE data_editor;
GRANT USAGE ON SCHEMA raw_db.customer_schema TO ROLE data_editor;
GRANT CREATE TABLE ON SCHEMA raw_db.shop_schema TO ROLE data_editor;
GRANT CREATE TABLE ON SCHEMA raw_db.customer_schema TO ROLE data_editor;

-- stg_db の各スキーマに CREATE VIEW 権限を付与
GRANT USAGE ON DATABASE stg_db TO ROLE data_editor;
GRANT USAGE ON SCHEMA stg_db.shop_schema TO ROLE data_editor;
GRANT USAGE ON SCHEMA stg_db.customer_schema TO ROLE data_editor;
GRANT CREATE VIEW ON SCHEMA stg_db.shop_schema TO ROLE data_editor;
GRANT CREATE VIEW ON SCHEMA stg_db.customer_schema TO ROLE data_editor;

-- mart_db の各スキーマに CREATE TABLE 権限を付与
GRANT USAGE ON DATABASE mart_db TO ROLE data_editor;
GRANT USAGE ON SCHEMA mart_db.analytics TO ROLE data_editor;
GRANT CREATE TABLE ON SCHEMA mart_db.analytics TO ROLE data_editor;

GRANT ROLE data_editor TO ROLE SYSADMIN;

USE ROLE SECURITYADMIN;
GRANT usage on warehouse compute_wh to role data_editor;

/*テーブル・ビューを作成*/

USE ROLE data_editor;

-- 購買履歴テーブル(raw_db.shop_schema)
CREATE TABLE raw_db.shop_schema.purchase_history (
    purchase_id INT AUTOINCREMENT PRIMARY KEY,
    customer_id INT,
    product_name STRING,
    quantity INT,
    purchase_date DATE
);

-- サンプルデータ挿入
INSERT INTO raw_db.shop_schema.purchase_history (customer_id, product_name, quantity, purchase_date) VALUES
(1, 'Laptop', 1, '2024-06-01'),
(2, 'Smartphone', 2, '2024-06-02'),
(1, 'Keyboard', 1, '2024-06-03');

-- 顧客テーブル(raw_db.customer_schema)
CREATE TABLE raw_db.customer_schema.customer (
    customer_id INT PRIMARY KEY,
    customer_name STRING,
    email STRING,
    registration_date DATE
);

-- サンプルデータ挿入
INSERT INTO raw_db.customer_schema.customer (customer_id, customer_name, email, registration_date) VALUES
(1, 'Alice', 'alice@example.com', '2023-01-15'),
(2, 'Bob', 'bob@example.com', '2023-02-20');

-- 購買履歴ビュー(stg_purchase_history)
CREATE VIEW stg_db.shop_schema.stg_purchase_history AS
SELECT 
    purchase_id AS id,
    customer_id,
    product_name AS item_name,
    quantity,
    purchase_date
FROM raw_db.shop_schema.purchase_history;

-- 顧客ビュー(stg_customer)
CREATE VIEW stg_db.customer_schema.stg_customer AS
SELECT 
    customer_id AS id,
    customer_name AS name,
    email,
    registration_date
FROM raw_db.customer_schema.customer;

-- 購買履歴と顧客情報を結合し、顧客ごとの購入総数を集計
CREATE TABLE mart_db.analytics.customer_purchase_summary AS
SELECT 
    c.id AS customer_id,
    c.name AS customer_name,
    COUNT(p.id) AS total_purchases,
    SUM(p.quantity) AS total_items_purchased
FROM stg_db.customer_schema.stg_customer c
LEFT JOIN stg_db.shop_schema.stg_purchase_history p
ON c.id = p.customer_id
GROUP BY c.id, c.name;

image 1

また適切な権限であることを確認するため、セカンダリ ロールを無効化しておきました。

>SELECT CURRENT_SECONDARY_ROLES();
+-------------------------------------------------+
| CURRENT_SECONDARY_ROLES()                       |
|-------------------------------------------------|
| {"roles":"ACCOUNTADMIN,ORGADMIN","value":"ALL"} |
+-------------------------------------------------+

>USE SECONDARY ROLES NONE;
+----------------------------------+
| status                           |
|----------------------------------|
| Statement executed successfully. |
+----------------------------------+

>SELECT CURRENT_SECONDARY_ROLES();
+---------------------------+
| CURRENT_SECONDARY_ROLES() |
|---------------------------|
| {"roles":"","value":""}   |
+---------------------------+

CONTACT の管理

CONTACT の管理用に以下を用意しました。

  • CONTACT 作成先となるデータベース・スキーマ
  • CONTACT の管理を行う専用のアカウントロール
-- 管理用のデータベースを作成
USE ROLE SYSADMIN;
CREATE DATABASE IF NOT EXISTS governance;
CREATE SCHEMA IF NOT EXISTS governance.contacts;

-- contacts管理用ロールを作成
USE ROLE USERADMIN;
CREATE ROLE contact_admin;

-- 権限を付与
USE ROLE SECURITYADMIN;

GRANT USAGE ON DATABASE governance TO ROLE contact_admin;
GRANT USAGE ON SCHEMA governance.contacts TO ROLE contact_admin;

-- スキーマレベルのcontactsの作成権限
GRANT CREATE CONTACT ON SCHEMA governance.contacts TO ROLE contact_admin;

-- ロール階層
GRANT ROLE contact_admin TO ROLE SYSADMIN;

SHOW GRANTS TO ROLE contact_admin
    ->> SELECT "privilege","granted_on","name","grantee_name" FROM $1;
+----------------+------------+--------------------------------------+---------------+
| privilege      | granted_on | name                                 | grantee_name  |
|----------------+------------+--------------------------------------+---------------|
| USAGE          | DATABASE   | GOVERNANCE                           | CONTACT_ADMIN |
| CREATE CONTACT | SCHEMA     | GOVERNANCE.CONTACTS                  | CONTACT_ADMIN |
| USAGE          | SCHEMA     | GOVERNANCE.CONTACTS                  | CONTACT_ADMIN |
+----------------+------------+--------------------------------------+---------------+

管理用ロールに切り替えて CONTACT を作成します。

-- contactを作成
USE ROLE contact_admin;
USE SCHEMA governance.contacts;

-- URL
CREATE CONTACT my_url_contact
  URL = 'https://classmethod.jp/';

-- EMAIL
CREATE CONTACT my_email_contact
  EMAIL_DISTRIBUTION_LIST = 'info@example.com';

-- USER
CREATE CONTACT my_user_contact
  USERS = ('user1');

>SHOW CONTACTS;
+-------------------------------+------------------+---------------+-------------+---------------+---------+-----------------+-------------------------+-------------------------+------------------+---------+
| created_on                    | name             | database_name | schema_name | owner         | comment | owner_role_type | email_distribution_list | url                     | entries_in_users | users   |
|-------------------------------+------------------+---------------+-------------+---------------+---------+-----------------+-------------------------+-------------------------+------------------+---------|
| 2025-07-06 22:20:56.354 -0700 | MY_EMAIL_CONTACT | GOVERNANCE    | CONTACTS    | CONTACT_ADMIN |         | ROLE            | info@example.com        | NULL                    |                0 | NULL    |
| 2025-07-06 21:50:36.631 -0700 | MY_URL_CONTACT   | GOVERNANCE    | CONTACTS    | CONTACT_ADMIN |         | ROLE            | NULL                    | https://classmethod.jp/ |                0 | NULL    |
| 2025-07-06 21:51:00.052 -0700 | MY_USER_CONTACT  | GOVERNANCE    | CONTACTS    | CONTACT_ADMIN |         | ROLE            | NULL                    | NULL                    |                1 | [USER1] |
+-------------------------------+------------------+---------------+-------------+---------------+---------+-----------------+-------------------------+-------------------------+------------------+---------+

https://docs.snowflake.com/en/sql-reference/sql/create-contact

作成した CONTACT をテーブルに関連付けます。

USE ROLE contact_admin;

-- MART_DB内のテーブル(MART_DB/ANALYTICS/ CUSTOMER_PURCHASE_SUMMARY)に関連付け
>ALTER TABLE MART_DB.ANALYTICS.CUSTOMER_PURCHASE_SUMMARY SET CONTACT SUPPORT = governance.contacts.my_email_contact;
002003 (02000): SQL compilation error:
Database 'MART_DB' does not exist or not authorized.

この時点ではエラーになります。
CONTACT をオブジェクトに関連付けるには、アカウントレベルの APPLY CONTACT 権限またはオブジェクトの所有者権限と CONTACT に対する APPLY 権限が必要です。
ここではアカウントレベル権限を与えます。

USE ROLE ACCOUNTADMIN;
GRANT APPLY CONTACT ON ACCOUNT TO ROLE contact_admin;

SHOW GRANTS TO ROLE contact_admin
    ->> SELECT "privilege","granted_on","name","grantee_name" FROM $1;
+----------------+------------+--------------------------------------+---------------+
| privilege      | granted_on | name                                 | grantee_name  |
|----------------+------------+--------------------------------------+---------------|
| APPLY CONTACT  | ACCOUNT    | <ACCOUNT>                            | CONTACT_ADMIN |
| OWNERSHIP      | CONTACT    | GOVERNANCE.CONTACTS.MY_EMAIL_CONTACT | CONTACT_ADMIN |
| OWNERSHIP      | CONTACT    | GOVERNANCE.CONTACTS.MY_URL_CONTACT   | CONTACT_ADMIN |
| OWNERSHIP      | CONTACT    | GOVERNANCE.CONTACTS.MY_USER_CONTACT  | CONTACT_ADMIN |
| USAGE          | DATABASE   | GOVERNANCE                           | CONTACT_ADMIN |
| CREATE CONTACT | SCHEMA     | GOVERNANCE.CONTACTS                  | CONTACT_ADMIN |
| USAGE          | SCHEMA     | GOVERNANCE.CONTACTS                  | CONTACT_ADMIN |
+----------------+------------+--------------------------------------+---------------+

再度テーブルへの関連付けを実行してみます。

USE ROLE contact_admin;

-- MART_DB内のテーブル(MART_DB/ANALYTICS/ CUSTOMER_PURCHASE_SUMMARY)に関連付け
-- 目的(purpose)は「SUPPORT」としてみる
>ALTER TABLE MART_DB.ANALYTICS.CUSTOMER_PURCHASE_SUMMARY SET CONTACT SUPPORT = governance.contacts.my_email_contact;
+----------------------------------+
| status                           |
|----------------------------------|
| Statement executed successfully. |
+----------------------------------+

-- 確認
USE ROLE SYSADMIN;

>SELECT *
  FROM TABLE(SNOWFLAKE.CORE.GET_CONTACTS('MART_DB.ANALYTICS.CUSTOMER_PURCHASE_SUMMARY', 'TABLE'));
+---------+------------------+------+------+-------+
| PURPOSE | EMAIL            | URL  | USER | LEVEL |
|---------+------------------+------+------+-------|
| SUPPORT | info@example.com | NULL | NULL | TABLE |
+---------+------------------+------+------+-------+

CONTACT を関連付けたので、GUI で確認してみます。テーブルに関連付けたので、対象のテーブルの参照権限があるロールで確認すると下図のように指定の目的(ここでは SUPPORT)欄に表示されます。

image 2

CONTACT の継承

Snowflake のオブジェクトには階層があります。上位の階層にあるオブジェクトに設定した CONTACT は下層のオブジェクトに継承されます。

例えば、データベースに CONTACTを関連付けると、データベース内のスキーマやテーブルにも継承されます。

  • 承認者(ACCESS_APPROVAL)としてデータベースにコンタクトを関連付け
USE ROLE contact_admin;

-- 承認者(ACCESS_APPROVAL)として MART_DB に関連付け
>ALTER DATABASE MART_DB SET CONTACT ACCESS_APPROVAL = governance.contacts.my_user_contact;

GUI で確認します。いずれも「Approver」として連絡先が追加されています。

データベース

image 3

データベース内のスキーマ

image 4

テーブル

image 5

データベースの関連付けを解除してみます。

>ALTER DATABASE MART_DB UNSET CONTACT ACCESS_APPROVAL;
+----------------------------------+
| status                           |
|----------------------------------|
| Statement executed successfully. |
+----------------------------------+

データベース内のテーブルを確認します。当然ですが、継承された連絡先は表示されなくなります(スキーマやデータベースも同様)。

image 6

CONTACT のオーバーライド

同じ目的の CONTACT はオーバーライドできます。例として、別のメールアドレスを指定する CONTACT を作成します。

USE ROLE contact_admin;
USE SCHEMA GOVERNANCE.CONTACTS;

-- EMAIL
CREATE CONTACT my_test_email_contact
  EMAIL_DISTRIBUTION_LIST = 'test@example.com';

先の手順でテーブルへの SUPPORT として CONTACT は割り当て済みな状態から、テーブルが格納されてるスキーマに同じ目的(SUPPORT)として異なる CONTACT を割り当てます。

ALTER SCHEMA MART_DB.ANALYTICS SET CONTACT SUPPORT = governance.contacts.my_test_email_contact;

GUI で確認します。

スキーマ

image 7

テーブル:より下層のオブジェクトで設定した内容でオーバーライドされている。

image 8

その他

CONTACT について、以下のような操作はできません

  • 1つのコンタクトに複数の属性(URL、メールアドレス)を設定
>CREATE CONTACT multi_contact_info
	USERS = ('user1')
	EMAIL_DISTRIBUTION_LIST = 'info@example.com';
511706 (22023): Email, url or users, only one could be set.
  • 事前定義済み以外の目的の設定
>ALTER DATABASE MART_DB SET CONTACT OTHER = governance.contacts.my_test_email_contact;
511710 (22023): SQL compilation error: Purpose type OTHER is not valid, please use access_approval, steward and support.

参照権限を持つユーザーで確認

最後に、参照権限を持つロールを別途作成し、GUI で確認してみます。

--参照権限を持つロールで確認
USE ROLE USERADMIN;
CREATE ROLE data_viewer;

USE ROLE SECURITYADMIN;

GRANT USAGE ON DATABASE mart_db TO ROLE data_viewer;
GRANT USAGE ON SCHEMA mart_db.analytics TO ROLE data_viewer;

GRANT ROLE data_viewer TO ROLE sysadmin;

上記ではスキーマ使用権限までを与えているので、スキーマに設定した連絡先は確認できます。

image (7)

ただし、テーブルの参照権限は与えていないので、テーブルの連絡先は見えません。(前提としてテーブルそのものが見えない)

image (8)

さいごに

オブジェクトの問い合わせ先を目的別に管理できる CONTACT を試してみました。

特に、「スチュワード」「サポート」「承認者」という役割が事前定義されている点が特徴と感じました。組織によってはこれらの役割を1人(1チーム)が兼任することもあるかと思いますが、データ管理において、最低限これらの役割を定義するところから始める、といった型を示しているように感じました。

こちらの内容が何かの参考になれば幸いです。

参考

https://dev.classmethod.jp/articles/developersio-2022-purple-people/

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.