Guide · Native Data Quality

Snowflake data quality rules in GitHub: dev, test and production

Snowflake2026-11-05Code ran before publishing, PDF by email

The short answer

Keep your data quality rules in one SQL file in GitHub. Run that file once in each environment, so dev, test and production get the same rules. Then run a check query that reports every rule as OK, VIOLATED, CHANGED, MISSING or EXTRA. We tested the file-and-check setup on Snowflake with three rules in three environments.

What you will have at the end

Three plain SQL files. dq_rules.sql holds the rules and is the file you commit to GitHub. dq_rules_check.sql reports, for one environment, whether each rule is attached with the repository's expectation, whether any row breaks it, and anything attached that the repository does not list. setup_test_environments.sql only builds stand-in DEV, TEST and PROD schemas so you can watch the rules and the check work. Full details are in the full guide (PDF).

Each rule is a custom data metric function (read 2026-11-05) that returns the number of rows breaking the rule, so 0 means pass. Snowflake says a data metric function (DMF) measures an attribute of your data, and that a DMF combined with an expectation becomes a data quality check. Snowflake says data quality monitoring requires Enterprise Edition (Snowflake docs (read 2026-11-05)).

Our guide on moving ETL rules into data metric functions explains how a single rule is written. This guide is about what happens next: keeping those rules identical across environments.

Step 1. Keep the rules in one file that names no database or schema

The file below creates three rules, then attaches them to the ORDERS table in whatever schema the session is pointed at. Because it names no database or schema, running it in DEV, TEST or PROD gives each the same rules. Change a rule by editing its body in a pull request, and every environment gets the change the next time the file runs.

The file starts by detaching its own rules if they are already attached. That is what makes it safe to run again. Snowflake's documentation allows only one data metric function of a given kind on a column, and its ALTER TABLE syntax lists no IF EXISTS form for dropping one (Snowflake docs (read 2026-11-05)), so the file looks first and drops only what is there. Our runs show it can be run on top of schemas that already have the rules.

SQL: dq_rules.sql
-- Data quality rules for the ORDERS table, kept as code. Commit this file to your repository.
-- Run it once per environment, after pointing the session at that environment's database and schema
-- (USE DATABASE ...; USE SCHEMA ...;). It names no database or schema, so the same file gives DEV, TEST
-- and PROD the same rules. Safe to run again: it detaches its own rules first if they are attached.
-- Needs Snowflake Enterprise Edition. Each rule returns the number of rows that BREAK it, so 0 passes.

-- 1. Detach the rules this file owns, if they are attached. Snowflake has no DROP ... IF EXISTS for
--    a rule on a table and refuses to attach the same rule twice, so look first.
EXECUTE IMMEDIATE $$
DECLARE
  n NUMBER;
BEGIN
  SELECT COUNT(*) INTO :n FROM TABLE(INFORMATION_SCHEMA.DATA_METRIC_FUNCTION_REFERENCES(
    REF_ENTITY_NAME => 'ORDERS', REF_ENTITY_DOMAIN => 'TABLE')) WHERE METRIC_NAME = 'RULE_PRICE_POSITIVE';
  IF (n > 0) THEN ALTER TABLE ORDERS DROP DATA METRIC FUNCTION RULE_PRICE_POSITIVE ON (O_TOTALPRICE); END IF;
  SELECT COUNT(*) INTO :n FROM TABLE(INFORMATION_SCHEMA.DATA_METRIC_FUNCTION_REFERENCES(
    REF_ENTITY_NAME => 'ORDERS', REF_ENTITY_DOMAIN => 'TABLE')) WHERE METRIC_NAME = 'RULE_STATUS_VALID';
  IF (n > 0) THEN ALTER TABLE ORDERS DROP DATA METRIC FUNCTION RULE_STATUS_VALID ON (O_ORDERSTATUS); END IF;
  SELECT COUNT(*) INTO :n FROM TABLE(INFORMATION_SCHEMA.DATA_METRIC_FUNCTION_REFERENCES(
    REF_ENTITY_NAME => 'ORDERS', REF_ENTITY_DOMAIN => 'TABLE')) WHERE METRIC_NAME = 'RULE_CUSTOMER_EXISTS';
  IF (n > 0) THEN ALTER TABLE ORDERS DROP DATA METRIC FUNCTION RULE_CUSTOMER_EXISTS ON (O_CUSTKEY, TABLE (CUSTOMER(C_CUSTKEY))); END IF;
  RETURN 'rules detached';
END;
$$;

-- 2. The rules. Change a rule by editing its body here, in a pull request.
CREATE OR REPLACE DATA METRIC FUNCTION RULE_PRICE_POSITIVE(arg_t TABLE(arg_c NUMBER))
RETURNS NUMBER AS
$$ SELECT COUNT(*) FROM arg_t WHERE arg_c IS NULL OR arg_c <= 0 $$;

CREATE OR REPLACE DATA METRIC FUNCTION RULE_STATUS_VALID(arg_t TABLE(arg_c VARCHAR))
RETURNS NUMBER AS
$$ SELECT COUNT(*) FROM arg_t WHERE arg_c IS NULL OR arg_c NOT IN ('F', 'O', 'P') $$;

CREATE OR REPLACE DATA METRIC FUNCTION RULE_CUSTOMER_EXISTS(
  arg_t1 TABLE(arg_c1 NUMBER), arg_t2 TABLE(arg_c2 NUMBER))
RETURNS NUMBER AS
-- NOT EXISTS, not NOT IN: one NULL key in the customer table would make NOT IN match no row.
$$ SELECT COUNT(*) FROM arg_t1
   WHERE arg_c1 IS NULL OR NOT EXISTS (SELECT 1 FROM arg_t2 WHERE arg_t2.arg_c2 = arg_t1.arg_c1) $$;

-- 3. Attach them to the table in the current schema, each with an expectation that the count is 0.
ALTER TABLE ORDERS SET DATA_METRIC_SCHEDULE = '60 MINUTE';
ALTER TABLE ORDERS ADD DATA METRIC FUNCTION RULE_PRICE_POSITIVE ON (O_TOTALPRICE)
  EXPECTATION price_positive (VALUE = 0);
ALTER TABLE ORDERS ADD DATA METRIC FUNCTION RULE_STATUS_VALID ON (O_ORDERSTATUS)
  EXPECTATION status_valid (VALUE = 0);
ALTER TABLE ORDERS ADD DATA METRIC FUNCTION RULE_CUSTOMER_EXISTS ON (O_CUSTKEY, TABLE (CUSTOMER(C_CUSTKEY)))
  EXPECTATION customer_exists (VALUE = 0);

Rule 3 reads a second table, so it takes two table arguments. Snowflake documents that pattern for referential checks (Snowflake docs (read 2026-11-05)). It uses NOT EXISTS rather than NOT IN because one NULL key in the customer table would make NOT IN match no row at all.

Step 2. Run the same file in each environment

Point the session at the environment, then run the file. The only thing that differs between environments is the two USE lines, so keep them in a tiny file of their own, one per environment, outside the rules file.

SQL: one small file per environment
-- use_prod.sql: the one file that differs per environment
USE DATABASE ANALYTICS_PROD;
USE SCHEMA SALES;

With the Snowflake CLI, passing several -f options runs the files in order on a single connection (Snowflake CLI docs (read 2026-11-05)), so a pipeline step for production can look like this:

snow sql -f use_prod.sql -f dq_rules.sql -f dq_rules_check.sql

We did not run the CLI or a GitHub-connected pipeline for this guide. We ran the same files through our test runner, which sent the USE lines and then the file, once for each environment. Snowflake can also run a SQL file straight from a clone of a Git repository with EXECUTE IMMEDIATE FROM (Snowflake docs (read 2026-11-05); Snowflake docs (read 2026-11-05)). We did not test that route either.

In our test the three environments are three schemas in one sandbox database, built by setup_test_environments.sql from 1,000 orders and the 1,000 customers they are checked against. We ran dq_rules.sql in each. The detach step ends by printing one line, whether or not it had anything to detach:

Output from our run: the detach step, on a schema where nothing was attached yet
anonymous block
---------------
rules detached

Step 3. Check each environment against the repository

Deploying does not prove that an environment stays right. Someone can detach a rule by hand, attach a rule the repository does not know about, or change a rule's expectation, and bad rows can arrive. The check file lists the rules the repository expects, compares that list with what is attached to the table, and reports one state for each rule:

  • OK: the rule is attached with the repository's expectation, and no row breaks it.
  • VIOLATED: the rule is attached with the repository's expectation, and BROKEN_ROWS rows break it. The data is wrong.
  • CHANGED: the rule is attached, but its expectation was changed or removed by hand. The environment has drifted from the repository.
  • MISSING: the rule is not attached. This is drift too.
  • EXTRA: a data metric function the repository does not list is attached, with or without an expectation, or one of the repository's rules carries an expectation the repository does not list. This is drift too.
SQL: dq_rules_check.sql
-- Check one environment against the rules in dq_rules.sql. Run it after USE DATABASE / USE SCHEMA, like
-- dq_rules.sql. One row per rule the repository lists, and one per data metric function or expectation attached
-- that the repository does not list:
--   OK        the rule is attached with the repository's expectation, and no row breaks it
--   VIOLATED  the rule is attached with the repository's expectation, and BROKEN_ROWS rows break it
--   CHANGED   the rule is attached, but its expectation was changed or removed by hand (drift)
--   MISSING   the rule is not attached (drift)
--   EXTRA     a data metric function or expectation is attached that the repository does not list (drift)
-- Keep the repository list below in step with the rules and expectations in dq_rules.sql.

-- This statement evaluates the expectations once into a session-only table, so the query below reads
-- the same answer more than once. EXPECTATION_VIOLATED comes back as the text 'TRUE' or 'FALSE'.
CREATE OR REPLACE TEMPORARY TABLE EVALUATED_NOW AS
  SELECT EXPECTATION_ID, VALUE, EXPECTATION_VIOLATED
  FROM TABLE(SYSTEM$EVALUATE_DATA_QUALITY_EXPECTATIONS(REF_ENTITY_NAME => 'ORDERS'));

WITH repository(rule, metric, expression) AS (
  -- expectation name, the rule's data metric function, and the expectation exactly as dq_rules.sql writes it
  SELECT column1, column2, column3 FROM VALUES
    ('PRICE_POSITIVE',  'RULE_PRICE_POSITIVE',  'VALUE = 0'),
    ('STATUS_VALID',    'RULE_STATUS_VALID',    'VALUE = 0'),
    ('CUSTOMER_EXISTS', 'RULE_CUSTOMER_EXISTS', 'VALUE = 0')),
attached AS (
  -- every data metric function attached to the table, with or without an expectation
  SELECT REF_ID, METRIC_DATABASE_NAME, METRIC_SCHEMA_NAME, METRIC_NAME
  FROM TABLE(INFORMATION_SCHEMA.DATA_METRIC_FUNCTION_REFERENCES(
    REF_ENTITY_NAME => 'ORDERS', REF_ENTITY_DOMAIN => 'TABLE'))),
expectations AS (
  -- every expectation on those functions, with its expression
  SELECT REF_ID, EXPECTATION_ID, EXPECTATION_NAME, EXPECTATION_EXPRESSION
  FROM TABLE(INFORMATION_SCHEMA.DATA_METRIC_FUNCTION_EXPECTATIONS(
    REF_ENTITY_NAME => 'ORDERS', REF_ENTITY_DOMAIN => 'TABLE'))),
owned AS (
  -- the attached functions the repository owns: its rule names, created in the current schema
  SELECT r.rule, r.expression, a.REF_ID
  FROM repository r JOIN attached a ON a.METRIC_NAME = r.metric
   AND a.METRIC_DATABASE_NAME = CURRENT_DATABASE() AND a.METRIC_SCHEMA_NAME = CURRENT_SCHEMA())
SELECT r.rule AS RULE,
       CASE WHEN o.REF_ID IS NULL THEN 'MISSING'
            WHEN e.EXPECTATION_ID IS NULL
              OR REPLACE(UPPER(e.EXPECTATION_EXPRESSION), ' ', '') <> REPLACE(UPPER(r.expression), ' ', '')
              THEN 'CHANGED'
            WHEN v.EXPECTATION_VIOLATED = 'TRUE' THEN 'VIOLATED' ELSE 'OK' END AS STATE,
       v.VALUE AS BROKEN_ROWS
FROM repository r
LEFT JOIN owned o ON o.rule = r.rule
LEFT JOIN expectations e ON e.REF_ID = o.REF_ID AND e.EXPECTATION_NAME = r.rule
LEFT JOIN EVALUATED_NOW v ON v.EXPECTATION_ID = e.EXPECTATION_ID
UNION ALL
-- a function the repository does not own: named by its expectation, or by the function if it has none
SELECT COALESCE(e.EXPECTATION_NAME, a.METRIC_DATABASE_NAME || '.' || a.METRIC_SCHEMA_NAME || '.' || a.METRIC_NAME),
       'EXTRA', v.VALUE
FROM attached a
LEFT JOIN expectations e ON e.REF_ID = a.REF_ID
LEFT JOIN EVALUATED_NOW v ON v.EXPECTATION_ID = e.EXPECTATION_ID
WHERE a.REF_ID NOT IN (SELECT REF_ID FROM owned)
UNION ALL
-- an expectation added by hand to a rule the repository owns
SELECT e.EXPECTATION_NAME, 'EXTRA', v.VALUE
FROM owned o
JOIN expectations e ON e.REF_ID = o.REF_ID AND e.EXPECTATION_NAME <> o.rule
LEFT JOIN EVALUATED_NOW v ON v.EXPECTATION_ID = e.EXPECTATION_ID
ORDER BY RULE;

The check reads three Snowflake functions. DATA_METRIC_FUNCTION_REFERENCES lists every data metric function attached to the table, whether or not it has an expectation (Snowflake docs (read 2026-11-05)). DATA_METRIC_FUNCTION_EXPECTATIONS lists each expectation with its expression (Snowflake docs (read 2026-11-05)). SYSTEM$EVALUATE_DATA_QUALITY_EXPECTATIONS evaluates the expectations and returns the value of each expectation (Snowflake docs (read 2026-11-05)). The check runs that function once, into a session-only table. A rule belongs to the repository only if its function has a name from the repository list and sits in the current schema. The check compares each expectation's expression with the repository's, ignoring spaces and letter case. The repository list is typed into the check file, so keep it in step with dq_rules.sql.

Run 1. Three planted problems

After deploying the file to all three environments, we planted three problems, one in each. The check must catch each problem, and each problem trips a different state: the bad order trips VIOLATED, the hand-added rule trips EXTRA, and the hand-detached rule trips MISSING.

SQL: the three planted problems
-- planted problem 1: a bad order in TEST, with a price below zero
USE SCHEMA DATA_QUALITY_RULES_AS_CODE_SNOWFLAKE_TEST;
INSERT INTO ORDERS SELECT 900000001, MIN(C_CUSTKEY), 'F', -5.00 FROM CUSTOMER;

-- planted problem 2: someone attaches a rule by hand in DEV that is not in the repository, with no expectation
USE SCHEMA DATA_QUALITY_RULES_AS_CODE_SNOWFLAKE_DEV;
ALTER TABLE ORDERS ADD DATA METRIC FUNCTION SNOWFLAKE.CORE.NULL_COUNT ON (O_CUSTKEY);

-- planted problem 3: someone detaches a rule by hand in PROD
USE SCHEMA DATA_QUALITY_RULES_AS_CODE_SNOWFLAKE_PROD;
ALTER TABLE ORDERS DROP DATA METRIC FUNCTION RULE_STATUS_VALID ON (O_ORDERSTATUS);

Then we ran dq_rules_check.sql in each environment. In DEV, the check caught the rule nobody committed. That rule has no expectation, so the check names it by its function:

Output from our run: DEV, a rule added by hand
RULE                      | STATE | BROKEN_ROWS
--------------------------+-------+------------
CUSTOMER_EXISTS           | OK    | 0
PRICE_POSITIVE            | OK    | 0
SNOWFLAKE.CORE.NULL_COUNT | EXTRA | NULL
STATUS_VALID              | OK    | 0

In TEST, the check caught the bad order, with one broken row:

Output from our run: TEST, a bad order
RULE            | STATE    | BROKEN_ROWS
----------------+----------+------------
CUSTOMER_EXISTS | OK       | 0
PRICE_POSITIVE  | VIOLATED | 1
STATUS_VALID    | OK       | 0

In PROD, the check caught the rule that had been switched off:

Output from our run: PROD, a rule detached by hand
RULE            | STATE   | BROKEN_ROWS
----------------+---------+------------
CUSTOMER_EXISTS | OK      | 0
PRICE_POSITIVE  | OK      | 0
STATUS_VALID    | MISSING | NULL

Run 2. Fix each one and check again

