사용자 지정 클린룸 템플릿 참조

사용자 지정 클린룸 템플릿 참조

기능 — 일반 공급(Generally Available)

현재 이 리전들에서 사용할 수 있어요. 정부 및 VPS 배포에서는 사용할 수 없어요.

출처: Custom clean room template reference

본문

클린룸 템플릿 소개

클린룸 템플릿은 JinjaSQL로 작성돼요. JinjaSQL은 출력으로 SQL 쿼리를 생성하는 Jinja 템플릿 언어의 확장이에요. 이를 통해 템플릿이 논리 문과 런타임 변수 해석을 사용할 수 있어, 사용자가 실행 시점에 쿼리에서 사용할 테이블 이름, 테이블 컬럼, 사용자 지정 값을 지정할 수 있게 해 줘요. Snowflake는 일반적인 사용 사례를 위한 몇 가지 사전 설계된 템플릿을 제공해요. 그러나 대부분의 사용자는 클린룸을 위해 사용자 지정 쿼리 템플릿을 만드는 것을 선호해요.

사용자 지정 템플릿은 클린룸 API를 사용해 생성되지만, 코드나 클린룸 UI를 사용해 실행할 수 있어요. 템플릿에는 두 가지 일반적인 유형이 있어요.

  • 분석(analysis) 템플릿 — 템플릿 실행자에게 결과를 보여 주는 SELECT 문(또는 SELECT 작업 집합)으로 평가돼요.
  • 활성화(activation) 템플릿 — 현재 환경에서 결과를 보여 주는 대신 결과를 Snowflake 계정 또는 타사에 활성화하는 데 사용돼요. 활성화 템플릿은 몇 가지 추가 요구 사항이 있다는 점만 제외하면 분석 템플릿과 매우 유사해요.

클린룸 UI에서 분석 템플릿은 활성화 템플릿과 연결될 수 있어, 호출자가 분석을 실행하고 결과를 확인한 다음 자신이나 타사에 데이터를 활성화할 수 있게 해 줘요. 활성화 템플릿은 연결된 분석 템플릿과 동일한 쿼리로 평가될 필요는 없어요.

사용자 지정 템플릿 생성 및 실행

기본 설정의 클린룸에서 프로바이더는 클린룸에 템플릿을 추가하고 소비자는 템플릿을 실행해요. 자세한 내용은 사용자 지정 템플릿 사용 문서를 참고하세요.

빠른 예시

프로바이더 테이블과 소비자 테이블을 이메일로 조인하고 도시별 중첩 수를 보여 주는 간단한 SQL 예시는 다음과 같아요.

SELECT COUNT(*), city
FROM consumer_table
INNER JOIN provider_table ON consumer_table.hashed_email = provider_table.hashed_email
GROUP BY city;

호출자가 JOIN 및 GROUP BY 컬럼과 사용할 테이블을 선택할 수 있게 해 주는 JinjaSQL 템플릿으로 해당 쿼리를 표현하면 다음과 같아요.

SELECT COUNT(*), IDENTIFIER({{ group_by_col | column_policy }})
FROM IDENTIFIER({{ my_table[0] }}) AS c
INNER JOIN IDENTIFIER({{ source_table[0] }}) AS p
ON IDENTIFIER({{ consumer_join_col | join_policy }}) = IDENTIFIER({{ provider_join_col | join_policy }})
GROUP BY IDENTIFIER({{ group_by_col | column_policy }});

템플릿에 대한 참고 사항:

  • {{ 이중 중괄호 쌍 }} 안의 값은 사용자 지정 변수예요.
  • group_by_col, my_table, source_table, consumer_join_col, provider_join_col, group_by_col은 모두 호출자가 채우는 사용자 지정 변수예요.
  • source_table과 my_table은 호출자가 채우는 Snowflake 정의 문자열 배열 변수예요. 배열 멤버는 클린룸에 연결된 프로바이더 및 소비자 테이블의 정규화된 이름(full-qualified names)이에요. 호출자는 각 배열에 포함할 테이블을 지정해요.
  • 프로바이더 테이블은 템플릿에서 소문자 p, 소비자 테이블은 소문자 c로 별칭을 지정해야 해요. 여러 테이블이 있다면 p1, p2, c1, c2 등으로 인덱싱할 수 있어요.
  • 모든 컬럼 및 테이블 이름에 IDENTIFIER가 필요한데, 이는 {{ 이중 중괄호 }} 안의 변수가 유효한 식별자가 아닌 문자열 리터럴로 평가되기 때문이에요.
  • JinjaSQL 필터를 변수에 적용해 어느 한쪽이 설정한 조인 또는 컬럼 정책을 적용할 수 있어요. Snowflake는 사용자 지정 필터 join_policy와 column_policy를 구현하며, 이 필터는 컬럼이 각각 클린룸의 조인 또는 컬럼 정책을 준수하는지 확인하고 그렇지 않으면 쿼리를 실패시켜요. 필터는 {{ *column_name* | *filter_name* }} 형식으로 컬럼 이름에 적용돼요. 이러한 모든 내용은 나중에 자세히 다룰게요.

소비자가 코드에서 이 템플릿을 실행하는 방법은 다음과 같아요. 컬럼 이름이 템플릿에 선언된 테이블 별칭으로 한정되는 방식을 주목하세요.

CALL SAMOOHA_BY_SNOWFLAKE_LOCAL_DB.CONSUMER.RUN_ANALYSIS(
  $cleanroom_name,
  $template_name,
  ['my_db.my_sch.consumer_table'],   -- Populates the my_table variable
  ['my_db.my_sch.provider_table'],   -- Populates the source_table variable
  OBJECT_CONSTRUCT(                  -- Populates custom named variables
    'consumer_join_col','c.age_band',
    'provider_join_col','p.age_band',
    'group_by_col','p.device_type'
  )
);

클린룸 UI에서 이 템플릿을 사용하려면 프로바이더가 템플릿용 사용자 지정 UI 양식을 만들어야 해요. UI 양식에는 템플릿 변수 이름에 해당하는 이름이 있는 양식 요소가 있으며, 양식에서 제공된 값이 템플릿으로 전달돼요.

사용자 지정 템플릿 개발

클린룸 템플릿은 JinjaSQL 템플릿이에요. 템플릿을 만들려면 다음 항목에 익숙해야 해요.

consumer.get_jinja_sql 절차를 사용해 템플릿의 유효성을 검사한 다음, 렌더링된 템플릿을 실행해 기대하는 결과가 나오는지 확인하세요. 이 절차는 join_policy 같은 클린룸 필터 확장을 지원하지 않으므로, 템플릿을 해당 필터 없이 테스트한 다음 나중에 추가해야 해요.

예시:

-- Template to test
SELECT {{ col1 | sqlsafe }}, {{ col2 | sqlsafe }}
FROM IDENTIFIER({{ source_table[0] }}) AS p
JOIN IDENTIFIER({{ my_table[0] }}) AS c
ON {{ provider_join_col | sqlsafe }} = {{ consumer_join_col | sqlsafe}}
{% if where_phrase %} WHERE {{ where_phrase | sqlsafe}}{% endif %};
-- Render the template.
USE WAREHOUSE app_wh;
USE ROLE SAMOOHA_APP_ROLE;

CALL SAMOOHA_BY_SNOWFLAKE_LOCAL_DB.CONSUMER.GET_SQL_JINJA(
  $$
  SELECT {{ col1 | sqlsafe }}, {{ col2 | sqlsafe }}
  FROM IDENTIFIER({{ source_table[0] }}) AS p
  JOIN IDENTIFIER({{ my_table[0] }}) AS c
  ON IDENTIFIER({{ provider_join_col }}) = IDENTIFIER({{ consumer_join_col }})
  {% if where_phrase %} WHERE {{ where_phrase | sqlsafe }}{% endif %};
  $$,
  object_construct(
    'col1', 'c.status',
    'col2', 'c.age_band',
    'where_phrase', 'p.household_size > 2',
    'consumer_join_col', 'c.age_band',
    'provider_join_col', 'p.age_band',
    'source_table', ['SAMOOHA_SAMPLE_DATABASE.DEMO.CUSTOMERS'],
    'my_table', ['SAMOOHA_SAMPLE_DATABASE.DEMO.CUSTOMERS']
  )
);

렌더링된 템플릿은 다음과 같아요.

SELECT c.status, c.age_band
FROM IDENTIFIER('SAMOOHA_SAMPLE_DATABASE.DEMO.CUSTOMERS') AS p
JOIN IDENTIFIER('SAMOOHA_SAMPLE_DATABASE.DEMO.CUSTOMERS') AS c
ON p.age_band = c.age_band
WHERE p.household_size > 2;

환경에서 위 SQL 문을 실행해 동작하고 기대하는 결과가 나오는지 확인해 보세요. 그런 다음 WHERE 절 없이 템플릿을 테스트해 보세요.

-- Render the template without a WHERE clause
CALL SAMOOHA_BY_SNOWFLAKE_LOCAL_DB.CONSUMER.GET_SQL_JINJA(
  $$
  SELECT {{ col1 | sqlsafe }}, {{ col2 | sqlsafe }}
  FROM IDENTIFIER({{ source_table[0] }}) AS p
  JOIN IDENTIFIER({{ my_table[0] }}) AS c
  ON {{ provider_join_col | sqlsafe }} = {{ consumer_join_col | sqlsafe}}
  {% if where_phrase %} WHERE {{ where_phrase | sqlsafe }}{% endif %};
  $$,
  object_construct(
    'col1', 'c.status',
    'col2', 'c.age_band',
    'consumer_join_col', 'c.age_band',
    'provider_join_col', 'p.age_band',
    'source_table', ['SAMOOHA_SAMPLE_DATABASE.DEMO.CUSTOMERS'],
    'my_table', ['SAMOOHA_SAMPLE_DATABASE.DEMO.CUSTOMERS']
  )
);

렌더링된 템플릿:

SELECT c.status, c.age_band
FROM IDENTIFIER('SAMOOHA_SAMPLE_DATABASE.DEMO.CUSTOMERS') AS p
JOIN IDENTIFIER('SAMOOHA_SAMPLE_DATABASE.DEMO.CUSTOMERS') AS c
ON p.age_band = c.age_band;

정책 필터를 템플릿에 추가하고, 템플릿을 클린룸에 추가하세요.

CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template(
  $cleanroom_name,
  'simple_template',
  $$
  SELECT {{ col1 | sqlsafe | column_policy }}, {{ col2 | sqlsafe | column_policy }}
  FROM IDENTIFIER({{ source_table[0] }}) AS p
  JOIN IDENTIFIER({{ my_table[0] }}) AS c
  ON {{ provider_join_col | sqlsafe | join_policy }} = {{ consumer_join_col | sqlsafe | join_policy }}
  {% if where_phrase %} WHERE {{ where_phrase | sqlsafe }}{% endif %};
  $$,
);

데이터 보호

템플릿은 프로바이더와 소비자가 클린룸에 연결한 데이터셋에만 접근할 수 있어요. 프로바이더와 소비자 모두 자체 데이터에 조인, 컬럼, 활성화 정책을 설정해 어떤 컬럼에 조인하거나, 프로젝션하거나, 활성화할 수 있는지 보호할 수 있어요. 그러나 정책이 적용되려면 템플릿이 컬럼에 적절한 JinjaSQL 정책 필터를 포함해야 해요.

사용자 지정 템플릿 구문

Snowflake Data Clean Rooms는 몇 가지 확장과 함께 V3 JinjaSQL을 지원해요. 이 섹션에는 다음 항목이 포함돼요.

템플릿 명명 규칙

템플릿을 만들 때 이름은 모두 소문자, 숫자, 공백, 밑줄이어야 해요. 활성화 템플릿(소비자 실행 프로바이더 활성화 제외)은 activation_으로 시작해야 해요. 템플릿 이름은 provider.add_custom_sql_template 또는 consumer.create_template_request를 호출할 때 지정돼요.

유효한 이름 예시:

  • my_template
  • activation_template_1

잘못된 이름 예시:

  • my template — 공백은 허용되지 않아요.
  • My_Template — 소문자 템플릿만 허용돼요.

템플릿 변수

템플릿 호출자는 템플릿 변수에 값을 전달할 수 있어요. JinjaSQL 구문은 {{ 이중_중괄호 }} 안의 모든 변수 이름에 대해 변수 바인딩을 가능하게 하지만, Snowflake는 아래에 설명된 대로 재정의하지 말아야 할 몇 가지 변수 이름을 예약해요.

주의

Snowflake 정의든 사용자 지정이든 모든 변수는 사용자가 채우므로 적절한 주의를 기울여 취급해야 해요. Snowflake Data Clean Rooms 템플릿은 단일 SELECT 문으로 평가되어야 하지만, 모든 변수는 호출자가 전달한다는 점을 여전히 기억해야 해요.

Snowflake 정의 변수

모든 클린룸 템플릿은 Snowflake가 정의하지만 호출자가 전달하는 다음 전역 변수에 접근할 수 있어요.

  • source_table — 템플릿에서 사용할 수 있는 클린룸 내 프로바이더 연결 테이블과 뷰의 0 기반(zero-based) 문자열 배열이에요. 테이블 이름은 정규화되어 있어요. 예: my_db.my_sch.provider_customers. 예시: SELECT col1 FROM IDENTIFIER({{ source_table[0] }}) AS p;

  • my_table — 템플릿에서 사용할 수 있는 클린룸 내 소비자 테이블과 뷰의 0 기반 문자열 배열이에요. 테이블 이름은 정규화되어 있어요. 예: my_db.my_sch.consumer_customers. 예시: SELECT col1 FROM IDENTIFIER({{ my_table[0] }}) AS c;

  • privacy — 사용자와 템플릿과 관련된 프라이버시 관련 값 집합이에요. 사용 가능한 하위 필드 목록을 참고하세요. 이러한 값은 사용자에 대해 명시적으로 설정할 수 있지만, 템플릿에서 기본값을 설정하고 싶을 수도 있어요. 템플릿에서 privacy.threshold 같은 하위 필드에 직접 접근하세요.

    예시: 집계 절에서 최소 그룹 크기를 적용하기 위해 threshold_value를 사용하는 템플릿 스니펫은 다음과 같아요.

    SELECT IFF(a.overlap > ( {{ privacy.threshold_value | default(2) | sqlsafe }} ), a.overlap,1 ) AS overlap,
      c.total_count AS total_count ...
    
  • measure_column, dimensions, where_clause — 레거시 클린룸 전역 변수예요. 더 이상 사용을 권장하지 않지만 여전히 정의되어 일부 레거시 템플릿과 문서에 나타나므로, 이름 충돌을 피하기 위해 이 이름들 중 어느 것으로도 테이블이나 컬럼에 별칭을 지정하지 말아야 해요.

    • 템플릿이 measure_column이나 dimensions를 사용하면, 이 변수들로 전달되는 모든 컬럼에 대해 컬럼 정책이 확인돼요.
    • 템플릿이 조인 조건(예: table1.column1 = table2.column2)이 있는 where_clause를 사용하면, 거기에 이름이 지정된 모든 컬럼에 대해 조인 정책이 확인되고, 그렇지 않으면 거기에 이름이 지정된 모든 컬럼에 대해 컬럼 정책이 확인돼요.
사용자 지정 변수

템플릿 작성자는 호출자가 채울 수 있는 임의의 변수를 템플릿에 포함할 수 있어요. 이 변수들은 Snowflake 정의 변수나 테이블 별칭 이름을 제외한 모든 임의의 Jinja 준수 이름을 가질 수 있어요. 템플릿을 클린룸 UI에서 사용할 수 있게 하려면 클린룸 UI 사용자를 위한 UI 양식도 제공해야 해요. API 사용자에게는 필수 및 선택 변수에 대한 좋은 문서를 제공해야 해요.

템플릿은 사용자 지정 변수 max_income에 대해 다음과 같이 접근할 수 있어요.

SELECT income
FROM my_db.my_sch.customers
WHERE income < {{ max_income }};

사용자는 두 가지 다른 방식으로 템플릿에 변수를 전달할 수 있어요.

  • 클린룸 UI에서 템플릿 개발자가 만든 UI 양식을 통해 값을 선택하거나 제공해요. 이 UI 양식에는 사용자가 템플릿에 값을 제공할 수 있는 양식 요소가 포함돼요. 양식 요소의 이름은 변수의 이름이에요. 템플릿은 간단히 양식 요소의 이름을 사용해 값에 접근해요. UI 양식은 provider.add_ui_form_customizations로 만들어요.
  • 코드에서 소비자는 consumer.run_analysis를 호출하고, 테이블 이름을 인수 배열로, 사용자 지정 변수를 이름-값 쌍으로 analysis_arguments 인수에 전달해요.

참고

클린룸에 업로드된 사용자 지정 Python 코드에서 사용자 제공 값에 접근해야 한다면, Python 함수 인수를 통해 코드에 변수 값을 명시적으로 전달해야 해요. {{jinja 변수 바인딩 구문}}을 사용해 Python 코드 내에서 템플릿 변수에 직접 접근할 수는 없어요.

변수 올바르게 해석하기

템플릿에 전달된 문자열 값은 최종 템플릿에서 문자열 리터럴로 해석돼요. 바인딩된 변수를 적절히 처리하지 않으면 SQL 구문 또는 논리 오류가 발생할 수 있어요.

  • SELECT {{ my_col }} FROM P; — 이는 SELECT 'my_col' from P;로 해석되어 단순히 문자열 "my_col"을 반환해요. 아마 원하는 것이 아닐 거예요.
  • SELECT age FROM {{ my_table[0] }} AS P; — 이는 SELECT age FROM 'somedb.somesch.my_table' AS P;로 해석되어 구문 오류를 일으켜요. 테이블은 리터럴 문자열이 아니라 식별자여야 하기 때문이에요.
  • SELECT age FROM IDENTIFIER({{ my_table[0] }}) AS P {{ where_clause }}; — "WHERE age < 50"을 전달하면 SELECT age FROM mytable AS P 'WHERE age < 50';로 평가되어 리터럴 문자열 WHERE 절 때문에 구문 오류가 발생해요.

따라서 적절한 곳에서 변수를 해석해야 해요. 템플릿에서 변수를 올바르게 해석하는 방법은 다음과 같아요.

테이블 및 컬럼 이름 해석 — 테이블 또는 컬럼 이름을 지정하는 변수는 다음 두 가지 방법 중 하나로 템플릿에서 식별자로 변환해야 해요.

  • IDENTIFIER: 예: SELECT IDENTIFIER({{ my_column }}) FROM P;
  • sqlsafe: 이 JinjaSQL 필터는 식별자 문자열을 SQL 텍스트로 해석해요. 이전 항목과 동등한 문은 SELECT {{ my_column | sqlsafe }} FROM P;이에요.

특정 사용 방식에 따라 IDENTIFIER 또는 sqlsafe 중 무엇을 사용할지가 정해져요. 예를 들어 c.{{ my_column | sqlsafe }}는 IDENTIFIER로 쉽게 다시 쓸 수 없어요.

동적 SQL 해석 — WHERE 절처럼 리터럴 SQL로 사용해야 하는 문자열 변수가 있다면 템플릿에서 sqlsafe 필터를 사용하세요.

SELECT age FROM IDENTIFIER({{ my_table[0] }}) AS C
WHERE {{ where_clause }};

사용자가 where_clause에 "age < 50"을 전달하면 쿼리는 SELECT age FROM *sometable* AS C WHERE 'age < 50';로 해석되며, 이는 리터럴 문자열 WHERE 조건 때문에 잘못된 SQL이에요. 이 경우 sqlsafe 필터를 사용해야 해요.

