cancel
Showing results for 
Search instead for 
Did you mean: 
Data Governance
Join discussions on data governance practices, compliance, and security within the Databricks Community. Exchange strategies and insights to ensure data integrity and regulatory compliance.
cancel
Showing results for 
Search instead for 
Did you mean: 

Issue in DQX DQGeneration with AI - DQrules generated with sql_query function having syntax errors.

Dharmin
New Contributor

While using DQX to generate DQ rules on a table i have used the following prompt.

from databricks.labs.dqx.profiler.generator import DQGenerator
from databricks.labs.dqx.profiler.profiler import DQProfiler
from databricks.labs.dqx.config import InputConfig
from databricks.sdk import WorkspaceClient

ws = WorkspaceClient()
generator = DQGenerator(workspace_client=ws, spark=spark)
# Step 1: Profile the data to generate summary statistics
profiler = DQProfiler(workspace_client=ws, spark=spark)
# Generate rules with input data schema awareness
input_df = spark.read.table(f"{schema}.{tablename}")
summary_stats, profiles = profiler.profile(input_df)
user_input = """
Make sure tid and tdescr are one to one mapped
make sure l and ldesc are one to one mapped
make sure effective startdate and effective enddate are lesser than current date
Make sure the test cases are executable through dbx and should not throw any errors like table or view not found
"""
# Option A: With business context
checks = generator.generate_dq_rules_ai_assisted(
    user_input=user_input,
    summary_stats=summary_stats
)

print(checks)
 
For the above code i am getting some valid response but the response is not as directly usable.
 

{'criticality': 'error', 'check': {'function': 'sql_query', 'arguments': {'query': 'SELECT TID, COUNT(DISTINCT TIDDESCR) as desc_count FROM input_view GROUP BY TID HAVING COUNT(DISTINCT TIDDESCR) > 1', 'name': 'tid_to_description_one_to_one', 'msg': 'CTID must map to exactly one TIDDESCR'}}}
 
I tried to correct it as below.
 
- check:
    arguments:
      merge_columns:
      - TID
      - TIDDESCR
      msg: TID has multiple TIDDESCR values
      input_placeholder: input_view
      condition_column: desc_count
      name: tid_tiddescr_one_to_one
      query: with main_cte as (SELECT TID, TIDDESCR, COUNT(DISTINCT TIDDESCR) AS desc_count
        FROM {{ input_view }} WHERE TID IS NOT NULL GROUP BY TID, TIDDESCR
        HAVING COUNT(DISTINCT TIDDESCR) > 1)select *,case when desc_count > 1 then true else false end as condition from main_cte
    function: sql_query
  criticality: error
- check:
arguments:
merge_columns:
- l
- lDESC
input_placeholder: input_view
msg: l has multiple lDESC values
name: l_ldesc_one_to_one
condition_column: condition
query: with main_cte as (SElECT l, lDESC, COUNT(DISTINCT lDESC) AS desc_count
FROM {{ input_view }} WHERE l IS NOT NUll GROUP BY l, lDESC
HAVING COUNT(DISTINCT lDESC) > 1)select *,case when desc_count > 1 then true else false end as condition from main_cte
function: sql_query
criticality: error
Still  facing the following issue
{"ts": "2026-03-13 06:46:43.193", "level": "ERROR", "logger": "DataFrameQueryContextLogger", "msg": "[DATATYPE_MISMATCH.UNEXPECTED_INPUT_TYPE] Cannot resolve \"CASE WHEN Tid_Tiddescr_one_to_one_desc_count_de5f40594692464892443d2e0412aaef THEN TID has multiple TIDDESCR values ELSE CAST(NULL AS STRING) END\" due to data type mismatch: The first parameter requires the \"BOOLEAN\" type, however \"Tid_Tiddescr_one_to_one_desc_count_de5f40594692464892443d2e0412aaef\" has the type \"BIGINT\". SQLSTATE: 42K09;\n'Project [TID#1233, TIDDESCR#1234, l#1235, lDESC#1236,
 
Can some one guide me on what chould be the issue.
I need help on the following things
1.Is there any possibility to get better response from the LLM model. Any better prompt etc.?
2.Why is the sql_query function not working?
1 REPLY 1

SumeshKashyap
New Contributor III

Based on the error message shared, there are two issues in the corrected rule, plus one in the logic.

 

Why sql_query is failing:

 

- condition_column must be a BOOLEAN column. DQX treats it as "TRUE = this row fails the check" and wraps it in a CASE WHEN to build the error message. You pointed it at desc_count, which is a BIGINT, hence "The first parameter requires the BOOLEAN type, however ... has the type BIGINT". Return a boolean from the query and point condition_column at that.

 

- Your GROUP BY makes the check a no-op. Grouping by TID, TIDDESCR makes COUNT(DISTINCT TIDDESCR) always 1 per group, so nothing would ever be flagged even after the type fix. To test "one TID maps to one TIDDESCR", group by TID only, and set merge_columns to TID only. merge_columns is how DQX joins the query result back to the input rows, so it must match the grain of your GROUP BY.

 

- In the second rule, "SEIECT" and "NUIl" look like a capital I / lowercase l typed in place of L. Worth checking, because that will fail to parse too.

 

A working version of the first rule:

 

- criticality: error

  check:

    function: sql_query

    arguments:

      query: |

        SELECT TID, COUNT(DISTINCT TIDDESCR) > 1 AS condition

        FROM {{ input_view }}

        WHERE TID IS NOT NULL

        GROUP BY TID

      input_placeholder: input_view

      merge_columns:

        - TID

      condition_column: condition

      msg: TID has multiple TIDDESCR values

      name: tid_tiddescr_one_to_one

 

For a true one-to-one mapping, add the mirror check (GROUP BY TIDDESCR, COUNT(DISTINCT TID) > 1, merge_columns TIDDESCR), since the rule above only covers one direction. The I/IDESC rule follows the same pattern.

 

The date rule doesn't need sql_query at all. It's a row-level condition, so a sql_expression check is simpler and far less error-prone, e.g. expression: effective_startdate < current_date() AND effective_enddate < current_date(). In sql_expression the expression is what must be TRUE for a valid row, which is the opposite of sql_query's condition_column.

 

Getting better output from the LLM:

 

- Put the contract in user_input explicitly, e.g. "Use Databricks SQL syntax. Only use sql_query for cross-row or aggregate rules; use built-in checks or sql_expression for row-level rules. For sql_query, reference the table only as {{ input_view }}, return a boolean column that is TRUE when the row violates the rule, set condition_column to that column, and set merge_columns to exactly the GROUP BY columns." Most of the unusable output you got (no merge_columns, no condition_column, a literal input_view) comes from the model not knowing that contract.

 

- Validate before applying anything. DQEngine.validate_checks(checks) catches structural problems. Then, for each sql_query check, replace {{ input_view }} with a temp view of your data and run spark.sql("EXPLAIN " + query) to catch syntax errors without executing it.

 

- If you're on a small serving endpoint, pointing the generator at a stronger model noticeably reduces broken SQL.

 

Treat the generated rules as a first draft. Once they pass validation, save them to YAML or a Delta table and load them from there in the pipeline, rather than regenerating on every run.

I hope this helps 🙂