<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Declarative Pipeline Expectations - Quarantining Bad Records in Data Engineering</title>
    <link>https://community.databricks.com/t5/data-engineering/declarative-pipeline-expectations-quarantining-bad-records/m-p/172395#M56634</link>
    <description>&lt;P&gt;&lt;STRONG&gt;Short answer:&lt;/STRONG&gt; the two temporary views are empty because nothing reads them. Views in a pipeline are only computed when another dataset queries them, and the temporary streaming table isn't published to Unity Catalog. To see the actual bad rows, read the flagged table into a published table. To see the counts per expectation, query the pipeline event log.&lt;/P&gt;&lt;H2&gt;1. What the pattern does&lt;/H2&gt;&lt;P&gt;The docs pattern [1] has three parts:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;A temporary streaming table that adds an is_quarantined flag and applies the expectations, so the event log records data quality metrics.&lt;/LI&gt;&lt;LI&gt;Two temporary views that split the rows on that flag, one for valid rows and one for invalid rows.&lt;/LI&gt;&lt;LI&gt;The views are meant to feed downstream datasets in the same pipeline. They aren't meant to be queried directly.&lt;/LI&gt;&lt;/UL&gt;&lt;H2&gt;2. Why the temporary views show nothing&lt;/H2&gt;&lt;P&gt;Views in a pipeline are calculated only when queried, so a view that no downstream dataset reads may have no data quality metrics at all [2]. The temporary (now called &lt;EM&gt;private&lt;/EM&gt;) table isn't published to the metastore and can't be accessed outside the pipeline [3]. The expectation UI shows counts ("2 failed") but not the failing rows.&lt;/P&gt;&lt;H2&gt;3. See which rows were quarantined&lt;/H2&gt;&lt;P&gt;Add published tables that read from the flagged table:&lt;/P&gt;&lt;PRE&gt;CREATE OR REFRESH STREAMING TABLE trips_quarantine AS
SELECT * FROM STREAM(trips_data_quarantine) WHERE is_quarantined = TRUE;

CREATE OR REFRESH STREAMING TABLE trips_clean AS
SELECT * FROM STREAM(trips_data_quarantine) WHERE is_quarantined = FALSE;&lt;/PRE&gt;&lt;P&gt;Both tables then show up in Unity Catalog, and you can query trips_quarantine to inspect and fix the rows.&lt;/P&gt;&lt;H2&gt;4. See the counts per expectation&lt;/H2&gt;&lt;P&gt;The pass and fail counts are in flow_progress events in the event log. By default, the pipeline's run-as user can read them with event_log() [4]:&lt;/P&gt;&lt;PRE&gt;SELECT timestamp, origin.flow_name, e.name AS expectation, e.passed_records, e.failed_records
FROM event_log('&amp;lt;pipeline-id&amp;gt;'),
  LATERAL explode(from_json(details:flow_progress.data_quality.expectations,
    'array&amp;lt;struct&amp;lt;name:string,dataset:string,passed_records:bigint,failed_records:bigint&amp;gt;&amp;gt;')) AS t(e)
WHERE event_type = 'flow_progress'
  AND details:flow_progress.data_quality.expectations IS NOT NULL
ORDER BY timestamp DESC;&lt;/PRE&gt;&lt;P&gt;In my test on samples.nyctaxi.trips, this returned one row per expectation (for example valid_trip_distance: 21,856 passed, 76 failed), and the quarantine table held exactly the 85 rows that failed.&lt;/P&gt;&lt;H2&gt;&lt;SPAN&gt;What I'd do&lt;/SPAN&gt;&lt;/H2&gt;&lt;P&gt;Keep the pattern, but replace the two temporary views with published streaming tables like the ones in step 3. Make sure is_quarantined is exactly NOT(&amp;lt;all expectation rules&amp;gt;), so the quarantine table matches the failed counts in the event log. The Python version of the docs pattern builds the flag from the same rules dict for this reason [1].&lt;/P&gt;&lt;H2&gt;References&lt;/H2&gt;&lt;P&gt;[1] Expectation recommendations and advanced patterns | Databricks on AWS — &lt;A href="https://docs.databricks.com/aws/en/ldp/expectation-patterns#quarantine-invalid-records" target="_blank" rel="noopener"&gt;docs.databricks.com/aws/ldp/expectation-patterns&lt;/A&gt;&lt;BR /&gt;[2] Manage data quality with pipeline expectations | Databricks on AWS — &lt;A href="https://docs.databricks.com/aws/en/ldp/expectations" target="_blank" rel="noopener"&gt;docs.databricks.com/aws/ldp/expectations&lt;/A&gt;&lt;BR /&gt;[3] table (Python language reference) | Databricks on AWS — &lt;A href="https://docs.databricks.com/aws/en/ldp/developer/ldp-python-ref-table" target="_blank" rel="noopener"&gt;docs.databricks.com/aws/ldp/developer/ldp-python-ref-table&lt;/A&gt;&lt;BR /&gt;[4] Pipeline event log | Databricks on AWS — &lt;A href="https://docs.databricks.com/aws/en/ldp/monitor-event-logs" target="_blank" rel="noopener"&gt;docs.databricks.com/aws/ldp/monitor-event-logs&lt;/A&gt;&lt;/P&gt;</description>
    <pubDate>Fri, 09 Oct 2026 07:55:39 GMT</pubDate>
    <dc:creator>VladTamas</dc:creator>
    <dc:date>2026-10-09T07:55:39Z</dc:date>
    <item>
      <title>Declarative Pipeline Expectations - Quarantining Bad Records</title>
      <link>https://community.databricks.com/t5/data-engineering/declarative-pipeline-expectations-quarantining-bad-records/m-p/170101#M56231</link>
      <description>&lt;P&gt;Hi there,&lt;/P&gt;&lt;P&gt;I'm trying to follow&amp;nbsp;&lt;A href="https://docs.databricks.com/aws/en/ldp/expectation-patterns?language=SQL#quarantine-invalid-records" target="_self"&gt;Expectation recommendations and advanced patterns | &lt;STRONG&gt;Quarantine invalid records&lt;/STRONG&gt;&lt;/A&gt;, but this doesn't really make sense to me.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P class="lia-indent-padding-left-30px"&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ChristianRRL_0-1790630498503.png" style="width: 400px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/31565i372FAFABF5A1E0AF/image-size/medium?v=v2&amp;amp;px=400" role="button" title="ChristianRRL_0-1790630498503.png" alt="ChristianRRL_0-1790630498503.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;Following the described pattern almost exactly in my case, I see that there are two TEMPORARY LIVE VIEWs generated (one for valid records and another for quarantined records).&lt;/P&gt;&lt;P&gt;Sure enough, I see there are two temp views generated, but I don't understand what their practical use case is here. The&amp;nbsp;TEMPORARY STREAMING TABLE does show two records out of 6.9k that did not pass the expectation (and are showing as warning), but I don't see specifically which records those are. And when checking the TEMPORARY LIVE VIEWs, they don't really give me any information at all.&lt;/P&gt;&lt;P&gt;Can I get some help to understand this pattern better?&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ChristianRRL_1-1790630675699.png" style="width: 400px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/31566iCF23CAA67B215615/image-size/medium?v=v2&amp;amp;px=400" role="button" title="ChristianRRL_1-1790630675699.png" alt="ChristianRRL_1-1790630675699.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ChristianRRL_2-1790630695429.png" style="width: 400px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/31567iB5D150C0A19A07D1/image-size/medium?v=v2&amp;amp;px=400" role="button" title="ChristianRRL_2-1790630695429.png" alt="ChristianRRL_2-1790630695429.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="ChristianRRL_3-1790630715478.png" style="width: 400px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/31568iE80F716FAC0043D2/image-size/medium?v=v2&amp;amp;px=400" role="button" title="ChristianRRL_3-1790630715478.png" alt="ChristianRRL_3-1790630715478.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Mon, 28 Sep 2026 21:27:36 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/declarative-pipeline-expectations-quarantining-bad-records/m-p/170101#M56231</guid>
      <dc:creator>ChristianRRL</dc:creator>
      <dc:date>2026-09-28T21:27:36Z</dc:date>
    </item>
    <item>
      <title>Re: Declarative Pipeline Expectations - Quarantining Bad Records</title>
      <link>https://community.databricks.com/t5/data-engineering/declarative-pipeline-expectations-quarantining-bad-records/m-p/170176#M56244</link>
      <description>&lt;P class=""&gt;The practical purpose of this pattern is to create two internal processing branches.&lt;/P&gt;&lt;P class=""&gt;trips_data_quarantine classifies each record by adding is_quarantined and applies the expectations so that the pipeline records data-quality metrics. The two temporary views are simply reusable filters:&lt;/P&gt;&lt;UL class=""&gt;&lt;LI&gt;&lt;P class=""&gt;valid_trips_data contains records where is_quarantined = FALSE and is intended to feed the normal downstream flow.&lt;/P&gt;&lt;/LI&gt;&lt;LI&gt;&lt;P class=""&gt;invalid_trips_data contains records where is_quarantined = TRUE and is intended to feed a remediation, audit, or replay flow.&lt;/P&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;P class=""&gt;This is useful when the two branches have different downstream consumers. For example, valid trips could be written to a curated table, while invalid trips could be written to a quarantine table for investigation and later reprocessing.&lt;/P&gt;</description>
      <pubDate>Tue, 29 Sep 2026 15:56:38 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/declarative-pipeline-expectations-quarantining-bad-records/m-p/170176#M56244</guid>
      <dc:creator>veeramadaan</dc:creator>
      <dc:date>2026-09-29T15:56:38Z</dc:date>
    </item>
    <item>
      <title>Re: Declarative Pipeline Expectations - Quarantining Bad Records</title>
      <link>https://community.databricks.com/t5/data-engineering/declarative-pipeline-expectations-quarantining-bad-records/m-p/170192#M56252</link>
      <description>&lt;P&gt;Hi! The confusion here is understandable, because the docs example stops one step short of being useful on its own.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Why the views show nothing&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;Temporary views in a pipeline aren't materialized or published to Unity Catalog. They're logical building blocks meant to be read by other datasets &lt;EM&gt;within the same pipeline&lt;/EM&gt;. If nothing downstream consumes them, they're never computed, so there are no metrics and nothing to query. Similarly, the temporary streaming table isn't published, and the expectation metrics in the UI only store counts in the event log, not the actual failing rows. That's why you can see "2 failed" but not which two.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;How to actually see the quarantined records&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;Replace the two temporary views with published tables that read from the temp table and filter on the flag, for example:&lt;BR /&gt;&lt;BR /&gt;CREATE OR REFRESH STREAMING TABLE quarantine_eleven_mile_outages AS&lt;BR /&gt;SELECT * FROM STREAM(temp_eleven_mile_outages) WHERE is_quarantined = TRUE;&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;&lt;P&gt;Do the same with is_quarantined = FALSE for your silver table. Both will then appear in Unity Catalog, show row counts in the pipeline graph, and can be queried directly to review and fix the bad records. Alternatively, if you just want a quick look, you can drop the TEMPORARY keyword from the flagged table and query WHERE is_quarantined = TRUE.&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;One thing to double-check&lt;/STRONG&gt;&lt;/P&gt;&lt;P&gt;Make sure your is_quarantined expression is the exact negation of your valid_id expectation. The expectation and the flag are evaluated independently, so if the logic drifts apart, the counts in the UI won't match what lands in the quarantine table.&lt;/P&gt;&lt;P&gt;Hope that helps!&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;</description>
      <pubDate>Tue, 29 Sep 2026 19:55:48 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/declarative-pipeline-expectations-quarantining-bad-records/m-p/170192#M56252</guid>
      <dc:creator>LiresaFerizaj</dc:creator>
      <dc:date>2026-09-29T19:55:48Z</dc:date>
    </item>
    <item>
      <title>Re: Declarative Pipeline Expectations - Quarantining Bad Records</title>
      <link>https://community.databricks.com/t5/data-engineering/declarative-pipeline-expectations-quarantining-bad-records/m-p/172395#M56634</link>
      <description>&lt;P&gt;&lt;STRONG&gt;Short answer:&lt;/STRONG&gt; the two temporary views are empty because nothing reads them. Views in a pipeline are only computed when another dataset queries them, and the temporary streaming table isn't published to Unity Catalog. To see the actual bad rows, read the flagged table into a published table. To see the counts per expectation, query the pipeline event log.&lt;/P&gt;&lt;H2&gt;1. What the pattern does&lt;/H2&gt;&lt;P&gt;The docs pattern [1] has three parts:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;A temporary streaming table that adds an is_quarantined flag and applies the expectations, so the event log records data quality metrics.&lt;/LI&gt;&lt;LI&gt;Two temporary views that split the rows on that flag, one for valid rows and one for invalid rows.&lt;/LI&gt;&lt;LI&gt;The views are meant to feed downstream datasets in the same pipeline. They aren't meant to be queried directly.&lt;/LI&gt;&lt;/UL&gt;&lt;H2&gt;2. Why the temporary views show nothing&lt;/H2&gt;&lt;P&gt;Views in a pipeline are calculated only when queried, so a view that no downstream dataset reads may have no data quality metrics at all [2]. The temporary (now called &lt;EM&gt;private&lt;/EM&gt;) table isn't published to the metastore and can't be accessed outside the pipeline [3]. The expectation UI shows counts ("2 failed") but not the failing rows.&lt;/P&gt;&lt;H2&gt;3. See which rows were quarantined&lt;/H2&gt;&lt;P&gt;Add published tables that read from the flagged table:&lt;/P&gt;&lt;PRE&gt;CREATE OR REFRESH STREAMING TABLE trips_quarantine AS
