### Summary comparison example Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_queries.md Example of using `compare_queries` with default `summarize=true`. It defines two queries and calls the macro with a primary key. ```sql {% set old_query %} select id as order_id, amount, customer_id from old_database.old_schema.fct_orders {% endset %} {% set new_query %} select order_id, amount, customer_id from {{ ref('fct_orders') }} {% endset %} {{ audit_helper.compare_queries( a_query = old_query, b_query = new_query, primary_key = "order_id" ) }} ``` -------------------------------- ### Detail mode with row limit example Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_queries.md Example of using `compare_queries` with `summarize=false` and a `limit` of 100. Returns up to 100 rows present in exactly one side, ordered by the primary key, with `in_a`/`in_b` flags. ```sql {{ audit_helper.compare_queries( a_query = old_query, b_query = new_query, primary_key = "order_id", summarize = false, limit = 100 ) }} ``` -------------------------------- ### Summary view of discrepancies per column Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_all_columns.md Example showing how to compare a baseline relation (obtained via adapter.get_relation) with a ref('fct_orders') candidate. Uses primary_key = "order_id", excludes the "loaded_at" column, and sets summarize = true to get a summary view of discrepancies per column. ```sql {% set old_relation = adapter.get_relation( database = "old_database", schema = "old_schema", identifier = "fct_orders" ) %} {{ audit_helper.compare_all_columns( a_relation = old_relation, b_relation = ref('fct_orders'), primary_key = "order_id", exclude_columns = ["loaded_at"], summarize = true ) }} ``` -------------------------------- ### compare_queries Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_queries.md Documentation for the legacy `compare_queries` macro in dbt-audit-helper, including its signature, parameters, return value, and examples. ```APIDOC ## compare_queries ### Description Compares the results of two SQL queries at the row level, identifying rows present in one query but not the other. It can return either a summary of the differences or the detailed rows that differ. ### Method Macro ### Endpoint `audit_helper.compare_queries(a_query, b_query, primary_key=None, summarize=true, limit=None)` ### Parameters - **a_query** (string) - Required - Baseline query; used as CTE `a`. - **b_query** (string) - Required - Candidate query; used as CTE `b`. - **primary_key** (string or None) - Optional - Used only for ordering in detail mode: `order by {{ primary_key ~ ", " if primary_key is not none }} in_a desc, in_b desc`. - **summarize** (boolean) - Optional - If `true` (default), returns grouped counts per `(in_a, in_b)` combination. If `false`, returns every non-identical row. - **limit** (number or None) - Optional - Row cap applied only when `limit and not summarize`: `limit {{ limit }}`. ### Request Example ```sql {% set old_query %} select id as order_id, amount, customer_id from old_database.old_schema.fct_orders {% endset %} {% set new_query %} select order_id, amount, customer_id from {{ ref('fct_orders') }} {% endset %} {{ audit_helper.compare_queries( a_query = old_query, b_query = new_query, primary_key = "order_id" ) }} ``` ### Response #### Success Response - **summarize=true**: Returns `summary_stats` grouped by `in_a, in_b` with columns `in_a`, `in_b`, `count`, `percent_of_total` (rounded to 2 decimal places), ordered by `in_a desc, in_b desc`. - **summarize=false**: Returns every source column plus `in_a` and `in_b` flags, filtered to rows where `not (in_a and in_b)`, ordered by the optional primary key then `in_a desc, in_b desc`, optionally limited. #### Response Example ```sql -- Example output for summarize=true in_a | in_b | count | percent_of_total -----+------+-------+----------------- true | false| 10 | 50.0 false| true | 10 | 50.0 ``` ### Errors No errors are raised directly. Set operations require the two queries to expose matching column names and types; mismatches surface as adapter errors when dbt executes the SQL. ``` -------------------------------- ### Verify refactor with quick_are_queries_identical Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/quick_are_queries_identical.md Example usage for Snowflake/BigQuery to verify a refactor introduced no changes. Sets two queries and calls the macro with explicit columns. ```sql {% set old_query %} select * from old_database.old_schema.dim_product {% endset %} {% set new_query %} select * from {{ ref('dim_product') }} {% endset %} {{ audit_helper.quick_are_queries_identical( query_a = old_query, query_b = new_query, columns = ['order_id', 'amount', 'customer_id'] ) }} ``` -------------------------------- ### Example: Auto-derive the column set Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_which_relation_columns_differ.md Shows how to call the macro with columns = None to auto-derive the intersecting columns. Uses adapter.get_relation for the baseline and ref for the candidate. ```sql {% set old_relation = adapter.get_relation( database = "old_database", schema = "old_schema", identifier = "fct_orders" ) %} {{ audit_helper.compare_which_relation_columns_differ( a_relation = old_relation, b_relation = ref('fct_orders'), primary_key_columns = ['order_id'], columns = None ) }} ``` -------------------------------- ### compare_relations (legacy) Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_relations.md Documentation for the legacy compare_relations macro in dbt-audit-helper, including signature, parameters, return value, and examples. ```APIDOC ## compare_relations (legacy) ### Description Compares two relations (tables/views) by projecting the same column list (from `a_relation` minus `exclude_columns`) and delegating to `compare_queries`. It is marked legacy; consider `compare_and_classify_relation_rows` instead. ### Method Macro (Jinja) ### Signature ```jinja {% macro compare_relations(a_relation, b_relation, exclude_columns=[], primary_key=None, summarize=true, limit=None) %} ``` ### Parameters - **a_relation** (Relation) - Required - Baseline relation. - **b_relation** (Relation) - Required - Candidate relation. - **exclude_columns** (list of strings) - Optional, default `[]` - Columns to drop from the projection. - **primary_key** (string or None) - Optional, default `None` - Ordering key in detail mode; forwarded to `compare_queries`. - **summarize** (boolean) - Optional, default `true` - Forwarded to `compare_queries`. - **limit** (number or None) - Optional, default `None` - Forwarded to `compare_queries` (effective in detail mode only). ### Return Value The compiled output of `compare_queries` applied to `select from ` for each input. The column list is built from the intersection of `a_relation`'s columns minus `exclude_columns`, with each name wrapped in `adapter.quote()`. Both relations must have the same column names (not necessarily the same order); columns present only in `b_relation` are silently ignored. Output record shape: see `compare_queries` types. ### Throws None raised directly. Inherits `compare_queries` behavior; a column present only in `b_relation` is dropped rather than erroring. ### Example: Basic comparison excluding a volatile column ```sql {% set old_relation = adapter.get_relation( database = "old_database", schema = "old_schema", identifier = "fct_orders" ) %} {{ audit_helper.compare_relations( a_relation = old_relation, b_relation = ref('fct_orders'), exclude_columns = ["loaded_at"], primary_key = "order_id" ) }} ``` ### Example: Detail mode with a limit ```sql {{ audit_helper.compare_relations( a_relation = old_relation, b_relation = ref('fct_orders'), exclude_columns = ["loaded_at", "updated_at"], primary_key = "order_id", summarize = false, limit = 50 ) }} ``` ``` -------------------------------- ### Macro signature and default implementation Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_queries.md The exact Jinja macro signature and the start of the default implementation. The macro dispatches to the adapter-specific implementation. ```jinja {% macro compare_queries(a_query, b_query, primary_key=None, summarize=true, limit=None) -%} {{ return(adapter.dispatch('compare_queries', 'audit_helper')(a_query, b_query, primary_key, summarize, limit)) }} {%- endmacro %} {% macro default__compare_queries(a_query, b_query, primary_key=None, summarize=true, limit=None) %} ``` -------------------------------- ### Quick gate before expensive comparison Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_row_counts.md Example using compare_row_counts as a gate before an expensive comparison. It runs the query, checks if row counts differ, and logs a message or proceeds to compare_and_classify_query_results. ```sql {% set counts_query = audit_helper.compare_row_counts( a_relation = ref('fct_orders'), b_relation = api.Relation.create( database = 'dbt_db', schema = 'analytics_prod', identifier = 'fct_orders' ) ) %} {% set counts = run_query(counts_query) %} {% if execute and counts.rows[0][1] != counts.rows[1][1] %} {% do log('Row counts differ — skipping full comparison', info=true) %} {% else %} {{ audit_helper.compare_and_classify_query_results(...) }} {% endif %} ``` -------------------------------- ### compare_row_counts(a_relation, b_relation) Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_row_counts.md Documentation for the compare_row_counts macro, including its signature, parameters, return value, and usage examples. ```APIDOC ## compare_row_counts(a_relation, b_relation) ### Description Compares the row counts of two relations by generating a SQL statement that counts the rows in each relation and returns the results as two rows. This is the simplest audit check, providing a count-only sanity check without row-level comparison. ### Method Macro (dbt Jinja macro) ### Endpoint `audit_helper.compare_row_counts(a_relation, b_relation)` ### Parameters - **a_relation** (Relation) - Required - The first relation to count. - **b_relation** (Relation) - Required - The second relation to count. ### Return Value A two-row `union all` statement with columns `relation_name` (the rendered relation string) and `total_records` (count of rows). The first row corresponds to `a_relation`, the second to `b_relation`. ### Example ```sql {% set old_relation = adapter.get_relation( database = "old_database", schema = "old_schema", identifier = "fct_orders" ) %} {{ audit_helper.compare_row_counts( a_relation = old_relation, b_relation = ref('fct_orders') ) }} ``` ``` -------------------------------- ### compare_which_query_columns_differ macro signature and default implementation Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_which_query_columns_differ.md Macro signature and default implementation. The default implementation ensures all primary keys are in the column set and, if event_time is provided, attempts to get comparison bounds, but event_time is broken due to an arity mismatch in _get_comparison_bounds. ```jinja {% macro compare_which_query_columns_differ(a_query, b_query, primary_key_columns=[], columns=[], event_time=None) %} {{ return(adapter.dispatch('compare_which_query_columns_differ', 'audit_helper')(a_query, b_query, primary_key_columns, columns, event_time)) }} {% endmacro %} {% macro default__compare_which_query_columns_differ(a_query, b_query, primary_key_columns, columns, event_time) %} {% set columns = audit_helper._ensure_all_pks_are_in_column_set(primary_key_columns, columns) %} {% if event_time %} {% set event_time_props = audit_helper._get_comparison_bounds(event_time) %} {% endif %} ``` -------------------------------- ### Explicit columns and adapter guard Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/quick_are_relations_identical.md Example that explicitly passes columns and guards the call with an execute check and adapter type check for BigQuery or Snowflake, since the macro is only implemented on those adapters. ```jinja {% if execute and target.type in ['bigquery', 'snowflake'] %} {{ audit_helper.quick_are_relations_identical( a_relation = old_relation, b_relation = ref('fct_orders'), columns = ['order_id', 'amount', 'customer_id'] ) }} {% endif %} ``` -------------------------------- ### Compare row counts of two relations Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_row_counts.md Example usage comparing row counts of two relations: one obtained via adapter.get_relation and another via ref(). The macro returns a union all query with counts. ```sql {% set old_relation = adapter.get_relation( database = "old_database", schema = "old_schema", identifier = "fct_orders" ) %} {{ audit_helper.compare_row_counts( a_relation = old_relation, b_relation = ref('fct_orders') ) }} ``` -------------------------------- ### Example: Explicit column list excluding volatile columns Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_which_relation_columns_differ.md Shows how to pass an explicit column list, here using dbt_utils.get_filtered_columns_in_relation to exclude the 'loaded_at' column. ```sql {% set columns = dbt_utils.get_filtered_columns_in_relation( old_relation, except=['loaded_at'] ) %} {{ audit_helper.compare_which_relation_columns_differ( a_relation = old_relation, b_relation = ref('fct_orders'), primary_key_columns = ['order_id'], columns = columns ) }} ``` -------------------------------- ### Find which columns contain value-level differences Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_which_query_columns_differ.md Example showing how to find which columns contain value-level differences between two queries. It defines old_query and new_query, then calls compare_which_query_columns_differ with primary_key_columns and columns. ```sql {% set old_query %} select order_id, customer_id, order_date, status, amount from old_database.old_schema.fct_orders {% endset %} {% set new_query %} select order_id, customer_id, order_date, status, amount from {{ ref('fct_orders') }} {% endset %} {{ audit_helper.compare_which_query_columns_differ( a_query = old_query, b_query = new_query, primary_key_columns = ['order_id'], columns = ['order_id', 'customer_id', 'order_date', 'status', 'amount'] ) }} ``` -------------------------------- ### Compare two queries with compare_and_classify_query_results Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/README.md Use this macro to compare two queries row-by-row and get summary stats of added, removed, identical, and modified records. The macro requires primary_key_columns and columns arguments; sample_limit defaults to 20. The output includes dbt_audit_row_status and dbt_audit_num_rows_in_status, where the latter counts each primary key only once. ```sql {% set old_query %} select id as order_id, amount, customer_id from old_database.old_schema.fct_orders {% endset %} {% set new_query %} select order_id, amount, customer_id from {{ ref('fct_orders') }} {% endset %} {{ audit_helper.compare_and_classify_query_results( old_query, new_query, primary_key_columns=['order_id'], columns=['order_id', 'amount', 'customer_id'] ) }} ``` -------------------------------- ### compare_all_columns usage Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/README.md Use this macro to compare all column values between two relations and get a summary of matches, differences, nulls, and missing values. Set the primary_key to a unique key that is never null in both tables; otherwise the join won't work as expected. The summarize argument defaults to true; set it to false for row-by-row validation. ```sql {% set old_relation = adapter.get_relation( database = "old_database", schema = "old_schema", identifier = "fct_orders" ) -%} {% set dbt_relation = ref('fct_orders') %} {{ audit_helper.compare_all_columns( a_relation = old_relation, b_relation = dbt_relation, primary_key = "order_id" ) }} ``` -------------------------------- ### compare_and_classify_relation_rows Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_and_classify_relation_rows.md Documentation for the compare_and_classify_relation_rows macro, including its signature, parameters, return value, and usage examples. ```APIDOC ## compare_and_classify_relation_rows ### Description Compares two dbt relations row-by-row and classifies each row by its audit status. This macro is a wrapper around `compare_and_classify_query_results` that accepts relations instead of SQL queries. ### Signature ```jinja {% macro compare_and_classify_relation_rows(a_relation, b_relation, primary_key_columns=[], columns=None, event_time=None, sample_limit=20) %} ``` ### Parameters - **a_relation** (Relation) - Required - Baseline relation; rendered as `"select * from " ~ a_relation`. Can be a `ref()`, `source()`, or `adapter.get_relation()` result. - **b_relation** (Relation) - Required - Candidate relation. - **primary_key_columns** (list of strings) - Required (semantically) - Default: `[]` - PK column(s) used for the join. See `compare_and_classify_query_results` for PK auto-prepending behavior. - **columns** (list of strings) - Optional - Default: `None` - Columns to compare. When falsy, automatically set to the intersection of both relations' columns via `_get_intersecting_columns_from_relations`; pass an explicit list (e.g. from `dbt_utils.get_filtered_columns_in_relation(..., except=[...])`) to exclude columns. - **event_time** (string) - Optional - Default: `None` - Overlap-window time column; forwarded to `compare_and_classify_query_results`. - **sample_limit** (number) - Optional - Default: `20` - Samples per `dbt_audit_row_status`; forwarded unchanged. ### Return Value Returns exactly the SQL produced by `compare_and_classify_query_results`, i.e. a classified row-by-row comparison. Both relations must have the same column **names**, but not necessarily the same order. When `columns` is auto-derived, only the intersecting column names are compared. ### Throws None raised directly. Inherits the failure modes of `compare_and_classify_query_results` (including the event-time introspection query) plus a dbt error if either relation does not exist. ### Examples #### Basic comparison of two relations ```sql {% set old_relation = adapter.get_relation( database = "old_database", schema = "old_schema", identifier = "fct_orders" ) %} {{ audit_helper.compare_and_classify_relation_rows( a_relation = old_relation, b_relation = ref('fct_orders'), primary_key_columns = ["order_id"], columns = None ) }} ``` #### Excluding columns via `dbt_utils.get_filtered_columns_in_relation` ```sql {% set old_relation = adapter.get_relation( database = "old_database", schema = "old_schema", identifier = "fct_orders" ) %} {% set columns = dbt_utils.get_filtered_columns_in_relation( old_relation, except=["loaded_at", "updated_at"] ) %} {{ audit_helper.compare_and_classify_relation_rows( a_relation = old_relation, b_relation = ref('fct_orders'), primary_key_columns = ["order_id"], columns = columns, -- explicit list: volatile columns excluded sample_limit = 5 ) }} ``` ``` -------------------------------- ### compare_column_values Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_column_values.md Documentation for the compare_column_values macro in dbt-audit-helper, including signature, parameters, return value, and usage examples. ```APIDOC ## compare_column_values ### Description Compares the values of a specified column between two queries (baseline and candidate) and returns a summary of match statuses, counts, and percentages. ### Signature ```jinja {% macro compare_column_values(a_query, b_query, primary_key, column_to_compare, emojis=True, a_relation_name='a', b_relation_name='b') -%} {{ return(adapter.dispatch('compare_column_values', 'audit_helper')(a_query, b_query, primary_key, column_to_compare, emojis, a_relation_name, b_relation_name)) }} {%- endmacro %} ``` ### Parameters | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | `a_query` | string (SQL select) | yes | — | Baseline query; placed in a CTE named `a_query` | | `b_query` | string (SQL select) | yes | — | Candidate query; placed in a CTE named `b_query` | | `primary_key` | string (column name) | yes | — | Join key used in `full outer join b_query on a_query. = b_query.`. Must be unique and never null in both inputs | | `column_to_compare` | string (column name) | yes | — | The column whose values are compared | | `emojis` | boolean | no | `True` | Prepend `✅: `, `🤷: `, `❌: ` to `match_status` values for visual scanning; `false` drops them | | `a_relation_name` | string | no | `'a'` | Label interpolated into `missing from {a_relation_name}` / `value is null in {a_relation_name} only` | | `b_relation_name` | string | no | `'b'` | Same, for `b` | ### Return Value A summary SQL statement with one row per `match_status`: `column_name` (the literal `column_to_compare`), `match_status`, `count_records` (`count(*)`), `percent_of_total` (`round(100.0 * count_records / sum(count_records) over (), 2)`); ordered by the internal `match_order` (0 = perfect match, 1 = both null, 2 = missing from a, 3 = missing from b, 4 = null in a only, 5 = null in b only, 6 = values do not match). ### Throws None raised directly. A PK that is not unique/null in either input silently corrupts the join semantics ("the join won't work as expected" per README). ### Example: Basic usage ```sql {% set old_query %} select * from old_database.old_schema.dim_product where is_latest {% endset %} {% set new_query %} select * from {{ ref('dim_product') }} {% endset %} {{ audit_helper.compare_column_values( a_query = old_query, b_query = new_query, primary_key = "product_id", column_to_compare = "status" ) }} ``` ### Example: Plain labels, custom relation names, and logging the results ```sql {% set audit_query = audit_helper.compare_column_values( a_query = old_query, b_query = new_query, primary_key = "product_id", column_to_compare = "status", emojis = false, a_relation_name = "prod", b_relation_name = "ci" ) %} -- print the query output to the dbt logs instead of previewing it {% set audit_results = run_query(audit_query) %} {% if execute %} {% do audit_results.print_table() %} {% endif %} ``` `print_table()` is unavailable in dbt Cloud; iterate `audit_results.column_names` / `audit_results.rows` inside `{% do log(...) %}` there instead (see README "Print Output To Logs" section). ``` -------------------------------- ### Raise compiler error for unsupported adapter in default__quick_are_queries_identical Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/errors.md Default implementation of the quick_are_queries_identical macro that raises a dbt Core compiler error when called on any adapter other than BigQuery or Snowflake. The error is only raised when execute is true, so it is not triggered during the initial parse phase. ```jinja {% macro default__quick_are_queries_identical(query_a, query_b, columns, event_time) %} {% if execute %} {# Need to only throw this error when the macro is actually trying to be used, not during intial parse phase #} {# if/when unit tests get support for `enabled` config, this check can be removed as they won't be supplied for parse anyway #} {% do exceptions.raise_compiler_error("quick_are_queries_identical() is not implemented for adapter '"~ target.type ~ "'" ) %} {% endif %} {% endmacro %} ``` -------------------------------- ### Signature and default implementation of compare_column_values_verbose Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_column_values_verbose.md The macro signature in Jinja, followed by the start of the default implementation that dispatches via adapter.dispatch. ```jinja {% macro compare_column_values_verbose(a_query, b_query, primary_key, column_to_compare) -%} {{ return(adapter.dispatch('compare_column_values_verbose', 'audit_helper')(a_query, b_query, primary_key, column_to_compare)) }} {%- endmacro %} {% macro default__compare_column_values_verbose(a_query, b_query, primary_key, column_to_compare) -%} ``` -------------------------------- ### Compare schema of old and new relation Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_relation_columns.md Shows how to call compare_relation_columns with an existing relation obtained via adapter.get_relation and a ref() to compare schemas. ```sql {% set old_relation = adapter.get_relation( database = "old_database", schema = "old_schema", identifier = "fct_orders" ) %} {{ audit_helper.compare_relation_columns( a_relation = old_relation, b_relation = ref('fct_orders') ) }} ``` -------------------------------- ### quick_are_relations_identical usage Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/README.md Use this macro to compare two relations for identical data. It wraps quick_are_queries_identical and accepts Relations instead of queries. Columns must have the same names but can be in any order; pass None to automatically find all intersecting columns. ```sql {% set old_relation = adapter.get_relation( database = "old_database", schema = "old_schema", identifier = "fct_orders" ) -%} {% set dbt_relation = ref('fct_orders') %} {{ audit_helper.quick_are_relations_identical( a_relation = old_relation, b_relation = dbt_relation, columns = None ) }} ``` -------------------------------- ### Time-bounded comparison with a non-finite sample Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_and_classify_query_results.md Compares two queries using the created_at column as the event_time to restrict the comparison to the overlapping time window. The sample_limit is set to None to disable sampling and report every classified row. ```sql {% set old_query %} select * from old_database.old_schema.fct_orders {% endset %} {% set new_query %} select * from {{ ref('fct_orders') }} {% endset %} {{ audit_helper.compare_and_classify_query_results( a_query=old_query, b_query=new_query, primary_key_columns=['order_id'], columns=['order_id', 'amount', 'customer_id', 'created_at'], event_time='created_at', -- only the overlapping time window is compared sample_limit=None -- no sampling: report every classified row ) }} ``` -------------------------------- ### Auto-derive columns for two relations Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/quick_are_relations_identical.md Example that auto-derives columns by passing columns = None. It retrieves a relation using adapter.get_relation and compares it with a ref('fct_orders') relation. ```sql {% set old_relation = adapter.get_relation( database = "old_database", schema = "old_schema", identifier = "fct_orders" ) %} {{ audit_helper.quick_are_relations_identical( a_relation = old_relation, b_relation = ref('fct_orders'), columns = None ) }} ``` -------------------------------- ### quick_are_queries_identical(query_a, query_b, columns=[], event_time=None) Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/quick_are_queries_identical.md Compares two SQL queries by hashing their rows and checking if the aggregate hashes are equal. Returns a single boolean value. Supported on BigQuery and Snowflake; other adapters raise a compiler error. ```APIDOC ## quick_are_queries_identical(query_a, query_b, columns=[], event_time=None) ### Description Compares two SQL queries by hashing each row and comparing the aggregate hashes. Returns a single boolean value indicating whether the queries are identical. Supported on BigQuery and Snowflake; other adapters raise a compiler error. ### Method Macro (dbt) ### Parameters - **query_a** (string SQL select) - Required - First query; joined columns projected onto it. - **query_b** (string SQL select) - Required - Second query. - **columns** (list of strings) - Required for meaningful results - Columns included in each row hash; joined with ", ". Default is `[]`. - **event_time** (string column name) - Optional - **Broken in this macro** - Do not use; keep default `None`. ### Return Value A single-row, single-column statement: `are_tables_identical` (boolean). ### Throws - **Compiler error** - `quick_are_queries_identical() is not implemented for adapter ''` - Raised when adapter is not BigQuery or Snowflake and `execute` is true. - **Jinja UndefinedError** - On `a_query`/`b_query` - Raised when `event_time` is truthy on BigQuery/Snowflake due to internal parameter naming mismatch. ### Example ```sql {% set old_query %} select * from old_database.old_schema.dim_product {% endset %} {% set new_query %} select * from {{ ref('dim_product') }} {% endset %} {{ audit_helper.quick_are_queries_identical( query_a = old_query, query_b = new_query, columns = ['order_id', 'amount', 'customer_id'] ) }} ``` ``` -------------------------------- ### Standalone per-row comparison of one column Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_column_values_verbose.md Example showing how to call compare_column_values_verbose with two queries, a primary key, and a column to compare, producing a row-level boolean comparison. ```sql {% set old_query %} select id, amount from old_database.old_schema.fct_orders {% endset %} {% set new_query %} select id, amount from {{ ref('fct_orders') }} {% endset %} {{ audit_helper.compare_column_values_verbose( a_query = old_query, b_query = new_query, primary_key = "id", column_to_compare = "amount" ) }} ``` -------------------------------- ### Drill into a single differing column with compare_column_values Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_which_query_columns_differ.md Example showing how to drill into a single differing column by using compare_column_values after identifying that 'amount' has a difference. It quantifies the damage for that specific column. ```sql -- 1. run compare_which_query_columns_differ, note that `amount` has_difference = True -- 2. quantify the damage with compare_column_values: {{ audit_helper.compare_column_values( a_query = old_query, b_query = new_query, primary_key = 'order_id', column_to_compare = 'amount' ) }} ``` -------------------------------- ### Feeding a verbose comparison into a custom test failure filter Source: https://github.com/dbt-labs/dbt-audit-helper/blob/main/_autodocs/api-reference/compare_column_values_verbose.md Example that wraps the macro call in a query with a WHERE clause to filter for conflicting values, suitable for a dbt test or analysis. ```sql {{ audit_helper.compare_column_values_verbose( a_query = "select * from prod.fct_orders", b_query = "select * from " ~ ref('fct_orders'), primary_key = "order_id", column_to_compare = "amount" ) }} where conflicting_values ```