Skip to content

Pair the branches of a set operation by position - #8

Merged
IL-William merged 1 commit into
masterfrom
fix/union-by-position-master
Oct 11, 2026
Merged

IL-William merged 1 commit into
masterfrom
fix/union-by-position-master

Conversation

@IL-William

Copy link
Copy Markdown
Owner

Patch 9 of the engine fork that collin pins (dbt-collin decision 0028): the branches of a set operation pair by position, as SQL pairs them, not by name.

A later branch of a UNION, an INTERSECT or an EXCEPT added its columns to the target under their own names. A column that a later branch names differently from the first branch was therefore lost to whichever output column had that name, or became an output of its own:

SELECT k, a AS x FROM t1
UNION ALL
SELECT m.k, m.b FROM t2 AS m

That query came out with three outputs, k, x and b, and x derived from t1.a alone.

The change

  • A later branch's columns take the first branch's names, position by position, with stars expanded.
  • Only the columns the branch gives the set operation's target are renamed. A derived table or a subquery inside the branch keeps its own names.
  • UNION BY NAME still pairs by name.
  • A nested set operation hands its first branch's names up, so a third branch pairs with the first.

Tests

  • Four new tests: a top level union, three branches in a CTE with a star, BY NAME, and a derived table inside a later branch. The first two fail without the patch.
  • cte_self_join_alias_columns_do_not_leak_across_union_scopes asserted the old pairing: it expected the second branch's alias, dept_name, as an output. It now finds one output, emp_name, read from each branch's own CTE. If the second branch's alias leaked to the first CTE, it would see emp alone.
  • The recursive_cte snapshot gains the edge its second branch writes: SELECT e.employee_id, e.employee_id, e.name feeds manager_id from employee_id.
  • 2962 tests pass, and cargo fmt --check is clean.

Measured through collin

Project Effect
3507 model Snowflake project, both of its compiles cache and dumps identical
Cal-ITP (BigQuery) 3 models go from contradicted by the warehouse to confirmed; 12 phantom columns gone (uace_code, uza_name, and col_0 to col_4 twice); 4 edges added, 3 filter reads placed
Shopify, Jaffle Shop identical
lineage-library the one line it marked as known missing is now given

I read each moved edge against the SQL.

Nothing goes to pondpilot/flowscope.

🤖 Generated with Claude Code

https://claude.ai/code/session_017VTEw2dNNL9Pn57Hkeeirn

SQL pairs the columns of a UNION, an INTERSECT or an EXCEPT by position:
the output takes the first branch's names, and each later branch's column
feeds the output column at its place. The analyzer added each branch's
columns to the target under their own names instead, so a later branch
naming a column otherwise lost it to the column of that name, or added
one of its own.

    SELECT k, a AS x FROM t1
    UNION ALL
    SELECT m.k, m.b FROM t2 AS m

came out with three outputs, k, x and b, x derived from t1.a alone.

A later branch's columns now take the first branch's names, position by
position, stars expanded. Only the columns it gives the set operation's
target are renamed: a derived table or a subquery inside the branch keeps
its own. UNION BY NAME still pairs by name. A nested set operation hands
its first branch's names up, so a third branch pairs with the first.

The recursive CTE snapshot gains the edge its second branch writes:
`SELECT e.employee_id, e.employee_id, e.name` feeds manager_id from
employee_id. The test of CTE aliases reused across UNION branches now
finds one output column, read from each branch's own CTE.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017VTEw2dNNL9Pn57Hkeeirn
@IL-William
IL-William merged commit 07a2073 into master Oct 11, 2026
8 checks passed
@IL-William
IL-William deleted the fix/union-by-position-master branch October 11, 2026 05:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant