Skip to content

docs(core-spec): Let dataset-scoped metrics reference source columns as source.column - #633

Open
justint-db wants to merge 1 commit into
apache:mainfrom
justint-db:agg-and-source-qualifier
Open

justint-db wants to merge 1 commit into
apache:mainfrom
justint-db:agg-and-source-qualifier

Conversation

@justint-db

@justint-db justint-db commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

A dataset-scoped metric can now reference columns of its dataset's source, written as source.column.

Rules (spec.md Metric Scoping and Name Resolution, expression_language.md Name Spaces)

  • An unqualified name in a dataset-scoped metric must still be a declared field of the dataset: SUM(net_amount).
  • A source column must be qualified with source: SUM(source.quantity). The qualifier is case insensitive. source.amount refers to the source column even when the dataset declares a field named amount.
  • source is not reserved. If a dataset declares a field named source, the name refers to that field, and the dataset's metrics cannot refer to source columns.
  • Model-scoped metrics, keys, and relationships are unchanged: they refer to fields only.

Changes from the earlier version of this PR, following JB's review:

  • source. is required for source columns. Unqualified source-column names are no longer accepted, so a reference can't silently change meaning when a field is added later. This could be relaxed in the future.
  • No configurable source alias.

Validator (validation/validate.py)

  • Accepts source.column in dataset-scoped metrics.
  • Still reports any unqualified name that isn't a declared field, so a typo like SUM(quantiy) fails.
  • Reports source.column in a dataset that declares a field named source.

spec.yaml, ossie-schema.json, and a comment in the Python model are updated to match.

Related Issues

Follows #486 and #591. AGG() reservation: #662 (was previously part of this PR, now moved out to its own PR).

Checklist

Specification

  • Spec changes are included in core-spec/ and follow the existing structure
  • Spec changes have been discussed on the mailing list or in a linked issue
  • Breaking changes to the spec are clearly called out in the summary (none: this only allows a new reference form)

Validation

  • Validation rules in validation/ are updated if the spec changed
  • New validation cases are covered by tests

Tests

  • All existing tests pass (validation/tests/: 493 passed; python/tests/: 268 passed)

@julianhyde

Copy link
Copy Markdown

I welcome the AGG change.

Regarding column references. Are all columns always available? A dataset-scoped metric might be defined in terms of other metrics, and evaluated in a rolled-up context. As an analogy, consider the following SQL query:

SELECT job, MAX(sal) - MIN(sal) + deptno AS m
FROM emp
GROUP BY job

The reference to deptno is invalid because it is not functionally dependent on the group key (job).

Would the m metric definition only be valid if the group key included job? Or maybe deptno would be available but would evaluate to null?

This latter option I call "cube semantics", based on what comes out of the query

SELECT job, deptno, MAX(sal) - MIN(sal) + deptno AS m
FROM emp
GROUP BY CUBE(job, deptno)

@julianhyde

Copy link
Copy Markdown

Maybe we can talk more about "cube semantics" sometime. Once you're thinking in terms of SQL's CUBE and GROUPING SETS operations, it makes sense to bring in the GROUPING function, so you can find out the grain that the metric is being evaluated. I once found a nice way to express semi-additive measures using CASE WHEN GROUPING(d1) THEN ... WHEN GROUPING(d2, d3) THEN ... . A measure can be defined in terms of itself at finer grains.

…as source.column

A dataset-scoped metric may now reference a column of its dataset's
source, written as source.column. The source qualifier is case
insensitive and reaches a column that a field of the same name shadows.
Unqualified names must still be declared fields.

source is not reserved. If a dataset declares a field named source, the
field takes precedence, and the dataset's metrics cannot refer to source
columns. The validator accepts source.column and reports its use in a
dataset that declares a field named source.

Co-authored-by: Isaac <[email protected]>
@justint-db
justint-db force-pushed the agg-and-source-qualifier branch from f403d0c to 92a73f1 Compare October 30, 2026 18:09
@justint-db justint-db changed the title docs(core-spec): Reserve AGG() and let dataset-scoped metrics reference source columns docs(core-spec): Let dataset-scoped metrics reference source columns as source.column Oct 30, 2026
Comment thread validation/validate.py
qualifiers = set()
undeclared = set()
uses_source = False
for col in tree.find_all(exp.Column):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validate_metric_scoping rejects a dataset-scoped metric that uses DATEDIFF with a unit, because sqlglot parses the unit as a column. On 92a73f1, DATEDIFF(day, source.opened_at, source.closed_at) fails with "references undeclared field(s) 'day'". So does the form from expression_language.md, DATEDIFF(day, start_date, end_date), with both fields declared.

validate_metric_references and validate_field_shadowing already skip the unit through iter_columns. With it here, on 92a73f1 with sqlglot 30.27.0:

  • DATEDIFF(day, source.opened_at, source.closed_at) passes.
  • DATEDIFF(day, start_date, end_date) with both fields declared passes.
  • DATEDIFF(MINUTE, opened_at, CURRENT_TIMESTAMP) under OSSIE_SQL_2026 passes.
  • DATEDIFF(day, opened_at, closed_at) with closed_at undeclared reports CLOSED_AT instead of day.
  • SUM(minute) with no field minute is still reported.
  • validation/tests: 493 passed, the same as without the change.
Suggested change
for col in tree.find_all(exp.Column):
for col in iter_columns(tree):

If you'd rather keep this PR's scope, I can send this as a follow-up after it lands, as I offered in #608.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants