<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: XLTable</title>
    <description>The latest articles on DEV Community by XLTable (@xltable).</description>
    <link>https://dev.to/xltable</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3691086%2F694c0259-e9df-4d61-bc4c-298e287698c0.png</url>
      <title>DEV Community: XLTable</title>
      <link>https://dev.to/xltable</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xltable"/>
    <language>en</language>
    <item>
      <title>A Semantic Layer That Reads as SQL</title>
      <dc:creator>XLTable</dc:creator>
      <pubDate>Sun, 19 Jul 2026 08:12:49 +0000</pubDate>
      <link>https://dev.to/xltable/a-semantic-layer-that-reads-as-sql-4leg</link>
      <guid>https://dev.to/xltable/a-semantic-layer-that-reads-as-sql-4leg</guid>
      <description>&lt;h1&gt;
  
  
  A Semantic Layer That Reads as SQL
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Why a cube definition should be an executable query — not a YAML description of one. And what AI has to do with it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvt2nfcpz3jfzy8b8d0qa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvt2nfcpz3jfzy8b8d0qa.png" alt=" " width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Ten versions of the truth
&lt;/h2&gt;

&lt;p&gt;Every sufficiently large company has lived through the same conversation. The CFO asks, "What was our revenue this quarter?" — and gets three different answers from three different analysts. Not because anyone made a mistake. One counted revenue with VAT, another without, a third excluded returns but included intercompany sales.&lt;/p&gt;

&lt;p&gt;The data, meanwhile, sits in one place — ClickHouse, BigQuery, Snowflake, or another analytical warehouse. The problem isn't the data. The problem is that the &lt;em&gt;definition&lt;/em&gt; of a metric — what "revenue" means, how sales relate to stores, who is allowed to see which regions — doesn't live in one place. It lives in analysts' heads and in hundreds of scattered SQL queries.&lt;/p&gt;

&lt;p&gt;And business users end up in Excel anyway. You rolled out dashboards, bought licenses, ran trainings, built self-service portals — and still, every report ends its life as an Excel export on someone's desktop. That's not a failure of your team; it's how people actually work. Meanwhile, between Excel and the warehouse grows a pipeline of CSV exports and "intermediate" files, each one another opportunity for the numbers to drift apart.&lt;/p&gt;

&lt;p&gt;This is exactly the problem a semantic layer solves: define your metrics once, under IT control with fine-grained access — then let thousands of users explore them and get the same numbers. Excel becomes the front end. Your warehouse stays the single source of truth.&lt;/p&gt;

&lt;p&gt;A beautiful idea. So why do so many semantic layer projects stall at the pilot stage?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why data teams struggle with semantic layers
&lt;/h2&gt;

&lt;p&gt;Ask a data engineer what a semantic layer is, and the answer will depend on whose documentation they read last. The term is overloaded: metrics layer, headless BI, semantic layer, universal semantic layer — every vendor defines it differently and draws its own architecture diagram. A team reads three articles and comes away with three different pictures of the world.&lt;/p&gt;

&lt;p&gt;Then it turns out that a semantic layer is, as a rule, &lt;em&gt;a separate system with its own lifecycle&lt;/em&gt;. Its own modeling language to learn. Its own compiler to run. Its own deployment process, its own versions, its own breaking changes. The "warehouse + orchestrator + BI" stack gains yet another moving part that has to be studied, upgraded, and fixed.&lt;/p&gt;

&lt;p&gt;The cost of entry before the first result turns out to be high. Before the business sees a single number, someone has to design the model, absorb a new vocabulary — semantic models, entities, measures, metrics, with metrics further split into types: simple, ratio, derived, cumulative — wire up integrations, and explain to everyone why any of this was necessary. That's weeks of work before the first "wow," and an organization's budget of patience is not unlimited.&lt;/p&gt;

&lt;p&gt;Finally, the layer often has no obvious owner. Analysts consider it infrastructure ("that's for the engineers"), engineers consider it analytics ("that's about business metrics"). The layer hangs between teams, and once the enthusiasm of the first sprint wears off, nobody is left to maintain it.&lt;/p&gt;

&lt;p&gt;None of this says the idea of a semantic layer is bad. All of it says one thing: the &lt;em&gt;cost of adoption&lt;/em&gt; of a typical implementation is too high. Let's see where that cost comes from.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it's done today: YAML on top of SQL
&lt;/h2&gt;

&lt;p&gt;The dominant approach in modern semantic layers is declarative metadata. The model is described in YAML files: here are the entities, here are the dimensions, here are the measures, here are the metrics built on top of the measures. A dedicated engine reads these files and generates SQL at query time.&lt;/p&gt;

&lt;p&gt;It looks roughly like this. Suppose we need one single metric — the number of units sold:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;semantic_models&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sales&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;One&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;row&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;per&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;sale"&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ref('fct_sales')&lt;/span&gt;
    &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;agg_time_dimension&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sale_date&lt;/span&gt;
    &lt;span class="na"&gt;entities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sale&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;primary&lt;/span&gt;
        &lt;span class="na"&gt;expr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sale_id&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;store&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;foreign&lt;/span&gt;
        &lt;span class="na"&gt;expr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;store_id&lt;/span&gt;
    &lt;span class="na"&gt;dimensions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sale_date&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;time&lt;/span&gt;
        &lt;span class="na"&gt;type_params&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;time_granularity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;day&lt;/span&gt;
    &lt;span class="na"&gt;measures&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;qty&lt;/span&gt;
        &lt;span class="na"&gt;agg&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sum&lt;/span&gt;

&lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sales_quantity&lt;/span&gt;
    &lt;span class="na"&gt;label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Sales Quantity&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;simple&lt;/span&gt;
    &lt;span class="na"&gt;type_params&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;measure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;qty&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Almost thirty lines, two sections, four levels of nesting — and notice: the measure &lt;code&gt;qty&lt;/code&gt; is not yet a metric by itself. For the user to see a number, a metric of type &lt;code&gt;simple&lt;/code&gt; must be declared on top of the measure — one that "simply uses the measure as is."&lt;/p&gt;

&lt;p&gt;This approach has real strengths, and they deserve an honest mention. YAML is machine-readable — convenient for building APIs and code generation on top of. A declarative model isn't tied to any particular SQL dialect. The files live happily in git. All true.&lt;/p&gt;

&lt;p&gt;But there is a price, and here it is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YAML cannot be executed.&lt;/strong&gt; It is a description of a query, not a query. The debugging loop looks like this: edit the YAML → run the compiler → the engine generates SQL → execute it → get an error &lt;em&gt;in the generated SQL&lt;/em&gt; → mentally translate it back to lines of YAML that don't exist in that SQL. Every iteration passes through a layer of indirection. The engineer debugs something other than what they wrote.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The SQL never went away — it just moved into string literals.&lt;/strong&gt; As soon as an expression gets any more complex than a sum over a column, an &lt;code&gt;expr&lt;/code&gt; field appears in the YAML with a chunk of SQL inside: &lt;code&gt;expr: case when status = 'closed' then amount end&lt;/code&gt;. You get the worst of both worlds: expressions are still written in SQL, but now they live inside YAML strings — no syntax highlighting, no validation, with escaping rules and multi-line blocks via &lt;code&gt;|&lt;/code&gt;. Some systems add a templating engine on top — and now you have Jinja inside YAML inside SQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every tool is a new system of concepts.&lt;/strong&gt; Entities with types primary/foreign/unique/natural, dimensions with type_params, metrics of four kinds — each vendor has its own ontology, and none of it transfers between tools. Unlike SQL, which every person on a data team already knows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Join semantics are declared abstractly.&lt;/strong&gt; You write &lt;code&gt;type: foreign&lt;/code&gt; — but which JOIN the engine will actually build, and which path it will take through the model graph, only becomes visible after compilation. When the engine picks an unexpected join path, debugging turns into a study of the generator's internals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A definition can only be validated through the toolchain.&lt;/strong&gt; Validating a model means running the vendor's compiler with its own error messages. Without the tool installed and configured, a YAML file is just text.&lt;/p&gt;

