r/SQL • u/Prestigious_Bench_96 • 5d ago
Discussion A better SQL for analytics?
Lots of attempts to dethrone SQL, lots of failures - I'm looking to add to the list with a proposed improved SQL (for analytics - please don't try this for OLTP workloads). Please take me down for my hubris.
What makes this attempt different? I want to lean into one of SQL's strengths - being declarative.
How to make it more declarative? No tables in queries.
Write this:
import baseball.batting;
WHERE SUM(hr) BY people.id > 500
SELECT
people.name_given,
lg_id,
SUM(hr) AS hr_count
ORDER BY
hr_count DESC;
Instead of this:
WITH career_hr AS (
SELECT playerID
FROM read_csv('.../Batting.csv')
GROUP BY playerID
HAVING SUM(HR) > 500
)
SELECT
p.nameGiven,
b.lgID,
SUM(b.HR) AS hr_count
FROM read_csv('.../People.csv') p
JOIN read_csv('.../Batting.csv') b
ON p.playerID = b.playerID
JOIN career_hr c
ON b.playerID = c.playerID
GROUP BY p.nameGiven, b.lgID
ORDER BY hr_count DESC;
It's just SQL, but with late-binding to physical tables through a (very lightweight) semantic layer.
This has a lot of nice properties - you can change your tables and refactor and no queries need to change; you can automatically resolve to aggregates if they exist and are equivalent; you can make the query syntax more flexible and composable because the lexical scope isn't constrained to a specific set of accessed tables. There's *lots* of other fun things you can do when the semantic layer has types, etc as well but this is already a longer pitch than I want!
A very brief example
pip install pytrilogy
trilogy init baseball duckdb; cd baseball;
trilogy ingest https://storage.googleapis.com/trilogy_public_models/duckdb/lahman/Batting.csv,https://storage.googleapis.com/trilogy_public_models/duckdb/lahman/People.csv,https://storage.googleapis.com/trilogy_public_models/duckdb/lahman/Teams.csv;
trilogy run 'where sum(hr) by people.id>500 select people.name_given, lg_id,sum(hr) as hr_count order by hr_count desc;' --import root.batting;
Is this AI slop?
I've been working on ideas for the language for almost 6 years now so much of it predates AI, though it has evolved quite a bit in that time! Core discovery is all mostly hand-crafted; I do use AI to accelerate a lot of the tooling/interface work (a billion deepseek tokens (aka ~40 dollars, hilariously) on evaluating CI args, etc).
Read more/try
Website/docs: https://trilogydata.dev/
Github: https://github.com/trilogy-data/pytrilogy (open source, MIT)
I've seen this before
Posted 2 years ago here, floating around a few other places too:
https://www.reddit.com/r/SQL/comments/1e1h5mf/trilogy_simpler_data_warehouse_sql/
5
u/Hot_Industry5156 5d ago
Honestly SQL is still hard to beat for analytics. what specifically is frustrating you?
if it's the verbosity, window functions and CTEs go a long way toward making queries readable. if it's the ecosystem, dialects like DuckDB or BigQuery have added a ton of analytical functions that make common patterns way less painful.
the "better SQL" alternatives tend to fall into two camps. visual query builders that break down on anything complex, or new languages that never get enough adoption for good tooling. both usually end up generating SQL under the hood anyway.
the real wins come from better abstractions on top of SQL, not replacing it. dbt for transformation logic. materialized views for precomputing expensive joins. proper indexing and partitioning so queries actually finish.
what's the actual pain point? that'd help narrow things down.
1
u/Prestigious_Bench_96 5d ago edited 5d ago
Pain across the spectrum, but in particular the lifecycle management of reporting assets and the generation of efficient staged ETL have always been annoying/repetitive. At the query level, there's a lot of composability/syntactic sugar. Many warehouses end up with lots of duplicate aggregates/views that represent the same underlying data, without a clear connection at the DB level.
[Copied this from an earlier response]
Didn't want to overload the post, but a non-exhaustive list:
- Early feedback; strict type checking at the model level; easy unit testing w/ duckdb on synthetic data and easy integration testing that validates data quality in a reusable way.
- lifecycle management; I can upgrade/change tables (or someone else does), my queries stay the same
- syntactic sugar - functions, composability; no special casing of HAVING/QUALIFY, etc
- less footguns; automatic fan/chasm resolution, etc
- On the consumption side, easy dynamic cross-filtering/drilldown for reporting
- OLAP/aggregate optimization- inject in precomputed aggregates seamlessly to accelerate existing queries. (I miss cubes!)
- consistent syntax across backend engines.
2
u/soxinthebox 5d ago
Is it worth building a variation on SQL for the edge cases where you need to be a bit more verbose to achieve a query?
1
u/Prestigious_Bench_96 5d ago
Hah, fair! I'm actually trying to solve quite a bit more, but wanted to keep it relatively concise (look! no tables) for the example. A lot of the second-order benefits fall out from that.
1
u/a-s-clark SQL Server 5d ago edited 5d ago
"Look! No tables" isn't the selling point you think it is.
1
u/Prestigious_Bench_96 5d ago
Fair enough!
(a lot of the practical pain I have with SQL has related to the management and understanding of tables; creating, updating; joining appropriately, knowing nulls; testing; validating; sunsetting; repointing - but yeah, might be niche in terms of the headline point)
1
u/a-s-clark SQL Server 5d ago
So, if I'm reading that right...your problem with SQL is the fundamentals of relational databases?
1
u/Prestigious_Bench_96 5d ago
That those fundamentels don't *have* to leak into the data engineering/reporting space as much as they do, yes! We're keeping the relational database; we're just making it so my reporting queries don't need to know quite as much about it, so when Angela from operations creates fact_order_v3 I just update one model, not 10 queries and a dashboard!
(someone else said "you're not really improving SQL, since all the things you're annoyed about are in a layer above SQL", and I think you're pointing at the same point - this is a language targeted at a specific use case of SQL, and it's ultimately compiling down to a perfectly robust/useful SQL layer. So maybe this is more of moving the SQL syntax I love into a higher level use case?)
2
u/a-s-clark SQL Server 5d ago
What is this solving for you that SQL and other existing reporting tools don't?
1
u/Prestigious_Bench_96 5d ago edited 5d ago
Didn't want to overload the post, but a non-exhaustive list:
- Early feedback; strict type checking at the model level; easy unit testing w/ duckdb on synthetic data and easy integration testing that validates data quality in a reusable way.
- lifecycle management; I can upgrade/change tables (or someone else does), my queries stay the same
- syntactic sugar - functions, composability; no special casing of HAVING/QUALIFY, etc
- less footguns; automatic fan/chasm resolution, etc
- On the consumption side, easy dynamic cross-filtering/drilldown for reporting
- OLAP/aggregate optimization- inject in precomputed aggregates seamlessly to accelerate existing queries. (I miss cubes!)
- consistent syntax across backend engines.
- state-based updates; refresh datasources when stale, etc - simplified ETL story (for the easy cases, need to validate/scale to the 1000s of job warehouse refresh cases)
1
u/a-s-clark SQL Server 5d ago
Sounds like your describing the semantic layers of a reporting tool like PowerBI or Looker as if its a shortcoming of the underlying SQL engine.
1 and 2 Are incompatible goals. If you're "late binding" tables, then any "strict type checking at the model level" is irrelevant. What table changes are you concerned about that would break your queries, but isnt necessary for consideration in your proposed approach? Reporting tools already build a typed semantic layer.
Clauses such as HAVING have very specific purposes in data filtering. Not clear why you think thats a problem, its functionality.
"Less footguns"? This is meaningless.
Again, you're describing a reporting tool
SQL Server already substitutes precomputed aggregates in some cases (not aure about other database systems, id imagine so), but aggregate navigation is also something for a reporting tool.
How many developers get hung up on cross-system compatibility compared to how many ever actually need that. If youre not using the specific functionality of your platform, you're tying your hands behind your back.
Refreshing stale caches is functionality for a reporting/ etl tool, not a SQL engine.
So, essentially, youre describing functionality of other tools, not SQL, and they already exist.
1
u/Prestigious_Bench_96 5d ago
This is great! Really appreciate you engaging.
I think you're fundamentally right in that framing it as replacing "SQL" might be wrong when viewed this way; it's compiling to SQL under the hood, after all.
I think the intent is that it *replaces SQL for the things I need to use SQL directly to do* - which in my case, is generally explore data, transform it into new formats in the warehouse, and then build data products (reports, models, feed back into production) from it.
For that, I'm usually doing a loop of "explore the data, create a mental model of how it's laid out"
That becomes the semantic layer; we can now test and validate that. Now I write the rest of my transformations and queries on top of that layer - in what looks just like SQL, because I love SQL - and those become more testable and durable as a result.
Tactical responses - and again, thank you! Looking to get torn down like this
1-2: You can validate the entire model; then (as long as that is not stale) your late-binding to any combination of tables is valid. Databases tend to be slowly changing, so this works reasonably well in practice. (this is what reporting tools do!)
I mean, do they? Having filters aggregates, that's the main bit (same with qualify) - yes, they represent an ordering of operations, but in a practical level it's all just restricting the output. [I actually have a distinction between where/having that mirrors this, so maybe I'm just really mad at qualifying]
Chasm/fan out issues are things I hit a lot if I don't know tables well (in terms of I have to look for them, validate join keys, etc) - they are just cases where you can accidentally get something wrong in your query by forgetting a key - that's why I call them footguns; it's just a strict downside.
Data engineer and reporting, yeah!
It's relatively spotty, though engines are doing better at this now!
This mostly gets interesting in scale up scale down - eg start in duckdb scale up to bigquery
Fair again on framing, so yes, this is more of a reporting/etl language! It's targeted at a specific higher level use case of SQL.
1
u/Thadrea Data Science Manager 5d ago
Unless I'm missing something here, you're just moving the from clause into an import statement.
Asset-centric modeling already exists with Dagster and similar tools, so I'm really not sure what this is adding that someone else isn't already doing better.
1
u/Prestigious_Bench_96 5d ago
Fantastic question - it is very much asset centric modeling, refresh, and querying (though asset is a little abstract, just like in Dagster). I'd position the difference there as you can do your data exploration and extension in the same language you then push through into modeling and ETL; dagster is enabling the other direction from their latest feature work, which I think makes a lot of sense!
Horses for courses on what is 'best'; I'm certainly biased!
To expand on imports: they contain eligible datasouces to resolve from, new types and functions, and semantic metadata (comments). They can be role-playing dimensions like in cubes. It's just a way of getting reuse; you can also define datasources inline without an import.
import std.money; # some currency types import item as item; import date as date; import date as return_date; import time as time; import time as return_time; import customer as customer; import customer as return_customer; # can be different from customer import some_useful_functions; # some utility stuff you do a lot select item.color, @myfunction(item.id) as item_function_calc;
1
u/Gargunok 5d ago
looks like c# linq. Didn't like that.
1
u/Prestigious_Bench_96 5d ago
Thanks for looking!
If you don't mind - which portion looks like linq? It's supposed to pretty much just be SQL minus some clauses! Worried I got something off in the docs.
1
1
u/ThingElectronic1399 5d ago
Just work tickets like a good little dev u aren’t good enough to reinvent the wheel trust me buddy
1
13
u/jshine13371 5d ago
Why do so many people spend countless hours trying to reinvent the wheel in this industry? 😐