We fixed each problem by hand. In DEV we dropped the rule that nobody committed. In TEST and PROD we ran dq_rules.sql again, and in TEST we deleted the bad order. Running dq_rules.sql again in PROD put the missing rule back. dq_rules.sql ran without an error in TEST, where all three rules were still attached, and in PROD, where one rule was missing, so the file can be run on top of an environment that already has its rules. dq_rules.sql does not remove rules it does not own, which is why the hand-added rule in DEV needed a separate drop.

SQL: the fixes
-- remove the hand-added rule from DEV
USE SCHEMA DATA_QUALITY_RULES_AS_CODE_SNOWFLAKE_DEV;
ALTER TABLE ORDERS DROP DATA METRIC FUNCTION SNOWFLAKE.CORE.NULL_COUNT ON (O_CUSTKEY);

-- the repository's file is run again in TEST and PROD (USE SCHEMA first, then dq_rules.sql)
-- the bad order is deleted from TEST
USE SCHEMA DATA_QUALITY_RULES_AS_CODE_SNOWFLAKE_TEST;
DELETE FROM ORDERS WHERE O_ORDERKEY >= 900000001;

Then we ran dq_rules_check.sql in DEV, TEST and PROD again. All three printed the same table:

Output from our run: DEV
RULE            | STATE | BROKEN_ROWS
----------------+-------+------------
CUSTOMER_EXISTS | OK    | 0
PRICE_POSITIVE  | OK    | 0
STATUS_VALID    | OK    | 0
Output from our run: TEST
RULE            | STATE | BROKEN_ROWS
----------------+-------+------------
CUSTOMER_EXISTS | OK    | 0
PRICE_POSITIVE  | OK    | 0
STATUS_VALID    | OK    | 0
Output from our run: PROD
RULE            | STATE | BROKEN_ROWS
----------------+-------+------------
CUSTOMER_EXISTS | OK    | 0
PRICE_POSITIVE  | OK    | 0
STATUS_VALID    | OK    | 0

Run 3. An extra check: expectations changed by hand

This check is separate from the three planted problems in Run 1. After Run 2, with every environment passing, we changed expectations by hand on rules that stayed attached. In TEST we loosened the price rule's expectation to VALUE < 1000 and added a second expectation to the customer rule. In PROD we removed the status rule's expectation. Snowflake documents the MODIFY EXPECTATION, ADD EXPECTATION and DROP EXPECTATION statements (Snowflake docs (read 2026-11-05)).

SQL: expectations changed by hand
-- extra check 1: someone loosens the price rule's expectation by hand in TEST
USE SCHEMA DATA_QUALITY_RULES_AS_CODE_SNOWFLAKE_TEST;
ALTER TABLE ORDERS MODIFY DATA METRIC FUNCTION RULE_PRICE_POSITIVE ON (O_TOTALPRICE)
  MODIFY EXPECTATION price_positive (VALUE < 1000);
-- extra check 2: someone adds a second expectation by hand to the customer rule in TEST
ALTER TABLE ORDERS MODIFY DATA METRIC FUNCTION RULE_CUSTOMER_EXISTS ON (O_CUSTKEY, TABLE (CUSTOMER(C_CUSTKEY)))
  ADD EXPECTATION hand_added_expectation (VALUE < 5);

-- extra check 3: someone removes the status rule's expectation by hand in PROD, and leaves the rule attached
USE SCHEMA DATA_QUALITY_RULES_AS_CODE_SNOWFLAKE_PROD;
ALTER TABLE ORDERS MODIFY DATA METRIC FUNCTION RULE_STATUS_VALID ON (O_ORDERSTATUS)
  DROP EXPECTATION status_valid;

TEST reported the loosened expectation as CHANGED and the added expectation as EXTRA:

Output from our run: TEST, two expectations changed by hand
RULE                   | STATE   | BROKEN_ROWS
-----------------------+---------+------------
CUSTOMER_EXISTS        | OK      | 0
HAND_ADDED_EXPECTATION | EXTRA   | 0
PRICE_POSITIVE         | CHANGED | 0
STATUS_VALID           | OK      | 0

PROD reported the status rule as CHANGED. The rule is still attached, so the check does not call it MISSING:

Output from our run: PROD, an expectation removed by hand
RULE            | STATE   | BROKEN_ROWS
----------------+---------+------------
CUSTOMER_EXISTS | OK      | 0
PRICE_POSITIVE  | OK      | 0
STATUS_VALID    | CHANGED | NULL

Then we ran dq_rules.sql again in TEST and PROD. The file detaches each of its rules and attaches each rule again with the repository's expectation. That put back the price and status expectations, and the detach removed the hand-added expectation. The check then printed the same table in both:

Output from our run: TEST, after dq_rules.sql ran again
RULE            | STATE | BROKEN_ROWS
----------------+-------+------------
CUSTOMER_EXISTS | OK    | 0
PRICE_POSITIVE  | OK    | 0
STATUS_VALID    | OK    | 0
Output from our run: PROD, after dq_rules.sql ran again
RULE            | STATE | BROKEN_ROWS
----------------+-------+------------
CUSTOMER_EXISTS | OK    | 0
PRICE_POSITIVE  | OK    | 0
STATUS_VALID    | OK    | 0

Tested on

Tested on

Platform
Snowflake
Edition
Enterprise Edition
Date
2026-11-05
Dataset
SNOWFLAKE_SAMPLE_DATA, TPCH_SF1 (ORDERS and CUSTOMER, limited to 1,000 rows each), copied into three schemas that stand in for DEV, TEST and PROD
Code
dq_rules.sql, dq_rules_check.sql, setup_test_environments.sql

Use it on your own data

To use this on your own data, open dq_rules.sql and replace the table names ORDERS and CUSTOMER (not the rule names that contain them) and the column names O_TOTALPRICE, O_ORDERSTATUS, O_CUSTKEY and C_CUSTKEY with your own, everywhere they appear in the file. To change what a rule counts, edit the SELECT inside its data metric function and keep the rule's name, and replace the allowed status values 'F', 'O' and 'P' in RULE_STATUS_VALID with your own. Then open dq_rules_check.sql and replace ORDERS with your table name. Run both files in each environment after USE DATABASE and USE SCHEMA, and skip setup_test_environments.sql, which only builds the stand-in environments for the test.

We tested these steps on a made-up set of tables with different names from the demo, different status values, a lowercase spelling of the table names in the edited files, a NULL key in the customer table, and one bad row for each rule. The check reported each of the three rules as VIOLATED with one broken row.

Download: dq_rules.sql · dq_rules_check.sql · setup_test_environments.sql · Get the full guide (PDF)

Get the full guide as a PDF

We'll email you a link to it. Please use your work email.

What it costs to run

Snowflake says the DMFs behind data quality checks use serverless compute that incurs costs, charged only when a scheduled DMF is computed on an object, and that calling a DMF in a SELECT is not billed (Snowflake docs (read 2026-11-05)). The file sets a 60-minute schedule, so a scheduled run does cost compute. Our checks read the expectations on demand and we did not measure the cost of the schedule. Check your own account's usage before you attach rules to large tables.

When this is not enough

  • dq_rules.sql only manages its own rules. The file detaches and re-attaches the three rules it lists. A rule added by hand stays in place, and the check reports it as EXTRA. A person removes it.
  • dq_rules_check.sql reports; it does not stop a release. The file returns rows. We did not wire it to fail a pipeline or to send an alert, so a pipeline step has to read the STATE column and stop on anything that is not OK.
  • The expected list is typed twice. The rule names and expectations are in dq_rules.sql and again in dq_rules_check.sql. By the check's logic, a rule added to dq_rules.sql only is reported as EXTRA, a rule added to dq_rules_check.sql only is reported as MISSING, and an expectation changed in one file only is reported as CHANGED. We did not run these cases.
  • One table, one column per rule. Each rule checks one column of ORDERS, and rule 3 checks its column, O_CUSTKEY, against the customer table. A rule that compares several columns in the same row, or needs earlier loads, may need a different design.
  • Our environments are schemas. Your DEV, TEST and PROD may be separate databases or accounts. We did not test separate databases or accounts, the Snowflake CLI, or a GitHub-connected pipeline.
  • Passing is not the same as right. A rule counts the rows that break the rule. The count cannot say whether the rule itself is the right rule. Someone who owns the data has to approve each rule.

Run your data quality rules natively in Snowflake or Databricks

Data Meaning runs your approved data quality rules natively in Snowflake or Databricks. See what Native Data Quality covers and how we work.

See Native Data Quality