&lt;p&gt;Add it all up and you get exactly that high cost of adoption from the previous section. It isn't accidental — it's built into the architecture of the approach: between the engineer and their data stands a layer of abstraction that must be learned before it starts to help.&lt;/p&gt;

&lt;p&gt;Before building XLTable, we spent years implementing and operating Microsoft Analysis Services in large retail companies — watching the business live in PivotTables while IT lived in cube definitions. XLTable grew out of that experience, not out of a desire to invent a new format. And so we took a different path.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ph9p73a3gqvdaz2i64f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ph9p73a3gqvdaz2i64f.png" alt=" " width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The XLTable principle: the executable SELECT
&lt;/h2&gt;

&lt;p&gt;XLTable is an XMLA-compatible OLAP semantic layer for ClickHouse, Snowflake, BigQuery, Databricks, StarRocks, Trino, Greenplum, and DuckDB. Excel sees it as a familiar OLAP cube: MDX queries, PivotTables, hierarchies — everything works just as it does with Microsoft Analysis Services (for which XLTable is a drop-in replacement). What reaches the database is already optimized SQL. No SQL for end users, no data copies. The semantic layer here is the cube definition: measures, dimensions, hierarchies, relationships, and permissions.&lt;/p&gt;

&lt;p&gt;And that cube is defined not in YAML and not in a graphical designer, but in SQL. Here is the equivalent of those thirty lines of YAML from the previous section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--olap_source Sales&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
&lt;span class="c1"&gt;--olap_measures&lt;/span&gt;
    &lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sales_sum_qty&lt;/span&gt; &lt;span class="c1"&gt;--translation=`Sales Quantity` --format=`#,##0`&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five lines. But the key property isn't brevity — it's this: &lt;strong&gt;this is a working query&lt;/strong&gt;. Mentally strip the comments and you're left with an ordinary SELECT that can be copied into any database client, executed, and it returns real rows. The tags in the comments (&lt;code&gt;--olap_source&lt;/code&gt;, &lt;code&gt;--olap_measures&lt;/code&gt;, &lt;code&gt;--translation&lt;/code&gt;) merely tell XLTable how to assemble such queries into a cube.&lt;/p&gt;

&lt;p&gt;We call this the &lt;em&gt;executable SELECT&lt;/em&gt; principle, and it is not a syntactic quirk — it is the foundation of the whole system. Several things follow from it:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Debugging is execution.&lt;/em&gt; "Does the model compile?" is not a question that exists. The question is "does the query run" — and the database itself answers it, with an ordinary SQL error, in the dialect you write every day.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The barrier to entry is knowing SELECT.&lt;/em&gt; There is no ontology of entities and metric types to absorb. If an engineer can write &lt;code&gt;SELECT ... FROM ... LEFT JOIN&lt;/code&gt;, they can define cubes. A first cube is realistically an evening's work, and the full path from installing the server to the first PivotTable in Excel takes about an hour.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reviews work like regular code reviews.&lt;/em&gt; The diff of a definition reads at a glance; the reviewer sees actual SQL, not a description of SQL.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;No hidden magic.&lt;/em&gt; The queries XLTable sends to the database are exactly the ones written in the definition, plus aggregation over the fields the user selected. Turn on logging — and you see every generated query.&lt;/p&gt;

&lt;p&gt;A fair objection at this point: aren't the comment tags themselves a DSL? They are — any convention is. The difference is where that DSL lives. Strip every tag from an XLTable definition and the host language still executes: what remains is a valid SELECT. The surface area is a dozen tags, not an ontology of entities and four kinds of metrics. And validation doesn't depend on a proprietary compiler — the database checks the query, and XLTable checks the tags.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anatomy of a cube
&lt;/h2&gt;

&lt;p&gt;Let's walk through what a definition consists of — with examples, each of which, remember, can be executed as is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measures&lt;/strong&gt; are the numbers the business wants to count. A measure is an aggregate function, an alias, and optional display tags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--olap_source Sales&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
&lt;span class="c1"&gt;--olap_measures&lt;/span&gt;
 &lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sales_sum_qty&lt;/span&gt; &lt;span class="c1"&gt;--translation=`Sales Quantity` --format=`#,##0;-#,##0`&lt;/span&gt;
&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sales_sum_sum&lt;/span&gt; &lt;span class="c1"&gt;--translation=`Sales Amount`   --format=`#,##0.00;-#,##0.00`&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stores&lt;/span&gt; &lt;span class="n"&gt;stores&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;translation&lt;/code&gt; tag sets the name the user sees in the Excel field list; &lt;code&gt;format&lt;/code&gt; sets the numeric format in the PivotTable. Everything sits on the same line as the measure itself — the definition and its metadata never drift apart into separate files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dimensions&lt;/strong&gt; are the context of analysis: stores, regions, products, time. Syntactically they mirror measure groups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--olap_source Stores&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
&lt;span class="c1"&gt;--olap_dimensions&lt;/span&gt;
 &lt;span class="n"&gt;stores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;stores_id&lt;/span&gt;
&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;stores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store_name&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;stores_name&lt;/span&gt; &lt;span class="c1"&gt;--translation=`Store`&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stores&lt;/span&gt; &lt;span class="n"&gt;stores&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Hierarchies&lt;/strong&gt; are parent-child relationships between attributes, so a user can drill from year to day in one click. Four tags — and the hierarchy is done:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt; &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;year&lt;/span&gt;    &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;times_year&lt;/span&gt;    &lt;span class="c1"&gt;--hierarchy=`Dates`&lt;/span&gt;
&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quarter&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;times_quarter&lt;/span&gt; &lt;span class="c1"&gt;--hierarchy=`Dates`&lt;/span&gt;
&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;month&lt;/span&gt;   &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;times_month&lt;/span&gt;   &lt;span class="c1"&gt;--hierarchy=`Dates`&lt;/span&gt;
&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;day&lt;/span&gt;     &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;times_day&lt;/span&gt;     &lt;span class="c1"&gt;--hierarchy=`Dates`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Relationships&lt;/strong&gt; between measures and dimensions are not described with abstract types — they are written as ordinary, explicit LEFT JOINs. A dimension links to a measure group through a shared table alias: if the measure group contains &lt;code&gt;LEFT JOIN db.Stores stores&lt;/code&gt; and the dimension's source is &lt;code&gt;FROM db.Stores stores&lt;/code&gt;, XLTable connects them on that alias. The JOIN is visible to the naked eye — what is written is what runs.&lt;/p&gt;

&lt;p&gt;Special cases get clarifying tags. The most popular one in the ClickHouse world is &lt;code&gt;one-table&lt;/code&gt;, for denormalized tables where measures and dimensions live in one wide table and no real JOIN is needed. There is &lt;code&gt;many-to-many&lt;/code&gt; for classic many-to-many relationships (several managers assigned to one store) and &lt;code&gt;part-source&lt;/code&gt; for helper lookup tables that are needed inside a single source but should not become part of the cube.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Calculated fields&lt;/strong&gt; are virtual measures built on top of other measures — including measures from different measure groups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--olap_cube&lt;/span&gt;
&lt;span class="c1"&gt;--olap_calculated_fields Calculated fields&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales_sum_qty&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="k"&gt;nullIf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stock_avg_qty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;turnover&lt;/span&gt; &lt;span class="c1"&gt;--translation=`Turnover`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here inventory turnover is computed from sales and average stock — two different fact tables. XLTable merges the per-group results with a FULL JOIN on its own; all the expression has to do is guard against division by zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security — in the same file, in the same syntax
&lt;/h2&gt;

&lt;p&gt;In a typical architecture, access rights live apart from the data model — in an admin panel, in separate configs, in the BI tool. In XLTable, a role is just another block of the same definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--olap_user_role&lt;/span&gt;
&lt;span class="c1"&gt;--olap_user_groups&lt;/span&gt;
&lt;span class="n"&gt;finance_users&lt;/span&gt;
&lt;span class="c1"&gt;--olap_measures_visible&lt;/span&gt;
&lt;span class="n"&gt;sales_sum_sum&lt;/span&gt;
&lt;span class="c1"&gt;--olap_dimensions_visible&lt;/span&gt;
&lt;span class="n"&gt;Stores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Regions&lt;/span&gt;
&lt;span class="c1"&gt;--olap_access_filters&lt;/span&gt;
&lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;`EU`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`NA`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A role defines which measures and dimensions a user group can see, and &lt;code&gt;olap_access_filters&lt;/code&gt; sets row-level security: the finance users in this example physically receive only rows for the EU and NA regions — the filter is baked into every SQL query the server generates for them. Groups come from Active Directory, so access is granted to directory roles rather than individuals — as it should be in the enterprise.&lt;/p&gt;

&lt;p&gt;Crucially, all of this is part of the same text definition. Permissions go through the same code review and live in the same git history as the model itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  When static isn't enough: Jinja
&lt;/h2&gt;

&lt;p&gt;Honesty requires an admission: we have templating too. Cube definitions support Jinja — for the cases where SQL has to change dynamically: relative dates ("last 30 days" from the current moment), conditional logic, swapping a table for a pre-computed aggregate for performance.&lt;/p&gt;

&lt;p&gt;The difference from the YAML approaches lies in the role the templating engine plays. There, the declarative layer is mandatory for every metric; here, Jinja is an optional add-on for the five percent of cases where plain SQL falls short. Our own documentation puts the recommendation plainly: use Jinja for small SQL adjustments and avoid complex logic. The core of the cube remains an executable SELECT.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the business gets
&lt;/h2&gt;

&lt;p&gt;The user-facing side of the story fits in one sentence: &lt;strong&gt;business users stay in Excel, and there is nothing to retrain them on.&lt;/strong&gt; No add-ins, no plugins, no "new, more convenient interface." A native PivotTable connects to XLTable the same way it has connected to Analysis Services for twenty years — while the data lives in ClickHouse, billions of rows deep.&lt;/p&gt;

&lt;p&gt;Two details users appreciate most.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Drillthrough.&lt;/strong&gt; Double-click any cell in the PivotTable — and Excel shows the underlying rows that produced that number: the individual receipts, dates, stores. All of the cell's filters and slicers apply, including row-level security — a user sees only the detail rows they are entitled to. For trust in the numbers, this beats any written policy: every figure can be opened up down to the raw records.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speed.&lt;/strong&gt; Query results are cached, so typical PivotTable work — rearranging fields, filtering, slicing — feels instant. The heavy lifting is done by the database itself: XLTable never copies data to its side; it translates Excel's MDX into optimized SQL. A read-only service account is all the server needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What IT gets
&lt;/h2&gt;

&lt;p&gt;The engineering side of the story is about transparency and control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic layer as code.&lt;/strong&gt; Cube definitions are plain SQL files. They live in Git, changes are reviewed in pull requests and deployed through the CI/CD flow your team already uses. No black-box UI with a graphical designer — the semantic layer lives in the repo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Everything is visible.&lt;/strong&gt; The &lt;code&gt;WRITE_LOG&lt;/code&gt; setting turns on logging of every SQL query the server generates for a user's specific field selection. An unexpected result or a slow query stops being a mystery: open the log and read the actual SQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Broken definitions never reach users.&lt;/strong&gt; The &lt;code&gt;definition_check_on&lt;/code&gt; tag enables mandatory validation of the definition before connecting to data: if the definition contains an error, the connection is refused and an error is returned — users never see a half-working cube.&lt;/p&gt;

&lt;p&gt;The practical workflow: run each block of the definition by hand in a database client (every block is an executable SELECT), enable definition checking, review the final queries in the log. Three steps, zero new tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Light footprint.&lt;/strong&gt; XLTable is a single service in front of your warehouse — no cube storage layer, no heavy infrastructure to babysit. It goes live in a day, not a six-month rollout — a direct answer to the "cost of adoption" from the beginning of this article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And finally, the perimeter: your data never leaves.&lt;/strong&gt; Most managed semantic layer offerings are cloud services: metadata, queries, and results pass through someone else's infrastructure. For a bank, a retailer handling personal data, or the public sector, that is often not a "downside" but a hard stop — compliance and data-residency requirements are not negotiable. XLTable pushes queries down to your warehouse — no extracts, no in-memory copies, no data shipped to anyone's cloud. It deploys on-premises, up to and including fully air-gapped environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  The semantic layer in the age of AI
&lt;/h2&gt;

&lt;p&gt;So far we've talked about two readers of a cube definition: the database that executes it and the human who writes and reviews it. In the last couple of years a third reader has appeared — the large language model. And for that reader, the executable SELECT principle turned out to matter more than we could have planned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI writes cube definitions — because they are just SQL.&lt;/strong&gt; Language models are trained on colossal amounts of SQL; for them, SQL is close to a native tongue. Ask an assistant to write an XLTable definition block and it will manage, because it's an ordinary SELECT with comments. Ask it to write a model in a proprietary YAML dialect and it will start hallucinating fields of a schema it saw a thousand times less often in training. A proprietary DSL is a barrier not only for humans, but for models too.&lt;/p&gt;

&lt;p&gt;The feedback loop works as well: the AI writes a block → the block is executed in the database → the error comes back as an ordinary SQL error → the AI understands it and fixes it. The loop closes using standard tools. With a YAML layer the loop breaks: the error comes from a vendor's compiler whose quirks the model somehow has to know.&lt;/p&gt;

&lt;p&gt;XLTable takes this a step further: it can generate a cube definition from your tables automatically — from raw schema to a working model in minutes — which you then refine in Git like any other code. And for hands-on work there's a practical trick: hand the assistant the entire XLTable documentation as a single file, and you get a genuine pair-designer for your cubes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI reads data through the semantic layer.&lt;/strong&gt; XLTable supports MCP (Model Context Protocol) — the open standard for connecting AI assistants to data. The assistant sees the same cube the Excel user sees: the same measures with human-readable names, the same dimensions, the same hierarchies. Instead of dragging fields with a mouse — a question in plain language: "show me sales by region for the last quarter versus a year ago."&lt;/p&gt;

&lt;p&gt;And because both interfaces read the same semantic layer, the numbers always agree: ask the chat for Q4 margin and you get exactly the figure your PivotTable shows. One model, two ways to explore, one number in the answer.&lt;/p&gt;

&lt;p&gt;This is where the semantic layer solves the central problem of the text-to-SQL approach. When a model writes SQL against a raw database schema, it is forced to guess: which column is revenue with VAT and which without, how to join facts to reference tables, what &lt;code&gt;amt_2&lt;/code&gt; means in table &lt;code&gt;t_sales_f&lt;/code&gt;. Every guess is a potentially confident wrong number. The semantic layer removes the guessing: metrics are already defined and named, relationships are already spelled out. The AI picks from a ready menu instead of inventing a recipe.&lt;/p&gt;

&lt;p&gt;And — the decisive point for the enterprise — &lt;strong&gt;security does not break&lt;/strong&gt;. The assistant goes through the same layer Excel does: the same roles, the same row-level security, the same read-only database access. The AI physically cannot show a user data they are not entitled to. And since XLTable lives inside your perimeter, the entire AI scenario runs without data leaving the boundary — even the AI interface can run on locally hosted models, no cloud APIs required.&lt;/p&gt;

&lt;h2&gt;
  
  
  One file, three readers
&lt;/h2&gt;

&lt;p&gt;Let's sum up. A semantic layer does not have to be a separate platform with its own modeling language, compiler, and learning curve. It can be a SQL file — one that can be read, executed, and version-controlled.&lt;/p&gt;

&lt;p&gt;A cube definition in XLTable is equally legible to three very different readers. &lt;strong&gt;The database&lt;/strong&gt; — because every block runs as is. &lt;strong&gt;The human&lt;/strong&gt; — because it's SQL the data team already knows, with no new system of concepts. &lt;strong&gt;The AI&lt;/strong&gt; — because a model can both write such definitions fluently and query data through them, losing neither the semantics nor the access controls.&lt;/p&gt;

&lt;p&gt;And business users never see any of these layers at all. They open Excel, refresh the PivotTable, and get numbers that agree.&lt;/p&gt;

&lt;p&gt;Don't take our word for any of this. Take a sample dataset, define the same metric both ways, and see which one you'd rather debug, review, and hand to an AI.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;You can try it in about an hour: the &lt;a href="https://xltable-olap.readthedocs.io/en/latest/quickstart.html" rel="noopener noreferrer"&gt;Quickstart&lt;/a&gt; walks you from installing the server to your first PivotTable, and ready-made sample datasets are available for all eight supported databases — from ClickHouse to DuckDB. Documentation: &lt;a href="https://xltable-olap.readthedocs.io" rel="noopener noreferrer"&gt;xltable-olap.readthedocs.io&lt;/a&gt;. Questions: &lt;a href="mailto:help@xltable.com"&gt;help@xltable.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Excel Is Still the #1 Self-Service Analytics Tool. Here's Why That's Not a Problem Anymore.</title>
      <dc:creator>XLTable</dc:creator>
      <pubDate>Tue, 09 Jun 2026 14:12:52 +0000</pubDate>
      <link>https://dev.to/xltable/excel-is-still-the-1-self-service-analytics-tool-heres-why-thats-not-a-problem-anymore-32i0</link>
      <guid>https://dev.to/xltable/excel-is-still-the-1-self-service-analytics-tool-heres-why-thats-not-a-problem-anymore-32i0</guid>
      <description>&lt;h1&gt;
  
  
  Excel Is Still the #1 Self-Service Analytics Tool. Here's Why That's Not a Problem Anymore.
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Your company just renewed its Tableau license. Your analysts just exported the data to Excel.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This scene plays out in nearly every enterprise analytics department in the world. And yet, IT leaders keep funding BI platforms, training programs, and data governance initiatives — while business users quietly keep opening spreadsheets.&lt;/p&gt;

&lt;p&gt;This isn't a failure. It's a signal. And understanding what it means is the key to building an analytics stack that people actually use.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Self-Service Analytics Actually Means
&lt;/h2&gt;

&lt;p&gt;Self-service analytics refers to the ability of business users — not data engineers or BI developers — to independently access, explore, and analyze data without submitting a ticket to IT.&lt;/p&gt;

&lt;p&gt;The market has taken notice. Analysts estimate the global self-service analytics market was valued at roughly $5–6 billion in 2024, growing at a CAGR of ~16% toward a potential $17–27 billion by the early 2030s. The growth is real. But it masks a more nuanced picture on the ground.&lt;/p&gt;

&lt;p&gt;For CTOs and IT directors, the promise of self-service is compelling: fewer bottlenecks, faster decisions, reduced dependency on data teams. The challenge is delivering on that promise without creating a mess of shadow reports and disconnected data sources.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Landscape: A Quick Map of the Tools
&lt;/h2&gt;

&lt;p&gt;There are five broad categories of tools that compete — and coexist — in the self-service space:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Spreadsheets (Excel, Google Sheets)&lt;/strong&gt; — The original self-service layer. Every business user already knows them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern BI platforms (Power BI, Tableau, Looker)&lt;/strong&gt; — Visualization-first tools with strong governance features and growing AI capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedded analytics (Metabase, Redash)&lt;/strong&gt; — Lightweight, often open-source, embedded inside applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Headless BI / semantic layer (dbt Metrics, Cube.dev)&lt;/strong&gt; — Code-first approaches to defining business logic independently of visualization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OLAP servers (Microsoft Analysis Services, XLTable)&lt;/strong&gt; — Traditional and modern cube-based engines that sit between databases and analytics clients.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each category has genuine strengths. The problem is that organizations often treat them as competitors when they are more naturally complements.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Excel Paradox
&lt;/h2&gt;

&lt;p&gt;Let's be direct: Excel is not going away. Over 200 million enterprise users are licensed on Microsoft 365 globally. More than 1.3 million companies in the US alone use it. It is the most widely declared skill on LinkedIn among corporate professionals, ranging from 17% to 32% penetration depending on job function.&lt;/p&gt;

&lt;p&gt;And yet, the standard narrative in enterprise IT is that Excel is a legacy tool — a crutch for users who haven't been properly trained on "real" analytics platforms.&lt;/p&gt;

&lt;p&gt;This framing is wrong, and it's causing expensive mistakes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Executives don't use Tableau to build their Monday morning model. They use Excel. That's not a training problem. That's a product-market fit signal.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Excel's persistence isn't about inertia. It's about control. A pivot table in Excel is something a finance director can manipulate in real time, in a meeting, with no dependency on a dashboard developer. The cognitive overhead is near zero. The flexibility is near infinite.&lt;/p&gt;

&lt;p&gt;The actual problem with Excel isn't Excel. It's the data feeding it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Real Bottleneck: Data Access, Not the Spreadsheet
&lt;/h2&gt;

&lt;p&gt;When analysts export from Snowflake or ClickHouse into a CSV and then import it into Excel, two things go wrong:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The data is stale the moment it lands in the file.&lt;/li&gt;
&lt;li&gt;The analyst becomes a manual ETL pipeline — a job they weren't hired to do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where the architecture conversation needs to shift. The question isn't "How do we get users off Excel?" It's "How do we give Excel a live, governed connection to real data?"&lt;/p&gt;

&lt;p&gt;The answer exists and has for decades — it's called XMLA. It's the protocol that Microsoft built for exactly this scenario: connecting Excel PivotTables to analytical databases through a standardized interface. Analysis Services used it. Power BI uses it. And modern OLAP servers can expose it to any backend — ClickHouse, Snowflake, BigQuery, StarRocks, Databricks.&lt;/p&gt;

&lt;p&gt;When you connect Excel to a properly modeled OLAP cube, several things change simultaneously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Users get live data, not exports.&lt;/li&gt;
&lt;li&gt;Business logic (metrics, hierarchies, access rules) lives in one place — the semantic layer.&lt;/li&gt;
&lt;li&gt;Finance stays in Excel. IT controls the data.&lt;/li&gt;
&lt;li&gt;No SQL required for end users. No BI license required per seat.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What CTOs Should Actually Be Asking
&lt;/h2&gt;

&lt;p&gt;Most analytics infrastructure reviews focus on the wrong question: "Which BI tool should we standardize on?" A better set of questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Where does data actually get consumed?&lt;/strong&gt; Follow the spreadsheets, not the dashboards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What is the total cost of the export-import loop?&lt;/strong&gt; Count analyst hours, not just license fees.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do we have a semantic layer?&lt;/strong&gt; If business logic lives in reports rather than in a governed model, you have a governance problem regardless of which tool you use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Can our stack serve both technical and non-technical users from the same source of truth?&lt;/strong&gt; If the answer is "no," you are maintaining two parallel data cultures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What is the adoption rate of our BI investments?&lt;/strong&gt; If it's below 30%, the tool is not the answer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A modern analytics stack doesn't have to choose between Excel and BI. It can serve both — provided the data layer is properly architected.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Modern Answer: Embrace Excel, Fix the Data Layer
&lt;/h2&gt;

&lt;p&gt;Here is a practical architecture that resolves the Excel paradox without forcing users to abandon tools they trust:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build a semantic layer&lt;/strong&gt; on top of your analytical database. Define measures, dimensions, hierarchies, and access rules once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expose that layer via XMLA&lt;/strong&gt; so Excel connects natively — no plugins, no extensions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep BI tools for dashboards, alerts, and shared views.&lt;/strong&gt; They're excellent at that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let Excel do what Excel does:&lt;/strong&gt; ad-hoc analysis, financial modeling, executive reporting.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result is a stack where data governance and user freedom aren't in tension. IT owns the model. Business owns the analysis.&lt;/p&gt;




&lt;h2&gt;
  
  
  What About AI Chat? ChatGPT, Claude, and the "Just Ask" Trend
&lt;/h2&gt;

&lt;p&gt;There's a growing narrative that AI chat interfaces will replace both Excel and BI tools entirely. Users are already asking ChatGPT for dashboards and getting back static charts. The question CTOs are asking: is this the end of structured analytics?&lt;/p&gt;

&lt;p&gt;The honest answer is: AI chat and Excel are not competing for the same job.&lt;/p&gt;

&lt;p&gt;AI chat interfaces excel at one thing — answering a one-off question quickly. "What was our best-performing region last quarter?" works well in a chat window. But the moment you need that answer to be repeatable, auditable, consistent across departments, and connected to data that updates daily — chat alone falls short.&lt;/p&gt;

&lt;p&gt;Here's why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data is not live.&lt;/strong&gt; Users upload a CSV from yesterday. Tomorrow they upload a new one. The export-import loop moves from email to chat — but it's still a loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No single source of truth.&lt;/strong&gt; Every employee gets their own answer from their own data. Finance and Sales produce different numbers for the same metric.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No audit trail.&lt;/strong&gt; A CFO cannot sign off on a report generated by a language model without traceability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security.&lt;/strong&gt; Most enterprise data governance policies prohibit sending sensitive business data to external AI providers.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;AI chat is an interface for one-off questions. Excel and BI are the environment for repeatable, governed, auditable decisions. They are not competitors — they are built for different jobs.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But here is where the picture gets more interesting — and where the real opportunity lies.&lt;/p&gt;

&lt;p&gt;When an AI assistant connects directly to a live semantic layer via a protocol like MCP (Model Context Protocol), the equation changes entirely. Instead of answering from a stale uploaded file, an AI can query a live OLAP cube and return current, governed data — directly in the chat interface.&lt;/p&gt;

&lt;p&gt;This means the user gets the conversational experience they want, with the data integrity the organization requires. The AI becomes a natural language interface to the same semantic layer that powers Excel PivotTables and BI dashboards — not a replacement for it.&lt;/p&gt;

&lt;p&gt;For organizations building on a modern OLAP layer, this is not a threat. It is an additional channel — one that makes the investment in a proper semantic layer even more valuable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Self-service analytics is not a tool. It's a capability. And the most effective organizations build it around how their people actually work — not around how vendors think they should work.&lt;/p&gt;

&lt;p&gt;Excel is not the enemy of modern analytics. Ungoverned data is. Once you solve the data layer, the spreadsheet becomes a feature.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Stop trying to replace Excel. Start connecting it to something worth analyzing.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>excel</category>
      <category>olap</category>
      <category>bi</category>
    </item>
    <item>
      <title>XLTable + Snowflake: From Zero to Pivot Table in 15 Minutes</title>
      <dc:creator>XLTable</dc:creator>
      <pubDate>Sat, 04 Apr 2026 18:49:00 +0000</pubDate>
      <link>https://dev.to/xltable/xltable-snowflake-from-zero-to-pivot-table-in-15-minutes-1hdc</link>
      <guid>https://dev.to/xltable/xltable-snowflake-from-zero-to-pivot-table-in-15-minutes-1hdc</guid>
      <description>&lt;h1&gt;
  
  
  XLTable + Snowflake: From Zero to Pivot Table in 15 Minutes
&lt;/h1&gt;

&lt;p&gt;This guide shows how to connect Excel to Snowflake using XLTable — from creating sample tables to dragging measures into a Pivot Table.&lt;/p&gt;

&lt;p&gt;No custom data required. Everything runs on a free Snowflake trial account.&lt;/p&gt;




&lt;h2&gt;
  
  
  What You Will Build
&lt;/h2&gt;

&lt;p&gt;By the end of this guide you will have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Snowflake database with realistic sales and inventory data&lt;/li&gt;
&lt;li&gt;An OLAP cube named &lt;code&gt;myOLAPcube&lt;/code&gt; registered in XLTable&lt;/li&gt;
&lt;li&gt;A live Excel Pivot Table connected to Snowflake — no CSV exports, no BI tools&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Data Model Overview
&lt;/h2&gt;

&lt;p&gt;The sample script creates 8 tables in the &lt;code&gt;olap.public&lt;/code&gt; schema:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Table&lt;/th&gt;
&lt;th&gt;Rows&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Times&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;731&lt;/td&gt;
&lt;td&gt;Calendar: every day of 2023–2024&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Regions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Sales regions: North, South, East, West&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Managers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Sales managers linked to regions (many-to-many)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Stores&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Retail stores, each assigned to a region&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Models&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Product models (Alpha … Theta)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Sales&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3 000&lt;/td&gt;
&lt;td&gt;Transactions: store, model, date, quantity, amount&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Stock&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;Inventory snapshots: store, model, quantity on hand&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;olap_definition&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;OLAP cube definition read by XLTable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The relationships are straightforward: Sales and Stock facts join to Stores, Models, and the Times calendar. Stores belong to Regions, and Managers are linked to Regions in a many-to-many relationship.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Snowflake account (Trial or paid)&lt;/li&gt;
&lt;li&gt;A user with &lt;strong&gt;SYSADMIN&lt;/strong&gt; role or &lt;code&gt;CREATE DATABASE&lt;/code&gt; privilege&lt;/li&gt;
&lt;li&gt;A running virtual warehouse (e.g. &lt;code&gt;COMPUTE_WH&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;SnowSQL CLI installed, or access to Snowflake Worksheets&lt;/li&gt;
&lt;li&gt;XLTable server installed and running&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1: Run the SQL Script
&lt;/h2&gt;

&lt;p&gt;Download the script and run it against your Snowflake account:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://xltable-olap.readthedocs.io/en/latest/_downloads/74a3508ae69ac187b80106c3229a825c/snowflake_sample.sql" rel="noopener noreferrer"&gt;Download snowflake_sample.sql&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A — SnowSQL CLI&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;snowsql &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--accountname&lt;/span&gt; &amp;lt;your_account&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--username&lt;/span&gt;    &amp;lt;user&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dbname&lt;/span&gt;      olap &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--schemaname&lt;/span&gt;  public &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-f&lt;/span&gt; snowflake_sample.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Option B — Snowflake Worksheets&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Snowflake → Worksheets → + New Worksheet&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Paste the full script&lt;/li&gt;
&lt;li&gt;Select your warehouse&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Run All&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Verify the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;row_count&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;olap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tables&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;table_schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'PUBLIC'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see 8 tables with the row counts from the table above.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Configure XLTable
&lt;/h2&gt;

&lt;p&gt;Open &lt;code&gt;/usr/olap/xltable/setting/settings.json&lt;/code&gt; and add the Snowflake connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"SERVER_DB"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Snowflake"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"CREDENTIAL_DB"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;user&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;password&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"account"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your_account&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"warehouse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"COMPUTE_WH"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;"olap.public"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"USERS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"analyst"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"password123"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"USER_GROUPS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"analyst"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"olap_users"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;XLTable discovers cubes automatically from the &lt;code&gt;olap_definition&lt;/code&gt; table — no additional cube configuration needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Restart XLTable
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;supervisorctl restart olap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4: Connect Excel
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open Excel → &lt;strong&gt;Data → Get Data → From Database → From Analysis Services&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enter the server URL: &lt;code&gt;http://your_server_ip&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Log in with &lt;code&gt;analyst / password123&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;myOLAPcube&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Drag measures and dimensions onto the Pivot Table&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What the Cube Exposes
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;myOLAPcube&lt;/code&gt; cube provides the following fields out of the box:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measures&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sales Quantity&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;sum(sales.qty)&lt;/code&gt; across selected filters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sales Amount&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;sum(sales.sum)&lt;/code&gt; — revenue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sales last year Quantity&lt;/td&gt;
&lt;td&gt;Same query, dates shifted +1 year via Jinja&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sales last year Amount&lt;/td&gt;
&lt;td&gt;Revenue for the same period last year&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Average Stock Quantity&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;avg(stock.qty)&lt;/code&gt; per store and model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Turnover&lt;/td&gt;
&lt;td&gt;Calculated: Sales Quantity ÷ Average Stock Quantity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Dimensions&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Store ID / Store&lt;/td&gt;
&lt;td&gt;Individual retail locations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Region&lt;/td&gt;
&lt;td&gt;North · South · East · West&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manager&lt;/td&gt;
&lt;td&gt;Many-to-many with Region&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model&lt;/td&gt;
&lt;td&gt;Alpha … Theta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Year / Quarter / Month / Day&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Dates&lt;/code&gt; hierarchy with full drill-down&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  How the OLAP Cube Is Defined
&lt;/h2&gt;

&lt;p&gt;The cube definition lives inside the &lt;code&gt;olap_definition&lt;/code&gt; table as a SQL script with XLTable annotations. Each source section maps a SQL query to a set of measures or dimensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--olap_source Sales&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
&lt;span class="c1"&gt;--olap_measures&lt;/span&gt;
 &lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sales_sum_qty&lt;/span&gt; &lt;span class="c1"&gt;--translation=`Sales Quantity`&lt;/span&gt;
&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sales_sum_sum&lt;/span&gt; &lt;span class="c1"&gt;--translation=`Sales Amount`&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;olap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sales&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;olap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stores&lt;/span&gt; &lt;span class="n"&gt;stores&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;store&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;calendar&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;sales&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;date_sale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day_str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Year-over-year comparison is handled with a Jinja transformation — XLTable rewrites the date column at query time, no separate table or materialized view needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--olap_jinja&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;sql_text&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="k"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"salesly.date_sale"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nv"&gt;"TO_VARCHAR(DATEADD(YEAR, 1, TO_DATE(salesly.date_sale)), 'YYYY-MM-DD')"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Customising the Sample
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Extend the date range to 2025&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Times&lt;/code&gt; table generator, change the row count from 731 to 1096 (731 + 365), then update the cube filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;year_str&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'2023'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2024'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'2025'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Add more stores or models&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Extend the &lt;code&gt;VALUES&lt;/code&gt; lists in the &lt;code&gt;Stores&lt;/code&gt; / &lt;code&gt;Models&lt;/code&gt; sections and update the &lt;code&gt;MOD(..., 8)&lt;/code&gt; expressions in the Sales and Stock inserts to match the new total count.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use a different schema&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Replace every occurrence of &lt;code&gt;olap.public&lt;/code&gt; with your own database and schema, and update &lt;code&gt;"schema"&lt;/code&gt; in &lt;code&gt;settings.json&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Issues
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Database 'OLAP' does not exist&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run the first two statements manually before the rest of the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;olap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;USE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;olap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;Insufficient privileges&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Switch to a role that has the required privileges:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;USE&lt;/span&gt; &lt;span class="k"&gt;ROLE&lt;/span&gt; &lt;span class="n"&gt;SYSADMIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;Virtual warehouse is suspended&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Resume the warehouse before running the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="n"&gt;WAREHOUSE&lt;/span&gt; &lt;span class="n"&gt;COMPUTE_WH&lt;/span&gt; &lt;span class="n"&gt;RESUME&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;No cubes visible in Excel&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Verify the definition row exists and check that &lt;code&gt;USER_GROUPS&lt;/code&gt; in &lt;code&gt;settings.json&lt;/code&gt; includes &lt;code&gt;"olap_users"&lt;/code&gt; for the connecting user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;olap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;olap_definition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;Invalid account identifier&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;account&lt;/code&gt; field must use the Snowflake account locator format, e.g. &lt;code&gt;xy12345.eu-west-1&lt;/code&gt;. Find it in &lt;strong&gt;Snowflake UI → Admin → Accounts&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;One SQL script creates a complete, realistic data model in Snowflake&lt;/li&gt;
&lt;li&gt;XLTable reads the cube definition directly from the database — no YAML, no GUI&lt;/li&gt;
&lt;li&gt;Excel connects natively via XMLA, with no plugins or data exports&lt;/li&gt;
&lt;li&gt;Year-over-year and inventory turnover work out of the box&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;Download the sample script from the &lt;a href="https://xltable-olap.readthedocs.io/en/latest/snowflake_sample.html" rel="noopener noreferrer"&gt;XLTable documentation&lt;/a&gt; and follow the steps above.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://dev.to/"&gt;Get a 30-day XLTable trial&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://xltable-olap.readthedocs.io" rel="noopener noreferrer"&gt;Read the full documentation&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>snowflake</category>
      <category>excel</category>
    </item>
    <item>
      <title>XLTable: Bringing the OLAP Experience Back to Excel on Modern Data Warehouses</title>
      <dc:creator>XLTable</dc:creator>
      <pubDate>Thu, 29 Jan 2026 15:15:03 +0000</pubDate>
      <link>https://dev.to/xltable/xltable-bringing-the-olap-experience-back-to-excel-on-modern-data-warehouses-14i3</link>
      <guid>https://dev.to/xltable/xltable-bringing-the-olap-experience-back-to-excel-on-modern-data-warehouses-14i3</guid>
      <description>&lt;h1&gt;
  
  
  XLTable: Bringing the OLAP Experience Back to Excel on Modern Data Warehouses
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxriohqilmktj9kt1t6q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxriohqilmktj9kt1t6q.png" alt="XLTable architecture" width="643" height="359"&gt;&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: data has grown, but users haven’t
&lt;/h2&gt;

&lt;p&gt;Business users have always worked with data.&lt;br&gt;&lt;br&gt;
For many years, Excel was the primary tool for analysis, and it worked well as long as datasets were relatively small.&lt;/p&gt;

&lt;p&gt;Over time, data volumes have grown dramatically. Today, meaningful analytical work often requires knowledge of SQL, Python, and modern data warehouses. These technologies are far beyond the skill set of most business users.&lt;/p&gt;

&lt;p&gt;As a result, companies are forced to involve data engineers, analysts, or BI specialists even for simple analytical questions. This increases cost, slows down decision-making, and creates a gap between business questions and answers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Excel is still alive
&lt;/h2&gt;

&lt;p&gt;Despite countless predictions, Excel has not disappeared.&lt;/p&gt;

&lt;p&gt;The reason is simple: Excel is intuitive. Pivot tables allow users to explore data freely — choosing metrics, slicing by dimensions, drilling down, and rearranging reports on the fly.&lt;/p&gt;

&lt;p&gt;No BI tool has fully replicated this combination of flexibility, speed, and familiarity for a broad audience.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why BI tools did not replace Excel
&lt;/h2&gt;

&lt;p&gt;Modern BI tools such as Power BI, Looker Studio, or DataLens are powerful and well-designed. However, they have not become a true replacement for Excel in everyday analytical work.&lt;/p&gt;

&lt;p&gt;In practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reports are often predefined,&lt;/li&gt;
&lt;li&gt;ad-hoc analysis is limited,&lt;/li&gt;
&lt;li&gt;semantic models require maintenance by specialists,&lt;/li&gt;
&lt;li&gt;users lose the feeling of direct interaction with data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When business users want to explore data independently, they still turn to Excel.&lt;/p&gt;




&lt;h2&gt;
  
  
  OLAP was the right idea
&lt;/h2&gt;

&lt;p&gt;Many years ago, Microsoft took an important step by introducing OLAP technology.&lt;/p&gt;

&lt;p&gt;The idea was simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;data processing happens on a server,&lt;/li&gt;
&lt;li&gt;heavy computations are performed centrally,&lt;/li&gt;
&lt;li&gt;users work with data through Excel as a client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allowed business users to work with large datasets using familiar Excel pivot tables, while all complexity remained on the server side. OLAP dramatically improved accessibility of analytics.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why classic OLAP stopped evolving
&lt;/h2&gt;

&lt;p&gt;Traditional OLAP systems rely on pre-calculated cubes and aggregations. While this approach worked well in the past, it does not align with modern data architectures.&lt;/p&gt;

&lt;p&gt;At the same time, columnar databases and cloud data warehouses became dominant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ClickHouse&lt;/li&gt;
&lt;li&gt;BigQuery&lt;/li&gt;
&lt;li&gt;Snowflake&lt;/li&gt;
&lt;li&gt;Redshift&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These systems are extremely fast and scalable, but working with them still requires SQL, Python, or BI tools.&lt;/p&gt;

&lt;p&gt;As a result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OLAP provides the right user experience but is technologically outdated,&lt;/li&gt;
&lt;li&gt;modern data warehouses are powerful but inaccessible to most users.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The idea behind XLTable
&lt;/h2&gt;

&lt;p&gt;XLTable was created to bridge this gap.&lt;/p&gt;

&lt;p&gt;Our goal is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Give users the same experience they had with OLAP in Excel, but on top of modern columnar data warehouses.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Users should be able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;open Excel,&lt;/li&gt;
&lt;li&gt;connect to data,&lt;/li&gt;
&lt;li&gt;build pivot tables,&lt;/li&gt;
&lt;li&gt;work with measures and dimensions,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;without learning SQL or Python.&lt;/p&gt;




&lt;h2&gt;
  
  
  A short overview of OLAP principles
&lt;/h2&gt;

&lt;p&gt;OLAP is based on a multidimensional data model.&lt;/p&gt;

&lt;p&gt;Conceptually, data is represented as a multidimensional cube:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dimensions&lt;/strong&gt; define axes (time, products, customers, regions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measures&lt;/strong&gt; are stored in cube cells (revenue, quantity, average price)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a user asks a question like “revenue by year”, they select:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one measure (revenue),&lt;/li&gt;
&lt;li&gt;one dimension (year).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Excel pivot tables act as a client for OLAP systems, allowing users to arrange dimensions in rows and columns, apply filters, sorting, and drill-down operations.&lt;/p&gt;




&lt;h2&gt;
  
  
  OLAP vs columnar databases
&lt;/h2&gt;

&lt;p&gt;Classic OLAP systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;load data into cubes,&lt;/li&gt;
&lt;li&gt;pre-calculate aggregations,&lt;/li&gt;
&lt;li&gt;store results for fast access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Columnar databases work differently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;data is stored in raw, column-oriented form,&lt;/li&gt;
&lt;li&gt;aggregations are calculated on the fly,&lt;/li&gt;
&lt;li&gt;performance is achieved through compression, parallelism, and query optimization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern columnar systems are designed to compute analytical queries efficiently without pre-aggregation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Shifting computation to the database
&lt;/h2&gt;

&lt;p&gt;XLTable follows a simple principle:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;All heavy computation should happen inside the database.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of pre-calculating cubes, XLTable delegates aggregations and grouping to the underlying columnar database, using it exactly for what it was designed for.&lt;/p&gt;

&lt;p&gt;XLTable acts as a semantic and protocol layer, not as a compute engine.&lt;/p&gt;




&lt;h2&gt;
  
  
  Open OLAP standards: XMLA and MDX
&lt;/h2&gt;

&lt;p&gt;OLAP is an open technology.&lt;/p&gt;

&lt;p&gt;Besides Microsoft, OLAP servers have been implemented by multiple vendors such as Oracle and Hyperion. The ecosystem relies on two key standards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;XMLA (XML for Analysis)&lt;/strong&gt; — a protocol used by clients (such as Excel) to communicate with OLAP servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MDX&lt;/strong&gt; — a SQL-like query language for multidimensional data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When Excel works with an OLAP server, it sends XMLA requests containing embedded MDX queries.&lt;/p&gt;

&lt;p&gt;Microsoft published the XMLA specification, making it possible to implement compatible OLAP servers.&lt;/p&gt;




&lt;h2&gt;
  
  
  What XLTable actually is
&lt;/h2&gt;

&lt;p&gt;XLTable is a custom OLAP-compatible server that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;accepts XMLA requests from Excel over HTTP,&lt;/li&gt;
&lt;li&gt;translates MDX queries into SQL,&lt;/li&gt;
&lt;li&gt;executes them on modern data warehouses,&lt;/li&gt;
&lt;li&gt;returns results back to Excel in XMLA format.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From Excel’s perspective, XLTable behaves like a classic OLAP server.&lt;br&gt;&lt;br&gt;
From the database’s perspective, XLTable is a client that generates optimized SQL.&lt;/p&gt;




&lt;h2&gt;
  
  
  Defining the semantic model
&lt;/h2&gt;

&lt;p&gt;Any OLAP system requires a semantic model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;measures,&lt;/li&gt;
&lt;li&gt;dimensions,&lt;/li&gt;
&lt;li&gt;and mappings to source tables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Microsoft OLAP, this model is defined using graphical tools in Visual Studio.&lt;/p&gt;

&lt;p&gt;XLTable takes a different approach. The semantic model is defined using SQL-based configuration scripts.&lt;/p&gt;

&lt;p&gt;This approach is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;simpler and more transparent,&lt;/li&gt;
&lt;li&gt;easier to version and maintain,&lt;/li&gt;
&lt;li&gt;explicit in terms of generated SQL,&lt;/li&gt;
&lt;li&gt;important for performance and cost control, especially in systems like BigQuery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the model is defined, users simply connect to it from Excel.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key features of XLTable
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Fully proprietary, in-house development
&lt;/li&gt;
&lt;li&gt;All data processing happens inside the database (e.g. Snowflake)
&lt;/li&gt;
&lt;li&gt;Support for multiple measure groups, dimensions, and hierarchies in a single cube
&lt;/li&gt;
&lt;li&gt;Flexible caching strategies
&lt;/li&gt;
&lt;li&gt;LDAP / Active Directory integration
&lt;/li&gt;
&lt;li&gt;Fine-grained access control:

&lt;ul&gt;
&lt;li&gt;by measures,&lt;/li&gt;
&lt;li&gt;by dimensions,&lt;/li&gt;
&lt;li&gt;by dimension members
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Performance and scalability
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;XLTable does not perform aggregation or grouping itself
&lt;/li&gt;
&lt;li&gt;It receives MDX from Excel, translates it to SQL, and executes it in the database
&lt;/li&gt;
&lt;li&gt;This process requires minimal server resources
&lt;/li&gt;
&lt;li&gt;Performance depends entirely on database configuration, which aligns with columnar database design
&lt;/li&gt;
&lt;li&gt;Results can be cached at user or server level
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are no artificial limits on the number of dimensions or measure groups.&lt;/p&gt;

&lt;p&gt;A typical production configuration includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;~30 source tables
&lt;/li&gt;
&lt;li&gt;total data volume around 2 TB
&lt;/li&gt;
&lt;li&gt;individual tables with up to 2 billion rows
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What’s next
&lt;/h2&gt;

&lt;p&gt;In the next article, we will walk through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;installation,&lt;/li&gt;
&lt;li&gt;configuration,&lt;/li&gt;
&lt;li&gt;and the first connection from Excel to XLTable.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>excel</category>
      <category>dataengineering</category>
      <category>analytics</category>
      <category>datawarehouse</category>
    </item>
    <item>
      <title>Connect Snowflake to Excel Pivot Tables with XLTable</title>
      <dc:creator>XLTable</dc:creator>
      <pubDate>Sat, 03 Jan 2026 09:57:26 +0000</pubDate>
      <link>https://dev.to/xltable/connect-snowflake-to-excel-pivot-tables-with-xltable-34f8</link>
      <guid>https://dev.to/xltable/connect-snowflake-to-excel-pivot-tables-with-xltable-34f8</guid>
      <description>&lt;h1&gt;
  
  
  How to Connect Snowflake to Excel Pivot Tables (Without BI Tools or Data Exports)
&lt;/h1&gt;

&lt;p&gt;Excel is still the most popular analytics tool for business users.&lt;br&gt;&lt;br&gt;
Finance teams, sales managers, and executives rely on Excel Pivot Tables because they are fast, flexible, and familiar.&lt;/p&gt;

&lt;p&gt;At the same time, modern companies store analytical data in Snowflake — a cloud data platform built for large-scale analytics.&lt;/p&gt;

&lt;p&gt;Yet connecting &lt;strong&gt;Snowflake to Excel Pivot Tables&lt;/strong&gt; is still surprisingly difficult.&lt;/p&gt;

&lt;p&gt;Most teams rely on CSV exports, custom SQL queries, or heavy BI tools — all of which limit true self-service analytics.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explain &lt;strong&gt;how to connect Snowflake to Excel properly&lt;/strong&gt;, why exports don’t scale, and &lt;strong&gt;why OLAP is the missing layer&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Snowflake + Excel Gap
&lt;/h2&gt;

&lt;p&gt;Snowflake is excellent at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;large-scale analytics
&lt;/li&gt;
&lt;li&gt;elastic compute
&lt;/li&gt;
&lt;li&gt;centralized data storage
&lt;/li&gt;
&lt;li&gt;governance and security
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Excel is excellent at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ad-hoc analysis
&lt;/li&gt;
&lt;li&gt;Pivot Tables
&lt;/li&gt;
&lt;li&gt;business exploration
&lt;/li&gt;
&lt;li&gt;fast decision making
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But in many companies, these tools don’t work together smoothly.&lt;/p&gt;

&lt;h3&gt;
  
  
  A typical workflow today
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Analyst writes SQL in Snowflake
&lt;/li&gt;
&lt;li&gt;Exports data to CSV or Excel
&lt;/li&gt;
&lt;li&gt;Sends files to business users
&lt;/li&gt;
&lt;li&gt;Filters change, numbers drift
&lt;/li&gt;
&lt;li&gt;Trust is lost
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This workflow does &lt;strong&gt;not scale&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why CSV Exports from Snowflake Do Not Scale
&lt;/h2&gt;

&lt;p&gt;Exporting data from Snowflake may look simple, but it creates serious problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No live data
&lt;/li&gt;
&lt;li&gt;Manual refreshes
&lt;/li&gt;
&lt;li&gt;Multiple versions of truth
&lt;/li&gt;
&lt;li&gt;Broken security model
&lt;/li&gt;
&lt;li&gt;No semantic layer
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most importantly, &lt;strong&gt;business users don’t want raw tables&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
They want &lt;strong&gt;Pivot Tables&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why BI Tools Are Often Too Heavy
&lt;/h2&gt;

&lt;p&gt;Power BI, Tableau, Looker, and similar tools solve some problems — but create others:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;per-user licensing costs
&lt;/li&gt;
&lt;li&gt;additional infrastructure
&lt;/li&gt;
&lt;li&gt;dashboards instead of exploration
&lt;/li&gt;
&lt;li&gt;another UI to learn
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many companies discover a frustrating reality:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After dashboards are built, users still export data to Excel.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  What Excel Pivot Tables Actually Need
&lt;/h2&gt;

&lt;p&gt;Excel Pivot Tables do not work well with raw SQL tables.&lt;/p&gt;

&lt;p&gt;They expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dimensions and measures
&lt;/li&gt;
&lt;li&gt;hierarchies
&lt;/li&gt;
&lt;li&gt;aggregations
&lt;/li&gt;
&lt;li&gt;metadata
&lt;/li&gt;
&lt;li&gt;a semantic layer
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly what &lt;strong&gt;OLAP&lt;/strong&gt; provides.&lt;/p&gt;




&lt;h2&gt;
  
  
  OLAP as the Missing Layer for Snowflake
&lt;/h2&gt;

&lt;p&gt;OLAP sits between &lt;strong&gt;Snowflake&lt;/strong&gt; and &lt;strong&gt;Excel&lt;/strong&gt;, translating analytical data into a structure Excel understands.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture: Snowflake → OLAP → Excel
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyuyjvsvy7wcgi5ggtk99.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyuyjvsvy7wcgi5ggtk99.png" alt="Snowflake to Excel OLAP architecture" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How XLTable Fits Into This Architecture
&lt;/h2&gt;

&lt;p&gt;This Snowflake → OLAP → Excel architecture is exactly what &lt;strong&gt;XLTable&lt;/strong&gt; is built for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;XLTable&lt;/strong&gt; is an OLAP server designed to sit between Snowflake and Excel, providing a semantic layer that Excel Pivot Tables can work with natively.&lt;/p&gt;

&lt;p&gt;Instead of exporting data or building dashboards, XLTable allows business users to connect directly to Snowflake using familiar Excel Pivot Tables — while all data, logic, and governance remain in Snowflake.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key principles behind XLTable
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Snowflake stays the single source of truth
&lt;/li&gt;
&lt;li&gt;Business logic is defined once, centrally
&lt;/li&gt;
&lt;li&gt;Excel users work with Pivot Tables, not SQL
&lt;/li&gt;
&lt;li&gt;No CSV exports or data duplication
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What XLTable Provides
&lt;/h2&gt;

&lt;p&gt;XLTable implements this architecture as a production-ready OLAP layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OLAP cubes on top of Snowflake
&lt;/li&gt;
&lt;li&gt;Native Excel Pivot Table connectivity via XMLA
&lt;/li&gt;
&lt;li&gt;Centralized definitions for measures and dimensions
&lt;/li&gt;
&lt;li&gt;Secure, read-only access to analytical data
&lt;/li&gt;
&lt;li&gt;Scalable query generation optimized for Snowflake
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From the Excel user’s perspective, nothing changes — they simply connect to a cube and start building Pivot Tables.&lt;/p&gt;

&lt;p&gt;From the data team’s perspective, calculations, access rules, and performance are finally under control.&lt;/p&gt;




&lt;h2&gt;
  
  
  Typical Use Cases for XLTable
&lt;/h2&gt;

&lt;p&gt;XLTable is commonly used when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finance teams need live P&amp;amp;L or revenue analysis in Excel
&lt;/li&gt;
&lt;li&gt;Sales teams analyze performance by region, product, or customer
&lt;/li&gt;
&lt;li&gt;Operations teams explore large datasets without waiting for dashboards
&lt;/li&gt;
&lt;li&gt;Data teams want to reduce BI license and maintenance costs
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In all cases, Snowflake remains the backend — Excel becomes the interface.&lt;/p&gt;




&lt;h2&gt;
  
  
  Excel Is Still a BI Tool — When Connected Correctly
&lt;/h2&gt;

&lt;p&gt;Excel is not outdated.&lt;/p&gt;

&lt;p&gt;Disconnected Excel is.&lt;/p&gt;

&lt;p&gt;When Excel works directly with Snowflake through an OLAP layer, it becomes a powerful, scalable analytics interface.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CSV exports from Snowflake don’t scale
&lt;/li&gt;
&lt;li&gt;BI tools are often heavier than needed
&lt;/li&gt;
&lt;li&gt;Excel Pivot Tables require a semantic layer
&lt;/li&gt;
&lt;li&gt;OLAP bridges Snowflake and Excel
&lt;/li&gt;
&lt;li&gt;XLTable provides this missing layer
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  See Snowflake Analytics in Excel with XLTable
&lt;/h2&gt;

&lt;p&gt;If your company uses Snowflake and Excel is still the primary analytics tool for business users, XLTable provides the missing connection between them.&lt;/p&gt;

&lt;p&gt;You don’t replace Snowflake.&lt;br&gt;&lt;br&gt;
You don’t replace Excel.  &lt;/p&gt;

&lt;p&gt;You simply connect them correctly.&lt;/p&gt;

</description>
      <category>excel</category>
      <category>snowflake</category>
      <category>olap</category>
      <category>analytics</category>
    </item>
  </channel>
</rss>