SELECT * FROM STREAM(trips_data_quarantine) WHERE is_quarantined = TRUE;

CREATE OR REFRESH STREAMING TABLE trips_clean AS
SELECT * FROM STREAM(trips_data_quarantine) WHERE is_quarantined = FALSE;&lt;/PRE&gt;&lt;P&gt;Both tables then show up in Unity Catalog, and you can query trips_quarantine to inspect and fix the rows.&lt;/P&gt;&lt;H2&gt;4. See the counts per expectation&lt;/H2&gt;&lt;P&gt;The pass and fail counts are in flow_progress events in the event log. By default, the pipeline's run-as user can read them with event_log() [4]:&lt;/P&gt;&lt;PRE&gt;SELECT timestamp, origin.flow_name, e.name AS expectation, e.passed_records, e.failed_records
FROM event_log('&amp;lt;pipeline-id&amp;gt;'),
  LATERAL explode(from_json(details:flow_progress.data_quality.expectations,
    'array&amp;lt;struct&amp;lt;name:string,dataset:string,passed_records:bigint,failed_records:bigint&amp;gt;&amp;gt;')) AS t(e)
WHERE event_type = 'flow_progress'
  AND details:flow_progress.data_quality.expectations IS NOT NULL
ORDER BY timestamp DESC;&lt;/PRE&gt;&lt;P&gt;In my test on samples.nyctaxi.trips, this returned one row per expectation (for example valid_trip_distance: 21,856 passed, 76 failed), and the quarantine table held exactly the 85 rows that failed.&lt;/P&gt;&lt;H2&gt;&lt;SPAN&gt;What I'd do&lt;/SPAN&gt;&lt;/H2&gt;&lt;P&gt;Keep the pattern, but replace the two temporary views with published streaming tables like the ones in step 3. Make sure is_quarantined is exactly NOT(&amp;lt;all expectation rules&amp;gt;), so the quarantine table matches the failed counts in the event log. The Python version of the docs pattern builds the flag from the same rules dict for this reason [1].&lt;/P&gt;&lt;H2&gt;References&lt;/H2&gt;&lt;P&gt;[1] Expectation recommendations and advanced patterns | Databricks on AWS — &lt;A href="https://docs.databricks.com/aws/en/ldp/expectation-patterns#quarantine-invalid-records" target="_blank" rel="noopener"&gt;docs.databricks.com/aws/ldp/expectation-patterns&lt;/A&gt;&lt;BR /&gt;[2] Manage data quality with pipeline expectations | Databricks on AWS — &lt;A href="https://docs.databricks.com/aws/en/ldp/expectations" target="_blank" rel="noopener"&gt;docs.databricks.com/aws/ldp/expectations&lt;/A&gt;&lt;BR /&gt;[3] table (Python language reference) | Databricks on AWS — &lt;A href="https://docs.databricks.com/aws/en/ldp/developer/ldp-python-ref-table" target="_blank" rel="noopener"&gt;docs.databricks.com/aws/ldp/developer/ldp-python-ref-table&lt;/A&gt;&lt;BR /&gt;[4] Pipeline event log | Databricks on AWS — &lt;A href="https://docs.databricks.com/aws/en/ldp/monitor-event-logs" target="_blank" rel="noopener"&gt;docs.databricks.com/aws/ldp/monitor-event-logs&lt;/A&gt;&lt;/P&gt;</description>
      <pubDate>Fri, 09 Oct 2026 07:55:39 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/declarative-pipeline-expectations-quarantining-bad-records/m-p/172395#M56634</guid>
      <dc:creator>VladTamas</dc:creator>
      <dc:date>2026-10-09T07:55:39Z</dc:date>
    </item>
    <item>
      <title>Re: Declarative Pipeline Expectations - Quarantining Bad Records</title>
      <link>https://community.databricks.com/t5/data-engineering/declarative-pipeline-expectations-quarantining-bad-records/m-p/172399#M56635</link>
      <description>&lt;P&gt;Adding further to above good replies, one thing I would like to add is that a quarantine table is much more useful if it stores why each row was quarantined, not just &lt;STRONG&gt;is_quarantined = true&lt;/STRONG&gt;.&lt;/P&gt;&lt;P&gt;The expectation UI/event log is mainly for counts and trends, it is not a row-level error store and doesn't give full picture.&lt;/P&gt;&lt;P&gt;For multiple DQ rules, consider adding a &lt;STRONG&gt;failed_rules&lt;/STRONG&gt; column to the quarantined dataset, for example:&lt;/P&gt;&lt;LI-CODE lang="markup"&gt;rules = {
    "valid_pickup_zip": "pickup_zip IS NOT NULL",
    "valid_dropoff_zip": "dropoff_zip IS NOT NULL"
}