SELECT age FROM IDENTIFIER( {{ my_table[0] }} ) as c
{{ where_clause | sqlsafe }};

필수 테이블 별칭

쿼리의 최상위 레벨에서 모든 테이블 또는 하위 쿼리는 Snowflake가 쿼리에서 조인 및 컬럼 정책을 올바르게 검증할 수 있도록 p(프로바이더 테이블의 경우) 또는 c(소비자 테이블의 경우)로 별칭을 지정해야 해요. 조인 또는 컬럼 정책에 대해 검증해야 하는 모든 컬럼은 소문자 p 또는 c 테이블 별칭으로 한정되어야 해요(p 또는 c를 지정하면 백엔드가 컬럼을 프로바이더 정책 또는 소비자 정책 중 어느 것에 대해 검증할지 알려 줘요).

쿼리에서 여러 프로바이더 또는 소비자 테이블을 사용한다면, 첫 번째 이후의 각 테이블 별칭에 1 기반의 순차적 숫자 접미사를 추가하세요. 즉, 첫 번째, 두 번째, 세 번째 프로바이더 테이블에 대해 p, p1, p2를 사용하고, 첫 번째, 두 번째, 세 번째 소비자 테이블에 대해 c, c1, c2를 사용해요. p 또는 c 인덱스는 공백 없이 순차적이어야 해요(즉, p, p1, p2 별칭을 만들지 p, p2, p4를 만들지 말아요).

예시

SELECT p.col1 FROM IDENTIFIER({{ source_table[0] }}) AS P
UNION
SELECT p1.col1 FROM IDENTIFIER({{ source_table[1] }}) AS P1;

사용자 지정 클린룸 템플릿 필터

Snowflake는 모든 표준 Jinja 필터와 대부분의 표준 JinjaSQL 필터를 몇 가지 확장과 함께 지원해요.

  • join_policy — 컬럼이 데이터 소유자의 조인 정책에 있으면 성공하고, 그렇지 않으면 실패해요.
  • column_policy — 컬럼이 데이터 소유자의 컬럼 정책에 있으면 성공하고, 그렇지 않으면 실패해요.
  • activation_policy — 컬럼이 데이터 소유자의 활성화 정책에 있으면 성공하고, 그렇지 않으면 실패해요.
  • join_and_column_policy — 컬럼이 데이터 소유자의 조인 또는 컬럼 정책에 있으면 성공하고, 그렇지 않으면 실패해요.

identifier JinjaSQL 필터는 Snowflake 템플릿에서 지원되지 않아요.

팁

JinjaSQL 문은 왼쪽에서 오른쪽으로 평가돼요.

  • {{ my_col | column_policy }} 올바름
  • {{ my_col | sqlsafe | column_policy }} 올바름
  • {{ column_policy | my_col }} 잘못됨
  • {{ my_col | column_policy | sqlsafe }} 잘못됨 — column_policy가 my_col 값을 문자열로 확인하게 되며 이는 오류예요.

클린룸 정책 적용

클린룸은 템플릿에 사용된 컬럼에 대해 클린룸 정책을 자동으로 확인하지 않아요. 컬럼에 정책을 적용하려면 다음을 수행해야 해요.

  • 템플릿의 해당 컬럼에 적절한 정책 필터를 적용해야 해요. 예:

    JOIN IDENTIFIER({{ source_table[0] }}) AS p
    ON IDENTIFIER({{ c_join_col | join_policy }}) = IDENTIFIER({{ p_join_col | join_policy }})
    
  • 테이블을 소문자 p 또는 c로 별칭을 지정해야 해요. 필수 테이블 별칭을 참고하세요.

정책은 다른 협업자가 소유한 컬럼에 대해서만 확인되며, 자신의 데이터에 대한 정책은 확인되지 않아요. 정책을 테스트할 때 컬럼 이름은 모호할 수 없다는 점을 유의하세요. 따라서 두 테이블에 같은 이름의 컬럼이 있다면 해당 컬럼에 대해 정책을 테스트하려면 컬럼 이름을 한정해야 해요.

