{"id":3196,"date":"2026-04-20T14:30:33","date_gmt":"2026-04-20T06:30:33","guid":{"rendered":"https:\/\/www.dpriver.com\/blog\/?p=3196"},"modified":"2026-04-21T12:32:57","modified_gmt":"2026-04-21T04:32:57","slug":"datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep","status":"publish","type":"post","link":"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/","title":{"rendered":"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis"},"content":{"rendered":"<p>DataHub issue <a href=\"https:\/\/github.com\/datahub-project\/datahub\/issues\/15327\" target=\"_blank\" rel=\"noopener\">#15327<\/a> reports a common Power BI + DataHub problem: <strong>four Snowflake-connected Power BI datasets produce zero upstream lineage<\/strong>. No tables. No columns. The lineage graph just stops at the Power BI boundary.<\/p>\n<p>We analyzed all four M-language queries from the issue, identified two distinct failure patterns, and ran real lineage extraction against each one using GSP&#8217;s Power Query M-language parser. Here&#8217;s what we found \u2014 and how we solve both patterns.<\/p>\n<h2>Why DataHub Can&#8217;t Parse These Queries<\/h2>\n<p>The root cause is that Power BI doesn&#8217;t generate SQL \u2014 it generates <strong>M-language<\/strong> (Power Query Formula Language). M is a fully functional language (closer to F# than SQL) that Power BI uses behind the scenes for all &#8220;Get Data&#8221; and &#8220;Transform Data&#8221; operations.<\/p>\n<p>DataHub&#8217;s ingestion pipeline expects SQL. When it receives M-language, no SQL parser (sqlglot, sqllineage, or any other) can extract lineage from it because <em>it&#8217;s not SQL<\/em>.<\/p>\n<h2>Two Patterns, Both Solved<\/h2>\n<p>The four queries in #15327 fall into two fundamentally different categories. GSP&#8217;s Power Query M-language extractor (<code>dbvpowerquery<\/code>) handles both:<\/p>\n<table>\n<thead>\n<tr>\n<th>Pattern<\/th>\n<th>Queries<\/th>\n<th>What Happens<\/th>\n<th>GSP Result<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>Pattern A<\/strong> \u2014 M Navigation<\/td>\n<td>Q1, Q3<\/td>\n<td>Table reference encoded in M&#8217;s record-access syntax: <code>{[Name=\"X\", Kind=\"Database\"]}[Data]<\/code>. No SQL anywhere.<\/td>\n<td><strong>Table-level lineage recovered<\/strong> via navigation chain parsing<\/td>\n<\/tr>\n<tr>\n<td><strong>Pattern B<\/strong> \u2014 Value.NativeQuery()<\/td>\n<td>Q2, Q4<\/td>\n<td>M wraps actual SQL inside a <code>Value.NativeQuery()<\/code> call. SQL has M-encoded escapes (<code>#(lf)<\/code>, <code>\"\"<\/code>).<\/td>\n<td><strong>Column-level lineage recovered<\/strong> via SQL extraction + parsing<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Pattern A: Pure M Navigation (Queries 1 &amp; 3)<\/h2>\n<p>These queries use M-language&#8217;s navigation syntax to reach Snowflake objects \u2014 no SQL at all. GSP&#8217;s M-language parser walks the navigation chain <code>{[Name=\"X\", Kind=\"Y\"]}[Data]<\/code> to extract the full <code>database.schema.table<\/code> path.<\/p>\n<h3>Query 1: Navigation to a Snowflake View<\/h3>\n<p><strong>Original M-Language:<\/strong><\/p>\n<pre><code>let\n    Source = Snowflake.Databases(SnowFlakeConnector, SnowflakeWarehouse),\n    my_Database = Source{[Name=\"PROD201_DB_redacted\", Kind=\"Database\"]}[Data],\n    CONSUMPTION_Schema = my_Database{[Name=\"CONSUMPTION\", Kind=\"Schema\"]}[Data],\n    Details_View = CONSUMPTION_Schema{[Name=\"details\", Kind=\"View\"]}[Data],\n    #\"Changed Type1\" = Table.TransformColumnTypes(Details_View, ...),\n    #\"Filtered Rows\" = Table.SelectRows(#\"Changed Type1\", ...)\nin #\"Filtered Rows\"<\/code><\/pre>\n<p><strong>GSP analysis:<\/strong> The parser identifies <code>Snowflake.Databases<\/code> as the connector, then walks the navigation chain through three steps:<\/p>\n<ul>\n<li><code>my_Database<\/code>: <code>{[Name=\"PROD201_DB_redacted\", Kind=\"Database\"]}<\/code> \u2192 Database level<\/li>\n<li><code>CONSUMPTION_Schema<\/code>: <code>{[Name=\"CONSUMPTION\", Kind=\"Schema\"]}<\/code> \u2192 Schema level<\/li>\n<li><code>Details_View<\/code>: <code>{[Name=\"details\", Kind=\"View\"]}<\/code> \u2192 View level<\/li>\n<\/ul>\n<p><strong>GSP result:<\/strong><\/p>\n<pre><code>Navigation resolved:\n  Step: Details_View | Vendor: dbvsnowflake\n  Path: PROD201_DB_redacted.CONSUMPTION.details\n  Synthetic SQL: SELECT * FROM \"PROD201_DB_redacted\".\"CONSUMPTION\".\"details\"<\/code><\/pre>\n<p><strong>Upstream table recovered: <code>PROD201_DB_redacted.CONSUMPTION.details<\/code><\/strong> (table-level lineage)<\/p>\n<h3>Query 3: Navigation to a Snowflake Table + Column Renaming<\/h3>\n<p><strong>Original M-Language:<\/strong><\/p>\n<pre><code>let\n    Source = Snowflake.Databases(\"redacted.snowflakecomputing.com\", #\"Warehouse name\"),\n    my_Database = Source{[Name=\"PROD201_DB_redacted\", Kind=\"Database\"]}[Data],\n    CONSUMPTION_Schema = my_Database{[Name=\"CONSUMPTION\", Kind=\"Schema\"]}[Data],\n    MY_View = CONSUMPTION_Schema{[Name=\"MESSAGES\", Kind=\"Table\"]}[Data],\n    #\"Renamed Columns\" = Table.RenameColumns(MY_View, {{\"DATE\",\"Date\"}, ...}),\n    #\"Added Custom\" = Table.AddColumn(#\"Renamed Columns\", \"Message Type\", ...)\nin #\"Added Custom\"<\/code><\/pre>\n<p><strong>GSP result:<\/strong><\/p>\n<pre><code>Navigation resolved:\n  Step: MY_View | Vendor: dbvsnowflake\n  Path: PROD201_DB_redacted.CONSUMPTION.MESSAGES\n  Synthetic SQL: SELECT * FROM \"PROD201_DB_redacted\".\"CONSUMPTION\".\"MESSAGES\"<\/code><\/pre>\n<p><strong>Upstream table recovered: <code>PROD201_DB_redacted.CONSUMPTION.MESSAGES<\/code><\/strong> (table-level lineage). The <code>Table.RenameColumns<\/code> and <code>Table.AddColumn<\/code> steps are M-level transformations that don&#8217;t change the upstream source.<\/p>\n<h2>Pattern B: Embedded SQL (Queries 2 &amp; 4)<\/h2>\n<p>These queries wrap real Snowflake SQL inside M&#8217;s <code>Value.NativeQuery()<\/code> function. GSP extracts the SQL string, decodes M-specific escapes, infers the SQL dialect from the inline connector call, and parses the SQL for full column-level lineage.<\/p>\n<h3>Query 2: Simple SELECT with #(lf) escape<\/h3>\n<p><strong>Original M-Language:<\/strong><\/p>\n<pre><code>let\n    Source = Value.NativeQuery(\n        Snowflake.Databases(SnowFlakeServer, SnowFlakeDWH)\n            {[Name=\"PROD201_redacted\"]}[Data],\n        \"SELECT *#(lf)FROM PROD201_DB_redacted.CONSUMPTION.CV_OFFER_redacted_CITY\",\n        null, [EnableFolding=true])\nin Source<\/code><\/pre>\n<p><strong>Step 1 \u2014 Decode M escapes:<\/strong> <code>#(lf)<\/code> \u2192 newline. <strong>Step 2 \u2014 Infer vendor:<\/strong> The inline <code>Snowflake.Databases()<\/code> tells GSP this is Snowflake SQL. <strong>Step 3 \u2014 Parse SQL:<\/strong> <code>SELECT *<\/code> produces a wildcard column mapping.<\/p>\n<p><strong>GSP result:<\/strong><\/p>\n<pre><code>NativeQuery resolved:\n  Step: Source | Vendor: dbvsnowflake | Parse RC: 0\n  Decoded SQL: SELECT *\n               FROM PROD201_DB_redacted.CONSUMPTION.CV_OFFER_redacted_CITY\n  Column lineage: * \u2192 * (all columns flow through)<\/code><\/pre>\n<p><strong>Upstream: <code>PROD201_DB_redacted.CONSUMPTION.CV_OFFER_redacted_CITY<\/code><\/strong> \u2014 1 table-level + 1 column-level (<code>* \u2192 *<\/code>) lineage.<\/p>\n<h3>Query 4: Complex Snowflake SQL with GROUP BY ALL, quoted aliases, expressions<\/h3>\n<p><strong>Original M-Language<\/strong> (abbreviated):<\/p>\n<pre><code>let\n    Source = Value.NativeQuery(\n        Snowflake.Databases(\"redacted.snowflakecomputing.com\",\n            WAREHOUSE, [Implementation=\"2.0\"])\n            {[Name=\"PROD201_DB_redacted\"]}[Data],\n        \"\nSELECT\n  SERVICE_START_DATE AS \"\"Service Date\"\",\n  TO_NUMBER(OPERATIVE_OFFICE) || '_' || statement || '_'\n    || VENDOR_CODE || '_' || TO_CHAR(SERVICE_START_DATE, 'YYYYMMDD')\n    AS OFFICE_STATEMENT_VENDOR_DATE,\n  VENDOR_CODE\nFROM PROD201_DB_redacted_DATAMARTS.SALES_MARKETING\n     .CV_COMMDX_SALES_TRANSFERS\nWHERE SERVICE_START_DATE &gt;= '2023-10-01' ...\nGROUP BY ALL\nHAVING SUM(COST_OF_SALES_CUR) = 0 AND COUNT(*) &gt; 1\n        \", null, [EnableFolding=true]),\n    #\"TimeFilter\" = Table.SelectRows(Source, ...)\nin #\"TimeFilter\"<\/code><\/pre>\n<p><strong>Step 1 \u2014 Decode M escapes:<\/strong> <code>\"\"Service Date\"\"<\/code> \u2192 <code>\"Service Date\"<\/code> (Snowflake quoted identifier). <strong>Step 2 \u2014 Infer vendor:<\/strong> Inline <code>Snowflake.Databases()<\/code> \u2192 Snowflake. <strong>Step 3 \u2014 Analyze SQL:<\/strong><\/p>\n<ul>\n<li><strong>Column 1:<\/strong> <code>SERVICE_START_DATE AS \"Service Date\"<\/code> \u2014 simple alias (1 mapping)<\/li>\n<li><strong>Column 2:<\/strong> <code>TO_NUMBER(OPERATIVE_OFFICE) || '_' || statement || '_' || VENDOR_CODE || '_' || TO_CHAR(SERVICE_START_DATE, 'YYYYMMDD') AS OFFICE_STATEMENT_VENDOR_DATE<\/code> \u2014 concatenation with 4 source columns traced through <code>TO_NUMBER()<\/code> and <code>TO_CHAR()<\/code> (4 mappings)<\/li>\n<li><strong>Column 3:<\/strong> <code>VENDOR_CODE<\/code> \u2014 direct pass-through (1 mapping)<\/li>\n<\/ul>\n<p><strong>GSP result \u2014 6 column-level lineage mappings:<\/strong><\/p>\n<table>\n<thead>\n<tr>\n<th>Source Column<\/th>\n<th><\/th>\n<th>Target Column<\/th>\n<th>Why<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>SERVICE_START_DATE<\/code><\/td>\n<td>\u2192<\/td>\n<td><code>SERVICE DATE<\/code><\/td>\n<td>Direct alias: <code>AS \"Service Date\"<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>OPERATIVE_OFFICE<\/code><\/td>\n<td>\u2192<\/td>\n<td><code>OFFICE_STATEMENT_VENDOR_DATE<\/code><\/td>\n<td>Via <code>TO_NUMBER()<\/code> in concat<\/td>\n<\/tr>\n<tr>\n<td><code>STATEMENT<\/code><\/td>\n<td>\u2192<\/td>\n<td><code>OFFICE_STATEMENT_VENDOR_DATE<\/code><\/td>\n<td>Direct in <code>||<\/code> concat<\/td>\n<\/tr>\n<tr>\n<td><code>VENDOR_CODE<\/code><\/td>\n<td>\u2192<\/td>\n<td><code>OFFICE_STATEMENT_VENDOR_DATE<\/code><\/td>\n<td>Direct in <code>||<\/code> concat<\/td>\n<\/tr>\n<tr>\n<td><code>SERVICE_START_DATE<\/code><\/td>\n<td>\u2192<\/td>\n<td><code>OFFICE_STATEMENT_VENDOR_DATE<\/code><\/td>\n<td>Via <code>TO_CHAR()<\/code> in concat<\/td>\n<\/tr>\n<tr>\n<td><code>VENDOR_CODE<\/code><\/td>\n<td>\u2192<\/td>\n<td><code>VENDOR_CODE<\/code><\/td>\n<td>Direct pass-through<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><strong>Upstream: <code>PROD201_DB_redacted_DATAMARTS.SALES_MARKETING.CV_COMMDX_SALES_TRANSFERS<\/code><\/strong> \u2014 1 table-level + 6 column-level lineages.<\/p>\n<h2>Summary: All 4 Queries Solved<\/h2>\n<table>\n<thead>\n<tr>\n<th>Query<\/th>\n<th>Pattern<\/th>\n<th>Upstream Table<\/th>\n<th>DataHub Today<\/th>\n<th>With GSP<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>Q1<\/strong><\/td>\n<td>A (M Navigation)<\/td>\n<td><code>PROD201_DB_redacted.CONSUMPTION.details<\/code><\/td>\n<td>0 lineage<\/td>\n<td><strong>Table-level lineage<\/strong><\/td>\n<\/tr>\n<tr>\n<td><strong>Q2<\/strong><\/td>\n<td>B (NativeQuery)<\/td>\n<td><code>PROD201_DB_redacted.CONSUMPTION.CV_OFFER_redacted_CITY<\/code><\/td>\n<td>0 lineage<\/td>\n<td><strong>1 table + 1 column (*)<\/strong><\/td>\n<\/tr>\n<tr>\n<td><strong>Q3<\/strong><\/td>\n<td>A (M Navigation)<\/td>\n<td><code>PROD201_DB_redacted.CONSUMPTION.MESSAGES<\/code><\/td>\n<td>0 lineage<\/td>\n<td><strong>Table-level lineage<\/strong><\/td>\n<\/tr>\n<tr>\n<td><strong>Q4<\/strong><\/td>\n<td>B (NativeQuery)<\/td>\n<td><code>...DATAMARTS.SALES_MARKETING.CV_COMMDX_SALES_TRANSFERS<\/code><\/td>\n<td>0 lineage<\/td>\n<td><strong>1 table + 6 columns<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>How It Works<\/h2>\n<p>GSP&#8217;s Power Query module (<code>dbvpowerquery<\/code>) is a lightweight M-language extractor \u2014 not a full M parser. It answers exactly 6 questions about any M document:<\/p>\n<ol>\n<li>What are the <code>let<\/code> bindings?<\/li>\n<li>Which binding is returned by <code>in<\/code>?<\/li>\n<li>Does a binding contain <code>Value.NativeQuery()<\/code>? \u2192 Extract SQL, decode escapes, delegate to vendor SQL parser<\/li>\n<li>Does a binding represent a navigation chain? \u2192 Extract <code>database.schema.table<\/code><\/li>\n<li>What connector function is at the root? \u2192 Infer SQL dialect (Snowflake, SQL Server, Oracle, PostgreSQL, MySQL, BigQuery, Redshift, Databricks, Hive)<\/li>\n<li>Which bindings reference other bindings? \u2192 Follow step references<\/li>\n<\/ol>\n<p>Everything else in M (closures, <code>each<\/code>, <code>Table.*<\/code> transforms, type system) is parsed permissively \u2014 unknown constructs produce warnings, never wrong lineage.<\/p>\n<h2>Try It<\/h2>\n<pre><code># Install the sidecar\npip install git+https:\/\/github.com\/gudusoftware\/gsp-datahub-sidecar.git\n\n# Test with your Power BI queries\ngsp-datahub-sidecar --mode authenticated \\\n  --user-id YOUR_USER_ID \\\n  --secret-key YOUR_SECRET_KEY \\\n  --sql-file your_query.sql \\\n  --db-vendor dbvsnowflake \\\n  --dry-run<\/code><\/pre>\n<p>Sign up for a free API key at <a href=\"https:\/\/docs.gudusoft.com\/sign-up\/\" target=\"_blank\" rel=\"noopener\">docs.gudusoft.com\/sign-up<\/a>. For a full interactive analysis, see our <a href=\"https:\/\/www.sqlparser.com\/datahub\/powerbi-m-language\/\" target=\"_blank\" rel=\"noopener\">dedicated analysis page<\/a>.<\/p>\n<h2>Related Issues<\/h2>\n<ul>\n<li><a href=\"https:\/\/github.com\/datahub-project\/datahub\/issues\/15327\" target=\"_blank\" rel=\"noopener\">#15327<\/a> \u2014 No upstream lineage tracked for specific Power BI tables (this analysis)<\/li>\n<li><a href=\"https:\/\/github.com\/datahub-project\/datahub\/issues\/11251\" target=\"_blank\" rel=\"noopener\">#11251<\/a> \u2014 Power BI SQL comments break lineage (#(lf) encoding) \u2014 <a href=\"https:\/\/www.sqlparser.com\/datahub\/powerbi-lineage\/\">solved<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/datahub-project\/datahub\/issues\/11654\" target=\"_blank\" rel=\"noopener\">#11654<\/a> \u2014 BigQuery procedural SQL drops lineage \u2014 <a href=\"https:\/\/www.sqlparser.com\/datahub\/bigquery-lineage\/\">solved<\/a><\/li>\n<\/ul>\n<p><em>Disclosure: I work at <a href=\"https:\/\/www.gudusoft.com\" target=\"_blank\" rel=\"noopener\">Gudu Software<\/a>, the company behind GSP SQL Parser, SQLFlow, and the gsp-datahub-sidecar. All lineage results shown were produced by running the M scripts through GSP&#8217;s Power Query parser (<code>dbvpowerquery<\/code>) and verified against the actual M-language queries from DataHub issue #15327.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Deep analysis of 4 Power BI M-language queries from DataHub issue #15327. Both patterns solved: Pattern A (M navigation chains) produces table-level lineage; Pattern B (Value.NativeQuery with embedded SQL) produces column-level lineage with 6 column mappings traced through expressions.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[14,93],"tags":[119,135,132,139,138,136,130,127],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":5}},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v19.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis<\/title>\n<meta name=\"description\" content=\"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis\" \/>\n<meta property=\"og:description\" content=\"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/\" \/>\n<meta property=\"og:site_name\" content=\"SQL and Data Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-04-20T06:30:33+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-04-21T04:32:57+00:00\" \/>\n<meta name=\"author\" content=\"James\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"James\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.dpriver.com\/blog\/#organization\",\"name\":\"SQL and Data Blog\",\"url\":\"https:\/\/www.dpriver.com\/blog\/\",\"sameAs\":[],\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.dpriver.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.dpriver.com\/blog\/wp-content\/uploads\/2022\/07\/sqlpp-character.png\",\"contentUrl\":\"https:\/\/www.dpriver.com\/blog\/wp-content\/uploads\/2022\/07\/sqlpp-character.png\",\"width\":251,\"height\":72,\"caption\":\"SQL and Data Blog\"},\"image\":{\"@id\":\"https:\/\/www.dpriver.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.dpriver.com\/blog\/#website\",\"url\":\"https:\/\/www.dpriver.com\/blog\/\",\"name\":\"SQL and Data Blog\",\"description\":\"SQL related blog for database professional\",\"publisher\":{\"@id\":\"https:\/\/www.dpriver.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.dpriver.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/\",\"url\":\"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/\",\"name\":\"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis\",\"isPartOf\":{\"@id\":\"https:\/\/www.dpriver.com\/blog\/#website\"},\"datePublished\":\"2026-04-20T06:30:33+00:00\",\"dateModified\":\"2026-04-21T04:32:57+00:00\",\"description\":\"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis\",\"breadcrumb\":{\"@id\":\"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.dpriver.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis\"}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/\"},\"author\":{\"name\":\"James\",\"@id\":\"https:\/\/www.dpriver.com\/blog\/#\/schema\/person\/7bbdbb6e79c5dd9747d08c59d5992b04\"},\"headline\":\"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis\",\"datePublished\":\"2026-04-20T06:30:33+00:00\",\"dateModified\":\"2026-04-21T04:32:57+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/\"},\"wordCount\":705,\"publisher\":{\"@id\":\"https:\/\/www.dpriver.com\/blog\/#organization\"},\"keywords\":[\"column-lineage\",\"data-governance\",\"datahub\",\"gsp-datahub-sidecar\",\"m-language\",\"power-bi\",\"Snowflake\",\"sqlglot\"],\"articleSection\":[\"gsp\",\"SQLFlow\"],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.dpriver.com\/blog\/#\/schema\/person\/7bbdbb6e79c5dd9747d08c59d5992b04\",\"name\":\"James\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.dpriver.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/eeddf4ca7bdafa37ab025068efdc7302?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/eeddf4ca7bdafa37ab025068efdc7302?s=96&d=mm&r=g\",\"caption\":\"James\"},\"sameAs\":[\"http:\/\/www.dpriver.com\"],\"url\":\"https:\/\/www.dpriver.com\/blog\/author\/james\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis","description":"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/","og_locale":"en_US","og_type":"article","og_title":"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis","og_description":"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis","og_url":"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/","og_site_name":"SQL and Data Blog","article_published_time":"2026-04-20T06:30:33+00:00","article_modified_time":"2026-04-21T04:32:57+00:00","author":"James","twitter_card":"summary_large_image","twitter_misc":{"Written by":"James","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Organization","@id":"https:\/\/www.dpriver.com\/blog\/#organization","name":"SQL and Data Blog","url":"https:\/\/www.dpriver.com\/blog\/","sameAs":[],"logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.dpriver.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.dpriver.com\/blog\/wp-content\/uploads\/2022\/07\/sqlpp-character.png","contentUrl":"https:\/\/www.dpriver.com\/blog\/wp-content\/uploads\/2022\/07\/sqlpp-character.png","width":251,"height":72,"caption":"SQL and Data Blog"},"image":{"@id":"https:\/\/www.dpriver.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"WebSite","@id":"https:\/\/www.dpriver.com\/blog\/#website","url":"https:\/\/www.dpriver.com\/blog\/","name":"SQL and Data Blog","description":"SQL related blog for database professional","publisher":{"@id":"https:\/\/www.dpriver.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dpriver.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/","url":"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/","name":"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis","isPartOf":{"@id":"https:\/\/www.dpriver.com\/blog\/#website"},"datePublished":"2026-04-20T06:30:33+00:00","dateModified":"2026-04-21T04:32:57+00:00","description":"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis","breadcrumb":{"@id":"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.dpriver.com\/blog\/"},{"@type":"ListItem","position":2,"name":"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis"}]},{"@type":"Article","@id":"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/#article","isPartOf":{"@id":"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/"},"author":{"name":"James","@id":"https:\/\/www.dpriver.com\/blog\/#\/schema\/person\/7bbdbb6e79c5dd9747d08c59d5992b04"},"headline":"DataHub #15327: Why Power BI M-Language Queries Produce Zero Lineage \u2014 4-Query Deep Analysis","datePublished":"2026-04-20T06:30:33+00:00","dateModified":"2026-04-21T04:32:57+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dpriver.com\/blog\/2026\/04\/datahub-15327-why-power-bi-m-language-queries-produce-zero-lineage-4-query-deep\/"},"wordCount":705,"publisher":{"@id":"https:\/\/www.dpriver.com\/blog\/#organization"},"keywords":["column-lineage","data-governance","datahub","gsp-datahub-sidecar","m-language","power-bi","Snowflake","sqlglot"],"articleSection":["gsp","SQLFlow"],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dpriver.com\/blog\/#\/schema\/person\/7bbdbb6e79c5dd9747d08c59d5992b04","name":"James","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.dpriver.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/eeddf4ca7bdafa37ab025068efdc7302?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/eeddf4ca7bdafa37ab025068efdc7302?s=96&d=mm&r=g","caption":"James"},"sameAs":["http:\/\/www.dpriver.com"],"url":"https:\/\/www.dpriver.com\/blog\/author\/james\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dpriver.com\/blog\/wp-json\/wp\/v2\/posts\/3196"}],"collection":[{"href":"https:\/\/www.dpriver.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dpriver.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dpriver.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dpriver.com\/blog\/wp-json\/wp\/v2\/comments?post=3196"}],"version-history":[{"count":1,"href":"https:\/\/www.dpriver.com\/blog\/wp-json\/wp\/v2\/posts\/3196\/revisions"}],"predecessor-version":[{"id":3197,"href":"https:\/\/www.dpriver.com\/blog\/wp-json\/wp\/v2\/posts\/3196\/revisions\/3197"}],"wp:attachment":[{"href":"https:\/\/www.dpriver.com\/blog\/wp-json\/wp\/v2\/media?parent=3196"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dpriver.com\/blog\/wp-json\/wp\/v2\/categories?post=3196"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dpriver.com\/blog\/wp-json\/wp\/v2\/tags?post=3196"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}