quarantine_condition = " OR ".join(
    f"NOT ({expr})"
    for expr in rules.values()
)

failed_rule_exprs = [
    F.when(~F.expr(condition), F.lit(rule_name))
    for rule_name, condition in rules.items()
]
df = (
    source_df
    .withColumn(
        "failed_rules",
        F.array_compact(F.array(*failed_rule_exprs))
    )
)&lt;/LI-CODE&gt;&lt;P&gt;&lt;STRONG&gt;Then quarantine and clean rows are simply :&lt;/STRONG&gt;&lt;BR /&gt;quarantined_df = df.filter(F.size("failed_rules") &amp;gt; 0)&lt;BR /&gt;clean_df = df.filter(F.size("failed_rules") == 0)&lt;/P&gt;&lt;P&gt;That gives you both:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;expectation metrics for monitoring&lt;/LI&gt;&lt;LI&gt;row level failure reasons for investigation/reprocessing&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;One other thing for production is to keep the expectation rules and quarantine logic driven from the same rule set where possible. They could match today, but defining them separately makes it easy for them to drift over time when someone updates one and forgets the other. It's better to maintain single version of truth for the rules defined.&lt;/P&gt;</description>
      <pubDate>Fri, 09 Oct 2026 09:08:13 GMT</pubDate>
      <guid>https://community.databricks.com/t5/data-engineering/declarative-pipeline-expectations-quarantining-bad-records/m-p/172399#M56635</guid>
      <dc:creator>data_pulse</dc:creator>
      <dc:date>2026-10-09T09:08:13Z</dc:date>
    </item>
  </channel>
</rss>