사용자 지정 Python 코드 실행

템플릿은 클린룸에 업로드된 Python 코드를 실행할 수 있어요. 템플릿은 데이터 행의 값을 받아 쿼리에서 사용하거나 프로젝션할 값을 반환하는 Python 함수를 호출할 수 있어요.

  • 프로바이더가 클린룸에 사용자 지정 Python 코드를 업로드하면, 템플릿은 cleanroom.*function_name* 구문으로 Python 함수를 호출해요. 자세한 내용은 여기를 참고하세요.
  • 소비자가 클린룸에 사용자 지정 Python 코드를 업로드하면, 템플릿은 consumer.generate_python_request_template에 전달된 함수 이름(function_name)을 그대로 사용해 함수를 호출해요(프로바이더 코드처럼 cleanroom 범위로 지정하지 않아요). 자세한 내용은 여기를 참고하세요.

프로바이더 코드 예시:

-- Provider uploads a Python function that takes two numbers and returns the sum.
CALL samooha_by_snowflake_local_db.provider.load_python_into_cleanroom(
  $cleanroom_name,
  'simple_addition',               -- Function name to use in the template
  ['someval integer', 'added_val integer'],   -- Arguments
  [],                              -- No packages needed
  'integer',                       -- Return type
  'main',                          -- Handler for function name
  $$
  def main(input, added_val):
    return input + int(added_val)
  $$
);
-- Template passes value from each row to the function, along with a
-- caller-supplied argument named 'increment'
CALL samooha_by_snowflake_local_db.provider.add_custom_sql_template(
  $cleanroom_name,
  'simple_python_example',
  $$
  SELECT val, cleanroom.simple_addition(val, {{ increment | sqlsafe }})
  FROM VALUES (5),(8),(12),(39) AS P(val);
  $$
);

보안 고려 사항

클린룸 템플릿은 현재 사용자의 신원으로 실행되지 않아요. 사용자는 클린룸 내 어떤 데이터에도 직접 접근할 수 없으며, 모든 접근은 네이티브 애플리케이션을 통한 템플릿 결과를 통해 이루어져요. 템플릿에서 컬럼을 사용할 때마다 정책 필터를 적용해 자신의 정책과 모든 협업자의 정책이 존중되도록 하세요. 가능하면 사용자 제공 변수를 IDENTIFIER()로 감싸서 SQL 주입 공격에 대한 템플릿을 강화하세요.

활성화 템플릿

템플릿은 쿼리 결과를 클린룸 외부의 테이블에 저장하는 데에도 사용할 수 있으며, 이를 *활성화(activation)*라고 해요. 현재 사용자 지정 템플릿에 대해 지원되는 활성화 형식은 프로바이더 활성화와 소비자 활성화(각각 결과를 프로바이더 또는 소비자의 Snowflake 계정에 저장)뿐이에요. 활성화 구현 방법 알아보기.

활성화 템플릿은 다음 추가 요구 사항이 있는 분석 템플릿이에요.

  • 활성화 템플릿은 단순 SELECT 문일 수 있는 분석 템플릿과 달리 SQL 스크립트 블록으로 평가되는 JinjaSQL 문이에요.
  • 활성화 템플릿은 결과를 저장할 클린룸 내 테이블을 만들고, 생성된 테이블 이름(또는 이름 조각)을 템플릿 호출자에게 반환해요.
  • 스크립트 블록은 cleanroom. 또는 cleanroom.activation_data_ 접두사를 뺀 생성된 테이블 이름을 반환하는 RETURN 문으로 끝나야 해요.

템플릿 이름, 템플릿이 만드는 내부 테이블 이름, 템플릿이 반환하는 테이블 이름은 다음 패턴을 따라요.

활성화 유형 템플릿 이름 접두사 테이블 이름 접두사 반환되는 테이블 이름
소비자 실행 소비자 activation_ cleanroom.activation_data_* 접두사 없는 테이블 이름
소비자 실행 프로바이더 접두사 필요 없음 cleanroom.activation_data_* 접두사 없는 테이블 이름
프로바이더 실행 프로바이더 activation_ cleanroom.temp_result_data가 전체 테이블 이름 temp_result_data
  • 활성화되는 모든 컬럼은 데이터를 연결한 프로바이더 또는 소비자의 활성화 정책에 나열되어야 하며, 해당 컬럼에 activation_policy 필터를 적용해야 해요. 컬럼은 활성화 컬럼이면서 조인 컬럼일 수도 있다는 점을 유의하세요.
  • 템플릿이 클린룸 UI에서 실행될 예정이라면 activation_template_name과 enabled_activations 필드를 포함하는 웹 양식을 제공해야 해요. UI에서 사용할 템플릿은 분석 템플릿과 연결된 활성화 템플릿을 모두 가져야 해요.
  • 테이블이 생성되므로 계산된 컬럼은 모두 추론된 이름이 아니라 명시적으로 별칭을 지정해야 해요. 즉, SELECT COUNT(*), p.status from T AS P;는 COUNT 컬럼 이름이 추론되므로 실패하고, SELECT COUNT(*) AS COUNT_OF_ITEMS, p.status from T AS P;는 COUNT 컬럼을 명시적으로 별칭하므로 성공해요.

다음은 두 개의 샘플 기본 활성화 템플릿이에요. 하나는 프로바이더 실행 서버 활성화용이고, 다른 하나는 다른 활성화 유형용이에요. 두 템플릿은 결과 테이블 이름이 포함된 두 줄에서 차이가 나요.

프로바이더 실행 프로바이더 활성화 템플릿 — 테이블 이름은 cleanroom.temp_result_data여야 해요.

BEGIN
  CREATE OR REPLACE TABLE cleanroom.temp_result_data AS
  SELECT COUNT(c.status) AS ITEM_COUNT, c.status, c.age_band
  FROM IDENTIFIER({{ my_table[0] }}) AS c
  JOIN IDENTIFIER({{ source_table[0] }}) AS p
  ON {{ c_join_col | sqlsafe | activation_policy }} = {{ p_join_col | sqlsafe | activation_policy }}
  GROUP BY c.status, c.age_band
  ORDER BY c.age_band;
  RETURN 'temp_result_data';
END;

기타 활성화 템플릿 — 테이블 이름은 cleanroom.activation_data 접두사가 필요해요.

BEGIN
  CREATE OR REPLACE TABLE cleanroom.activation_data_analysis_results AS
  SELECT COUNT(c.status) AS ITEM_COUNT, c.status, c.age_band
  FROM IDENTIFIER({{ my_table[0] }}) AS c
  JOIN IDENTIFIER({{ source_table[0] }}) AS p
  ON {{ c_join_col | sqlsafe | activation_policy }} = {{ p_join_col | sqlsafe | activation_policy }}
  GROUP BY c.status, c.age_band
  ORDER BY c.age_band;
  RETURN 'analysis_results';
END;

다음 단계

템플릿 시스템을 익힌 후에는 템플릿 유형으로 클린룸을 구현하기 위한 구체적인 내용을 읽어 보세요.

  • 프로바이더 템플릿은 프로바이더가 작성하는 템플릿이에요. 이것이 기본 사용 사례예요.
  • 소비자 템플릿은 소비자가 작성하는 템플릿이에요. 경우에 따라 클린룸 생성자는 소비자가 자신의 템플릿을 만들어 업로드하고 실행할 수 있게 하려고 해요.
  • 활성화 템플릿은 성공적인 실행 후 결과 테이블을 만들어요. 활성화 템플릿에 따라 결과 테이블은 클린룸 외부의 프로바이더 또는 소비자 계정에 저장되거나, Activation Hub에 나열된 타사 활성화 제공자에게 전송될 수 있어요.
  • 연쇄 템플릿을 사용하면 여러 템플릿을 서로 연결할 수 있으며, 각 템플릿의 출력이 체인의 다음 템플릿에서 사용돼요.

추가 정보

더 알아보기