Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5bb8480
feat: Make merge_columns optional in sql_query check
vb-dbrks Nov 24, 2025
43812c8
fmt & tests: sql check complexity and reuse dataset level check. Adde…
vb-dbrks Nov 24, 2025
24abf0d
improve: tighten sql_query validation + share test helper
vb-dbrks Nov 25, 2025
55383ea
fix: test assertion when totals do not match
vb-dbrks Nov 25, 2025
2f43afa
Support Custom Folder Installation for CLI Commands (#942)
ghanse Nov 24, 2025
1694a72
fix: updated test assertion failure scenario totals mismatch / datase…
vb-dbrks Nov 25, 2025
270f1ab
Merge branch 'main' into 938-feature-sql_query-should-have-merge-colu…
vb-dbrks Nov 30, 2025
25c0bce
Merge branch 'main' into 938-feature-sql_query-should-have-merge-colu…
mwojtyczka Dec 7, 2025
5f4976c
Apply suggestion from @mwojtyczka
mwojtyczka Dec 7, 2025
03a1b1b
Apply suggestion from @mwojtyczka
mwojtyczka Dec 7, 2025
49326a3
Apply suggestion from @mwojtyczka
mwojtyczka Dec 7, 2025
7d98e2a
Apply suggestion from @mwojtyczka
mwojtyczka Dec 7, 2025
623c2df
Apply suggestion from @mwojtyczka
mwojtyczka Dec 7, 2025
b2062d4
Apply suggestion from @mwojtyczka
mwojtyczka Dec 7, 2025
c935591
Merge branch 'main' into 938-feature-sql_query-should-have-merge-colu…
mwojtyczka Dec 7, 2025
b943d5d
fmt
mwojtyczka Dec 7, 2025
f707a23
Update src/databricks/labs/dqx/check_funcs.py
mwojtyczka Dec 7, 2025
24cdd3f
Update src/databricks/labs/dqx/check_funcs.py
mwojtyczka Dec 7, 2025
ded5fee
fmt
mwojtyczka Dec 7, 2025
0f18b32
Merge remote-tracking branch 'origin/938-feature-sql_query-should-hav…
mwojtyczka Dec 7, 2025
e50db33
Add pytest-benchmark performance baseline
mwojtyczka Dec 7, 2025
cddee6b
fixed tests
mwojtyczka Dec 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 66 additions & 3 deletions demos/dqx_demo_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -943,11 +943,15 @@ def not_ends_with(column: str, suffix: str) -> Column:
# COMMAND ----------

# MAGIC %md
# MAGIC #### Using `sql_query` check
# MAGIC #### Using `sql_query` check - Row-level validation
# MAGIC
# MAGIC The `sql_query` check supports two modes:
# MAGIC - **Row-level validation** (with `merge_columns`): Query results are joined back to mark specific rows
# MAGIC - **Dataset-level validation** (without `merge_columns`): Check result applies to all rows

# COMMAND ----------

# using DQX classes
# Row-level validation example: Check each sensor against its threshold
from databricks.labs.dqx.rule import DQDatasetRule
from databricks.labs.dqx.check_funcs import sql_query

Expand All @@ -973,7 +977,7 @@ def not_ends_with(column: str, suffix: str) -> Column:
check_func=sql_query,
check_func_kwargs={
"query": query,
"merge_columns": ["sensor_id"],
"merge_columns": ["sensor_id"], # Results joined back by sensor_id
"condition_column": "condition", # the check fails if this column evaluates to True
"msg": "one of the sensor reading is greater than limit",
"name": "sensor_reading_check",
Expand All @@ -990,6 +994,41 @@ def not_ends_with(column: str, suffix: str) -> Column:

# COMMAND ----------

# MAGIC %md
# MAGIC #### Using `sql_query` check - Dataset-level validation
# MAGIC
# MAGIC When `merge_columns` is not provided, the check applies to all rows (all pass or all fail together).
# MAGIC This is useful for dataset-level aggregate validations.

# COMMAND ----------

# Dataset-level validation example: Check total sensor count
dataset_query = """
SELECT COUNT(DISTINCT sensor_id) < 1 AS condition
FROM {{ sensor }}
"""

checks = [
DQDatasetRule(
criticality="warn",
check_func=sql_query,
check_func_kwargs={
"query": dataset_query,
# No merge_columns = dataset-level check (all rows get same result)
"condition_column": "condition",
"msg": "Dataset has no sensors",
"name": "dataset_has_sensors",
"input_placeholder": "sensor",
},
),
]

ref_dfs = {"sensor_specs": sensor_specs_df}
valid_and_quarantine_df = dq_engine.apply_checks(sensor_df, checks, ref_dfs=ref_dfs)
display(valid_and_quarantine_df)

# COMMAND ----------

# using YAML declarative approach
checks = yaml.safe_load(
"""
Expand Down Expand Up @@ -1028,6 +1067,30 @@ def not_ends_with(column: str, suffix: str) -> Column:

# COMMAND ----------

# YAML example for dataset-level validation (without merge_columns)
checks_dataset_level = yaml.safe_load(
"""
- criticality: warn
check:
function: sql_query
arguments:
# No merge_columns = dataset-level validation
condition_column: condition
msg: Dataset has no sensors
name: dataset_has_sensors
input_placeholder: sensor
query: |
SELECT COUNT(DISTINCT sensor_id) < 1 AS condition
FROM {{ sensor }}
"""
)

ref_dfs = {"sensor_specs": sensor_specs_df}
valid_and_quarantine_df = dq_engine.apply_checks_by_metadata(sensor_df, checks_dataset_level, ref_dfs=ref_dfs)
display(valid_and_quarantine_df)

# COMMAND ----------

# MAGIC %md
# MAGIC #### Defining custom python dataset-level check

Expand Down
2 changes: 2 additions & 0 deletions docs/dqx/docs/reference/benchmarks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ sidebar_position: 13
| test_benchmark_compare_datasets | 3.598445 | 3.556993 | 3.430710 | 3.793938 | 0.158157 | 0.280218 | 3.466942 | 3.747160 | 5 | 0 | 2 | 0.28 |
| test_benchmark_foreach_compare_datasets[n_rows_100000000_n_columns_5] | 25.879615 | 25.919933 | 25.536855 | 26.071184 | 0.217230 | 0.307223 | 25.748681 | 26.055904 | 5 | 0 | 1 | 0.04 |
| test_benchmark_foreach_foreign_key[n_rows_100000000_n_columns_5] | 24.264873 | 22.893218 | 20.587308 | 29.037093 | 4.062789 | 7.705522 | 20.652819 | 28.358341 | 5 | 0 | 1 | 0.04 |
| test_benchmark_foreach_has_no_outliers[n_rows_100000000_n_columns_5] | 22.524313 | 22.347593 | 22.104944 | 22.924248 | 0.374170 | 0.646915 | 22.271984 | 22.918899 | 5 | 0 | 3 | 0.04 |
| test_benchmark_foreach_has_valid_schema[n_rows_100000000_n_columns_5] | 1.068582 | 1.050490 | 0.979350 | 1.219259 | 0.092674 | 0.112164 | 1.003924 | 1.116088 | 5 | 0 | 1 | 0.94 |
| test_benchmark_foreach_is_aggr_equal[n_rows_100000000_n_columns_5] | 1.239298 | 1.213153 | 1.192442 | 1.341836 | 0.060654 | 0.068928 | 1.200719 | 1.269646 | 5 | 0 | 1 | 0.81 |
| test_benchmark_foreach_is_aggr_not_equal[n_rows_100000000_n_columns_5] | 1.264898 | 1.250273 | 1.218577 | 1.345211 | 0.051090 | 0.071957 | 1.225905 | 1.297862 | 5 | 0 | 1 | 0.79 |
Expand Down Expand Up @@ -54,6 +55,7 @@ sidebar_position: 13
| test_benchmark_foreach_sql_query[n_rows_100000000_n_columns_5] | 4.578799 | 4.602143 | 4.442396 | 4.644892 | 0.083901 | 0.113694 | 4.530776 | 4.644470 | 5 | 0 | 1 | 0.22 |
| test_benchmark_foreign_key | 31.784272 | 31.787610 | 31.414708 | 32.123221 | 0.269713 | 0.386951 | 31.597198 | 31.984149 | 5 | 0 | 2 | 0.03 |
| test_benchmark_has_dimension | 0.215338 | 0.213285 | 0.210530 | 0.223131 | 0.005056 | 0.007086 | 0.211819 | 0.218905 | 5 | 0 | 1 | 4.64 |
| test_benchmark_has_no_outliers | 0.234952 | 0.228169 | 0.224165 | 0.257274 | 0.013649 | 0.017354 | 0.225936 | 0.243290 | 5 | 0 | 1 | 4.26 |
| test_benchmark_has_valid_schema | 0.172078 | 0.172141 | 0.163793 | 0.181081 | 0.006715 | 0.009295 | 0.167010 | 0.176305 | 6 | 0 | 2 | 5.81 |
| test_benchmark_has_x_coordinate_between | 0.217192 | 0.213656 | 0.209310 | 0.236233 | 0.011150 | 0.012638 | 0.209410 | 0.222048 | 5 | 0 | 1 | 4.60 |
| test_benchmark_has_y_coordinate_between | 0.218497 | 0.219630 | 0.209352 | 0.234111 | 0.010103 | 0.013743 | 0.209584 | 0.223327 | 5 | 0 | 1 | 4.58 |
Expand Down
Loading
Loading