Row Filtering Patterns
with ABAC
Learn how to filter table rows based on user group membership and governed tags in Databricks Unity Catalog. This tutorial covers regional access control, healthcare time-based filters, emergency access overrides, and fraud detection patterns β all without writing a single line of per-table access logic.
What is ABAC Row Filtering?
ABAC (Attribute-Based Access Control) row filtering lets you attach policies to a schema rather than individual tables. A policy says: "for tables whose columns are tagged X, apply filter function F to group G." When a new table gets the tag, it automatically inherits the policy β no ALTER TABLE needed.
Key Principle
UDFs contain only data logic (e.g. region_val = 'us').
Group membership logic belongs in the POLICY using TO group and EXCEPT group.
Never put is_account_group_member() inside a UDF β it causes per-row identity lookups.
Prerequisites
Account Groups
- abac_tut_admins
- abac_tut_us_team
- abac_tut_eu_team
- abac_tut_apac_team
- abac_tut_hr_team
- abac_tut_finance_team
Governed Tags
- abac_tut_region
- abac_tut_pii
- abac_tut_emergency
Privileges Needed
- CREATE FUNCTION
- CREATE TABLE
- APPLY TAG
- MANAGE POLICY
Core Pattern
Every row filter is built with two components: a UDF that contains the filter logic, and a POLICY that wires the UDF to a group and a tag condition.
Step 1 β Write the filter UDF
The UDF takes the column value and returns BOOLEAN. Pure data logic only.
CREATE OR REPLACE FUNCTION {catalog}.{schema}.region_filter_us(region_val STRING) RETURNS BOOLEAN DETERMINISTIC RETURN region_val = 'us'
Step 2 β Create the policy
The policy binds the UDF to a group (TO), defines which columns to apply it to
(MATCH COLUMNS has_tag()), and specifies which column to pass to the UDF
(USING COLUMNS).
CREATE OR REPLACE POLICY region_row_filter_us_policy ON SCHEMA {catalog}.{schema} ROW FILTER {catalog}.{schema}.region_filter_us TO abac_tut_us_team FOR TABLES MATCH COLUMNS has_tag('abac_tut_region') AS region_col USING COLUMNS (region_col)
A companion deny policy ensures users not in any regional group see zero rows:
CREATE OR REPLACE POLICY region_row_filter_deny_policy ON SCHEMA {catalog}.{schema} ROW FILTER {catalog}.{schema}.deny_all_filter TO `account users` EXCEPT abac_tut_us_team, abac_tut_eu_team, abac_tut_apac_team, abac_tut_admins FOR TABLES MATCH COLUMNS has_tag('abac_tut_region') AS region_col USING COLUMNS (region_col)
Who Sees What
Sample output (US team user)
Healthcare β Time-Based & Emergency Access
HIPAA-aligned row filtering with business hours, on-call overrides, and regional routing
The healthcare example introduces three advanced row filter patterns on a hospital_visits table:
Business hours filter
Restricts access to 7AMβ7PM MondayβFriday for standard staff:
CREATE OR REPLACE FUNCTION {catalog}.{schema}.business_hours_filter() RETURNS BOOLEAN RETURN ( HOUR(CURRENT_TIMESTAMP()) BETWEEN 7 AND 19 AND DAYOFWEEK(CURRENT_DATE()) BETWEEN 2 AND 6 )
Emergency override
On-call staff always see emergency visits regardless of hours or region:
CREATE OR REPLACE POLICY abac_hc_emergency_access ON SCHEMA {catalog}.{schema} ROW FILTER {catalog}.{schema}.emergency_access_filter TO `account users` EXCEPT abac_tut_admins FOR TABLES MATCH COLUMNS has_tag('abac_tut_emergency') AS emergency_col USING COLUMNS (emergency_col)
Policy Isolation
Before adding healthcare policies, drop the general regional policies
(region_row_filter_*) β a table can only have one active row filter.
Multiple schema-level policies that match the same tagged column cause a runtime error.
Financial Services β Fraud Detection
PCI-DSS and SOX-aligned row filtering for transaction data
The fraud detection example applies multi-condition row filters on a transactions table
tagged with abac_tut_region:
Fraud analyst access
Analysts only see flagged transactions (fraud_flag = TRUE), regardless of region.
Finance team and admins bypass this filter.
CREATE OR REPLACE FUNCTION {catalog}.{schema}.fraud_row_filter(fraud_flag BOOLEAN) RETURNS BOOLEAN RETURN fraud_flag = TRUE -- Policy: apply to all users except finance + admins CREATE OR REPLACE POLICY fraud_detection_filter ON SCHEMA {catalog}.{schema} ROW FILTER {catalog}.{schema}.fraud_row_filter TO `account users` EXCEPT abac_tut_finance_team, abac_tut_admins FOR TABLES MATCH COLUMNS has_tag_value('abac_tut_pii', 'fraud') AS fraud_col USING COLUMNS (fraud_col)
| Role | Sees | Reason |
|---|---|---|
| abac_tut_admins | All 10 transactions | EXCEPT clause |
| abac_tut_finance_team | All 10 transactions | EXCEPT clause |
| abac_tut_us_team | Fraud-flagged only | fraud_flag = TRUE filter |
| No group | 0 rows | Deny policy applies |
Key Learnings
- UDFs = data logic only. Never use
is_account_group_member()in a UDF β useTO/EXCEPTin the POLICY. - One active row filter per table. Drop previous section's policies before creating new ones for the same tagged columns.
CREATE OR REPLACE POLICYdoesn't clean up renamed policies. Old names accumulate and conflict β always DROP explicitly.- Catalog-level policies auto-apply to new schemas, not just the current one.
- MATCH COLUMNS only allows
has_tag()/has_tag_value()β comparison operators likename = 'col'are not supported.