Back to changelog
Improvement
•2 minute read

Column-Level Data Lineage: SQL Server Support

The lineage graph now supports SQL Server, tracing each view column through the T-SQL that defines it.

The Atlas Cloud column-level lineage graph now supports SQL Server. Atlas parses the T-SQL SELECT of each view and traces every view column to the columns it reads, through:

  • Common table expressions (WITH)
  • CROSS APPLY and OUTER APPLY
  • Window functions
  • The built-in table-valued functions STRING_SPLIT, OPENJSON, and GENERATE_SERIES

Column references match declared names case-insensitively: a view that selects customerid from a table that declares CustomerID links to that column.

Example

This view sums each customer's orders in a CTE and picks their latest order with OUTER APPLY:

schema.sql
CREATE TABLE dbo.Customers (
CustomerID int NOT NULL PRIMARY KEY,
FullName nvarchar(100) NOT NULL
);
CREATE TABLE dbo.Orders (
OrderID int NOT NULL PRIMARY KEY,
CustomerID int NOT NULL,
OrderedAt datetime2 NOT NULL,
Total decimal(10,2) NOT NULL
);
CREATE VIEW dbo.CustomerSummary AS
WITH Spend AS (
SELECT CustomerID, SUM(Total) AS TotalSpent
FROM dbo.Orders
GROUP BY CustomerID
)
SELECT c.CustomerID, c.FullName, s.TotalSpent, lo.OrderedAt AS LastOrderAt
FROM dbo.Customers AS c
LEFT JOIN Spend AS s ON s.CustomerID = c.CustomerID
OUTER APPLY (
SELECT TOP 1 o.OrderedAt
FROM dbo.Orders AS o
WHERE o.CustomerID = c.CustomerID
ORDER BY o.OrderedAt DESC
) AS lo;

In the lineage graph, TotalSpent traces through the Spend CTE to SUM(Total) over Orders.Total, and LastOrderAt traces through the OUTER APPLY subquery to Orders.OrderedAt. atlas cloud repo lingraph prints the same lineage:

atlas cloud repo lingraph --slug my-repo
{
"nodes": [
{ "id": "schema/dbo/table/Customers", "type": "table", "name": "Customers", "schema": "dbo" },
{ "id": "schema/dbo/table/Orders", "type": "table", "name": "Orders", "schema": "dbo" },
{ "id": "schema/dbo/view/CustomerSummary", "type": "view", "name": "CustomerSummary", "schema": "dbo" },
{ "id": "schema/dbo/dataset/CustomerSummary/Spend@5", "type": "dataset", "name": "Spend@5", "schema": "dbo" },
{ "id": "schema/dbo/dataset/CustomerSummary/lo@271", "type": "dataset", "name": "lo@271", "schema": "dbo" }
],
"edges": [
{ "from": "schema/dbo/table/Customers", "to": "schema/dbo/view/CustomerSummary" },
{ "from": "schema/dbo/table/Orders", "to": "schema/dbo/view/CustomerSummary" },
{ "from": "schema/dbo/table/Orders", "to": "schema/dbo/dataset/CustomerSummary/Spend@5", "fromColumn": "CustomerID", "toColumn": "CustomerID", "expr": "CustomerID" },
{ "from": "schema/dbo/table/Orders", "to": "schema/dbo/dataset/CustomerSummary/Spend@5", "fromColumn": "Total", "toColumn": "TotalSpent", "expr": "SUM(Total) AS TotalSpent" },
{ "from": "schema/dbo/table/Orders", "to": "schema/dbo/dataset/CustomerSummary/lo@271", "fromColumn": "OrderedAt", "toColumn": "OrderedAt", "expr": "o.OrderedAt" },
{ "from": "schema/dbo/table/Customers", "to": "schema/dbo/view/CustomerSummary", "fromColumn": "CustomerID", "toColumn": "CustomerID", "expr": "c.CustomerID" },
{ "from": "schema/dbo/table/Customers", "to": "schema/dbo/view/CustomerSummary", "fromColumn": "FullName", "toColumn": "FullName", "expr": "c.FullName" },
{ "from": "schema/dbo/dataset/CustomerSummary/Spend@5", "to": "schema/dbo/view/CustomerSummary", "fromColumn": "TotalSpent", "toColumn": "TotalSpent", "expr": "s.TotalSpent" },
{ "from": "schema/dbo/dataset/CustomerSummary/lo@271", "to": "schema/dbo/view/CustomerSummary", "fromColumn": "OrderedAt", "toColumn": "LastOrderAt", "expr": "lo.OrderedAt AS LastOrderAt" }
]
}

Spend@5 is the Spend CTE, and lo@271 is the OUTER APPLY subquery. The two edges with only from and to are the view's object-level dependencies on its tables.

Next Steps

Open the Lineage tab of a SQL Server project, or the lineage action in its ERD and Docs views. The Column-Level Data Lineage docs cover column pinning, transformation expressions, and the lingraph output formats.

improvementcloudlineagesqlserver