Show HN: PreQL/Trilogy – A Higher-Level, Composable SQL (github.com)
Key features are: Reusability - semantic layer supports full reuse of calculations, CTEs, and even entire models through a lightweight python inspired import syntax. Simple - writing queries that combines data at different granularity is straightforward and avoids common error patterns. Easy to refactor - changing the way the semantic layer binds to the database doesn’t require you to rewrite your queries. You don’t need to codemod 100 ETL scripts to deprecate a table!
Related packages [basic, links available from https://preqldata.dev/]: pypreql-etl -> basic DBT integration. pypreql-nlp -> obligatory GenAI integration. trilogy-studio -> electron IDE for running queries directly. trilogy-public-models -> common repository of public models (mostly BQ public datasets right now) that can be imported/queried.
Differs from other approaches to make a modern SQL I’m aware of (links below) in that it attempts to embrace current SQL syntax, not replace it. Each of these linked projects has a distinct value proposition and is worth checking out on their own!
Note: as you can see by names in the space, it turns out that I was not nearly as creative as I hoped with ‘PreQL’ as a ‘prequel/sequel’ play; PreQL/Trilogy is the intermediate Star Wars pun and it may migrate to just Trilogy (after the sequel!) to avoid confusion.
Other SQL Replacements:
Malloy (full rewrite, semantic focus) https://news.ycombinator.com/item?id=30053860
PRQL (pipelined SQL alternative, all new syntax) https://news.ycombinator.com/item?id=36866861
preql (much more ambitious, all new syntax) https://news.ycombinator.com/item?id=26447070
Things to do: - Define/implement better null handling - Rewrite some parsing/CLI in rust - More functions/backends, more window flexibility - Performance hooks/optimization
5 comments
[ 4.5 ms ] story [ 21.7 ms ] threadSimilarly, the "Concepts" section of the documentation has a diagram about joins, but no code examples.
On a more-technical note, the generated queries seem to use a LOT of CTEs. While they aren't a strict optimization barrier in PG anymore, there are definitely situations where they'll fall back to materialization - and the generated SQL seems to commonly build a "all of the rows" CTE and then apply conditions in a subsequent one.
Re: the structure - yeah, it's a lot of CTEs right now as that's the easiest way to guarantee correctness - I want to implement a optimization pass that will do some consolidation + predicate pushdown, but it's a balance with readability.
Is this somewhere well defined? Are there docs explaining how it works?
This part of the language seems the most magic to me, and I've found a few times now that things that feel like magic work great, but only 80% of the time.
The "datasources and joins" section attempts to cover this but I think I need to clean that up a bit!
As long as the semantic bindings are accurate, this can be a performance optimization - ex if it's a reporting query and there's an aggregate dataset that's available that can be safely used.
That's where the challenges will come up - there needs to be easy tooling to vet consistency across datasources (all these tables have the same # of orders) to validate the model, and I'm planning some form of query-level time/refresh hint (as of at least <x> date?) to help avoid resolving stale caches/consistency. These challenges should be pretty similar to what you'd get with plain SQL and the semantic layer hopefully makes the quality checks easier, so I'm optimistic that the tooling can help out here as well.
Ex: this binding from the hello world example says "this is a valid source for the sentence_id", and technically any of the 3 datasources could provide it. (the datasource here is a query not a table for portability)