Show HN: PRQL in PostgreSQL (github.com)
This extension let's you write PRQL functions in PostgreSQL.
When I first saw PRQL on Hacker News a few months ago, I was immediately captivated by the idea, yet equally disappointed that there was no integration for PostgreSQL. Having previous experience with writing PostgreSQL extensions in C, I thought this was a great opportunity to try out the pgrx framework and decided to integrate PRQL with PostgreSQL myself.
The maintainers of both PRQL and pgrx were very nice to work with. Thanks guys.
141 comments
[ 7.8 ms ] story [ 235 ms ] threadI don't think it's suggested that this replaces SQL. Use the right tool (and abstraction) for the job?
It's like complaining that you have to know the variable name you're going to assign something to before you start writing the expression that will set the value.
The idea is to evaluate the expression and store it, but the expression doesn't actually read that way left-to-right. Wouldn't it make more sense for it to be: Technically, that's written more in execution order. In practice it just isn't that big of a deal. It only trips up beginners.Short answer: DX
Slightly longer answer: Developer productivity and experience, especially for EDA and interactively writing complex analytical queries.
Most people that have tried PRQL just find it more convenient to write their analytical queries in it. PRQL compiles to SQL so it can't express anything you can't already do in SQL, but you can probably express yourself much faster in PRQL.
Just try the following query in the online PRQL Playground (https://prql-lang.org/playground/) to find the longest track per album:
```prql
from tracks
group album_id (
```How long would it take you to write the SQL for that?
Disclaimer: I'm a PRQL contributor.
It might be that the question was "the longest track across all albums" which indeed would require a LIMIT
A standard* method would be:
But the QUALIFY clause is so new that it doesn't work on most RDBMSs. If you're on MS SQL Server, you're still using: That said, I still don't think PRQL is particularly amazing. I can't tell if it's merely syntactic sugar for SQL, or if it's actually meant to control query execution. If it's the former, it's likely to frustrate developers because it's actually just another layer of abstraction. If it's the latter, then it requires the developer to not only understand the data model well enough to be able to write SQL queries, they need to be able to understand the RDBMS impementation details well enough to be able to write queries that best take advantage of the current database's indexes, statistics, and configuration. Even something as simple as sorting before filtering or projecting can be a significant performance issue. Nevermind the fact that relational algebra done in the wrong order can be non-deterministic or not equivalent transformations, so even if the query processor is smart enough to do rewrites whatever the developer enters might be logically different unintentionally.Ultimately I think it's a tool that lets the developer thinking about the problem in the way they prefer, rather than thinking about the problem in the way that best suits the problem at hand. Like insisting on writing documentation in LaTeX instead of Word or Markdown.
*: I believed this was in SQL 2023, but double checking it looks like it did not have make the final standard. I would be surprised if it didn't make it in the future, however.
And even then, it'll be another 6 years before your application vendor finally upgrades to it.
And even then, it'll be another 6 years before the database feature is allowed to be enabled.
And even then, your reporting software won't support it.
The bigger problem, is the "over use of tools to boost developers" the real problem, is putting poor developers into the pipeline. complex analytics is SQL is just simple, and lovely. The fact other struggle is not going to be helped by pretending the "code" looks more C like, they need to learn to think like a performant machine, and then be productive.
Since when is QUALIFY part of the SQL standard? So far I have only seen it as a proprietary feature in Terradata.
I don't want to appear rude, but unless I'm missing something, this is a pretty simple SQL query, of the kind anyone with mimimal SQL experience could write off the top of their head in seconds.
I like the idea of PRQL, but I think a better example is needed to sell it.
The same logic is applied to TypeScript vs JavaScript. Or C vs assembly. Or Nano vs vim. Etc etc.
It's a quandary though. SQL is clearly difficult for most people to get their heads around. It does require a different way of thinking about data, and you can get by with a minimal SQL knowledge for a long time, especially nowadays with ORMs.
But like so many other things, making the investment is worthwhile and pays off in small and large ways, forever (so far).
And... 'making the investment' takes time, and means that time is not able to be invested someplace else.
If the majority of your job is writing SQL or similar (data access, etc) then sure - yes, learn more of those tools. Some folks have a wider range of responsibilities that means you have to decide what to make more time investments in, and saying 'yes' to something is necessarily saying 'no' to other things.
But 20 hours spent learning SQL pays off for a lifetime. Most people watch more hours of TV than that per week.
We all make our choices, but very very few people could not find 20 hours somewhere in their lives, with zero net loss.
The problem this is resolving, if it successfully resolves anything at all, is that the SQL language is a mess of random keywords, inconsistent syntax requirements and generates some of the worst error messages known to man. It’s an attempt at making SQL a consistent, simple language — ideally exposing the data model more directly and with less noise
As for SQL being too much like English, making the syntax closer to a general purpose functional programming language isn't necessarily an improvement in my opinion.
It’s more about having a consistent, predictable and simple language. Being more functional-like or imperative-like or declarative-like or whatever is just a byproduct. I suppose LISP is the extreme of that goal, and probably too extreme, but SQL itself is on the other end, with every clause and function running its own subsyntax and special cases. I believe I’ve read the ANSI SQL standard defines something like 1700 terminals — it’s absolutely absurd. And of course every database extends that standard arbitrarily with a slew of new keywords.
There’s a reason every RDBMS can only report errors like “syntax error on line 1: <entire query>” and it’s not because the devs are completely incompetent
Here's the SQL it generates:
WITH table_0 AS ( SELECT , ROW_NUMBER() OVER ( PARTITION BY album_id ORDER BY milliseconds DESC ) AS _expr_0 FROM tracks ) SELECT FROM table_0 WHERE _expr_0 <= 1
If I understand PRQL correctly, it finds the longest song for each album? A simple concept, but not a simple MySQL query.
For those unfamiliar with Postgres, DISTINCT ON takes only one row for each of the groups based on the supplied columns. So in this case, it will return only one row per album_id.
Without an ORDER BY, DISTINCT ON chooses a random row (not actually, but you can’t rely on it.) Since we ORDER BY milliseconds DESC, the first row of each group will be the longest one.
Do you believe these cases are common enough to warrant discarding the tools and training available to SQL? Are you also certain that PRQL doesn't have corner cases where SQL is more concise and/or easier to understand?
E.g. see: https://stackoverflow.com/questions/1313120/retrieving-the-l...
This idea seems like it'd be better as an editor plugin that lets you write shorthand and have it automatically expanded into correct SQL rather than as a build time thing.
Yes the pipeline is more complex, there are more tools and more syntax to track, but the benefits are pretty clear (or we'd all be writing UI code in hand written asm)
While leaky abstractions are a huge problem, the thing about abstractions is that, if they are any good, the benefits and improvements to productivity outweigh the negatives. You just have to figure out if the gains PRQL could give you are worth the effort.
I rarely write SQL, so it's not worth it for me. But if PRQL were an actual query engine, not just a translation layer, and some database offered a native PRQL interface, I would immediately switch to it rather than to keep twisting my brain with SQL and it's inane syntax and rules.
(I was a full time DBA in one previous life, so I should be more comfortable with SQL than most.)
That should work
Look I’m a diehard SQL just use it guy but open to improvements. But I’m loathe to use abstractions for things when the underlying thing is so expressive.
Autocomplete of fields in a good editor, schema help, etc go a long way to making SQL being written raw very nice.
Data query specification is all about getting the details right. This does not look simpler than the corresponding SQL to me though. All components must be present -- scope, group, limit, order.
SQL, for all its faults, is generally succinct at incorporating the required details. The PRQL sample here is succinct as well, but to me at least, not differentiating.
Currently much of my complicated SQL is generated by a LLM.
You could do this:
But this is unlikely to perform as well as the row_number() method because it will cause the RDBMS to generate a record for every track and then waste time sorting the intermediate results to find the unique records in the output.Actually why limit yourself with SQL...?
PRQL is a language compiled into SQL and makes certain hard-to-do things in SQL easy purely because it allows to streamline operations which SQL needs CTE joins or whatever hoop jumping to solve.
My favorite example which sounds easy but isn't - select the row which is MAX(...).
Because it's everywhere, has extensive documentation and tutorials, all database tools support it, all relational engines support it, some non-relational engines support it, all programming languages have library support for it, it can be accessed through command line tools as well as graphical interfaces, etc.
You think an industry is going to give up 50 years of infrastructure because some (typically junior) devs think the syntax is "kinda icky"?
> My favorite example which sound easy but isn't - select the row which is MAX(...).
If you look earlier in the comments you will see queries that have "DISTINCT ON" in them. It solves the problem that sounds easy, but actually is pretty easy if you know SQL.
Just bite in and learn proper sql.
But databases aren't browsers. Devs just have a single target usually: whatever database engine the company decided to use.
Still it would be nice to have greater overlap to reduce the niggling details between them that only seem to exist today due to inertia rather than technical necessity.
In most languages it's easy to pull out functions.
In SQL you end up with a giant hard to comprehend mess.
I think the underlying relational concepts in SQL are sound but I'd love to see ideas like PRQL that aim make SQL easier to write and maintain.
Stored procedures and functions are nice but don't allow the basic idea of breaking a large query apart into smaller logical components.
The thing that's lacking right now is the tooling for managing/testing/deploying database code. There are solutions out there and the supabase folks have been working to make things better but database first development still has some hurdles in terms of DX.
So while it's true it can be composed etc the current state of the art planners struggle except under very simple/constrained scenarios.
This might be a special case however as the function called another function internally (also IMMUTABLE) which was essentially memoized using an expression index. This is the index that was no-longer hit when inlining failed.
If you think this is bug I think I can create a minimal reproduction.
I'm guessing switching the function that calls to_char to STABLE will fix the problem.
Would be nice if postgresql could tell you when the flags don’t match. I think anytime you deal with timestamps you can have problems since the expression may depend on the session’s time zone.
The problem you encoutered is that the rewritten function was either no longer table-valued, or else it was no longer deterministic (which is what that big list of rules for inlining really means). But that problem doesn't go away by adding a layer of abstraction. The need to understand relational determinism doesn't disappear. The need to understand SARGability doesn't go away. You can't really abstract the problem away.
I've used CTEs, but I had not tried breaking up an SQL query into functions. Didn't know that was possible!
For whatever reason, I feel like I end up with a giant blob of SQL when writing SQL and it's incredibly frustrating.
That being said, CTEs are a really good way to write complex queries. They let you tag bits of query with meaningful names, and each thing you tag is accessible to every CTE after it so you can build up an almost imperative data flow by just doing select transforms one after another. That way you're building hard queries from the bottom up rather than the top down.
Personally I'd go for breaking them into views. IIRC as of around postgres 11-13 they're no longer a barrier for the query planner.
SQL is also quite verbose in places (JOINs are the most trivial example), and lack a decent amount of abstraction (CTEs are relatively low level).
Updating a large set of FK'd tables can be a nightmare (this is what ORMs shine at).
Finally, some modern additions are quite unreadable, Postgres' JSON syntax, for example.
I'm not saying that PRQL solves any of the above, but these are all legit problems with "plain" SQL.
CTEs are a first step in structuring queries to make them decomposable. You can extract CTEs to functions and mark them stable and it's logically equivalent to the original query.
Sure, if you are a startup, or write your own code. But for most people the choice of database(s) is a given, and they are not in a position to challenge that. At the end of the day, Oracle has to make a living, too...
> you're not probably not going to be migrating away from it any time soon.
Oracle has its own optimizations and foot-guns that extend well beyond what you can represent in a database-agnostic API. And once you're on that DB, you can write DB-agnostic and have performance be relatively horrible or require a careful rewrite of your schema and stored procedures when you migrate. There is not door number three.
Writing a common layer for any and all relational databases is like using a Java UI library for all operating systems. Sure, it will work, but it will have obvious shortfalls, be immediately recognizable as such to anyone familiar with the underlying platform, be inconsistent with other apps on that platform, and leave any opportunities for efficiency and performance on the floor.
Say you want a pivot table. In Oracle and MS SQL, it's built in. In Postgres, it's possible but noticeably more annoying. In MySQL, it's simply not possible. How would you represent this in a database-agnostic way? And yet performing in the app layer is very much slower/less efficient.
Did you know Oracle supports parallel DML for enhanced performance and lower multi-query latency? You have to intentionally use though, and neither Postgres nor MySQL support it at all.
What about global temporary tables? Those especially aren't found in Postgres or MySQL and are not easily swapped into the app layer without a massive performance penalty.
Per-user namespaces are yet another Oracle-ism that just doesn't translate to other DB engines, but you definitely should know about.
If you're making a living from Oracle, earn your pay. Make the most of what you've got.
Postgres is single server OLTP DB with complicated failover story, it is strong enough reason to consider some other contenders e.g. CocroachDB, SpannerDB for distributed OLTP or OLAP specialized ClickHouse, BigQuery, DuckDB.
2. Propose newer, simpler language to take care of these
3. Newer, simpler language lacks features of original language
4. Newer language adds features, making it more complicated
5. GOTO 1
Arrays, JSON, CTEs, window functions, booleans, MERGE, temporal tables, regular expressions, foreign tables (aka SQL/MED), etc.
SQL hasn't been sitting still, (though ORMs seem to lead folks to believe it is).
Do you currently write K&R C or modern C (C11 or C17)?
Don't get me wrong, I don't think SQL is perfect. Far from it. But PRQL isn't fixing the defects in SQL I care about. For example in DDL, NOT NULL should be the default rather than nullable. When I declare a column as a foreign key, I shouldn't have to specify the type again when the system already knows what the referenced type is. Then again, PRQL is for querying, not data definition, so it doesn't actually solve my biggest issue at all.
SQL could perhaps be more terse. I agree with a lot of folks that FROM should have been first and SELECT near last. That's pretty uselessly subjective. The argument that it's not composable falls flat for me though. Views, CTEs, foreign tables, set-returning functions, etc. are all forms of composability within SQL. When you think in terms of sets, they all fit quite well together. If you're not thinking in sets, it doesn't belong in the database in my opinion.
The underlying engines themselves have been innovating like gangbusters. Using the same wire protocol, folks can connect to a standard Postgres database, a massive CockroachDB cluster, Supabase, and all points in between without changing a client library. The same is true for MySQL, MariaDB, and PlanetScale.
Time series DB? Just use SQL. Analytics? SQL. Document-oriented data? There's even standard JSON query syntax within SQL.
It works. It doesn't generate huge amounts of CVEs like C has. (DB libraries have the SQL injection attacks, not SQL itself.) And it scales fairly seamlessly from Google Spanner all the way down to embedded SQLite.
But folks assert it's irreparably broken and needs urgent replacement. Having trouble buying it. Perhaps I just haven't seen the right replacement yet. That may indeed be the case. I just don't see PRQL being that replacement. It feels a lot more like a lateral move to me at best, and that's just too disruptive compared to potential benefit.
Whenever I am writing SQL I am not thinking in SQL, but I am thinking in what I consider to be the mathematical sound way, which I translate into SQL while writing. I consider thinking in SQL a much greater mental handicap than having to translate mentally into it.
I would prefer to write directly in what I would consider as a good query language and have it translated automatically into SQL, for compatibility with what is, for unfortunate historical reasons, the standard.
I have not attempted previously to do or use something like this, but work like that discussed here seems like a step in the right direction.
This is one of the great HN mysteries to me, and if anyone can shed some light on it, it would be much appreciated.
Could be wrong though, just writing this from memory.
Only users with 500 karma can downvote.
Both are mechanisms to dull the potency of new users until they have a chance to learn how HN is expected to work.
This might sound gatekeeping, and it literally is, but consider than HN signup is open and takes 15 seconds with no verification. HN likes the way HN works and these provide simple rate-limits on destructive or oblivious change.
That term presumes unkept gates are preferable.
I grew up farming. One keeps one's gates or both wildlife and livestock run amuck.
It made sense to me almost immediately, so since people aren't making the connection: https://www.oxfordlearnersdictionaries.com/us/definition/eng...
>5 (informal) (of a person) young and without experience
> The new trainees are still very green.
YCombinator founders have their own colours which are only visible to each other.
There are plenty of undocumented features like this one.
It's confusing, but greying out is used on HN for a single purpose: to discourage reading (and therefore writing).
Low-quality comments are greyed by downvotes from other users and moderators.
Text posts (including Ask and Show HN) are greyed automatically.
Ask/Show posters are encouraged to post a comment on their own story, and to let that comment rise or fall according to its up/down votes.
Meta-meta: Your comment might be downvoted for being meta to the post. It looks like it has already been "detached" from the comment tree so that it appears at the bottom instead of responding to up/downvotes. This is actually protective of your karma and this conversation. Your question is valid, but it's not germane to the post. If your comment was allowed to float to its normal location, it would be downvoted by others who considered it off-topic.
Is it a new tool with great new powers or is it just syntactic sugar?
Personally, I was very excited about using it to write some complex queries in my application that does some fancy backtesting with sliding windows etc, but I reverted back to SQL pretty quickly because I found myself first thinking in SQL and translating back to PRQL :/
I'm working on a new language that compiles directly to Postgres' post-analysis structs. It's working out pretty well so far, but my chosen "universal set" (aggregation/array/subquery/... as one thing) semantics are sometimes a pain to encode.
For example, I want to have universal broadcasting of operators on subquery results, array values, and aggregated columns. To do this, I need to know which of these the operand expressions represent, which is slow or impossible with transpilation.
PRQL and EdgeQL (EdgeDB) are the most interesting ones to watch how they evolve, though.
I've also written a PG extension to make jq available in Postgres [0]
I believe Postgres, in general, will flourish as a host for DSL languages [1].
0: https://github.com/Florents-Tselai/pgJQ 1: https://tselai.com/pgjq-dsl-database.html
We'll soon be announcing some interesting developments on that front, stay tuned :)
The solution isn't for databases to become more like object stores but for general purpose programming languages to be more amenable to seamless access of set-oriented data.
More stuff like this:
https://github.com/porsager/postgres
https://github.com/launchbadge/sqlx
[1] https://www.edgedb.com/docs/edgeql/sets#ref-eql-everything-i...
> PRQL allows for powerful autocomplete, type-checking, and helpful error messages (in progress)
Without some kind of autocomplete though I'm a lot less motivated to do so.
PRQL as a DuckDB Extension - https://news.ycombinator.com/item?id=39130736 - Jan 2024 (47 comments)
PRQL: Pipelined Relational Query Language - https://news.ycombinator.com/item?id=36866861 - July 2023 (209 comments)
Calculate the Digits of Pi with DuckDB and PRQL - https://news.ycombinator.com/item?id=35153824 - March 2023 (1 comment)
One Year of PRQL - a modern language for relational data - https://news.ycombinator.com/item?id=34690560 - Feb 2023 (1 comment)
PRQL: a simple, powerful, pipelined SQL replacement - https://news.ycombinator.com/item?id=34181319 - Dec 2022 (215 comments)
Show HN: PRQL 0.2 – a better SQL - https://news.ycombinator.com/item?id=31897430 - June 2022 (159 comments)
PRQL – A proposal for a better SQL - https://news.ycombinator.com/item?id=30060784 - Jan 2022 (292 comments)
New syntax is nice, but it means that analysts and engineers need to learn something new and are more likely to make mistakes that could bubble up to production. There's always an argument to be made why shiny new tool XYZ is better, but unless it's 100X better, organizations are reluctant to switch from something like vanilla PostgreSQL that they know works 100% of the time.
> Windows is not supported. It could be, but will require a bit of work with cargo-pgrx and figuring out how to compile pgrx's "cshim" static library.
The intention is rather for it to be simpler, as it uses a linear direction of data handling. SQL jumps back and forth with its order of operations and can be confusing in this way.
PRQL also has a more modern syntax that reuses more universal concepts with fewer keywords to learn. In contrast to SQL which has a unique keyword, syntax, and behavior for everything.
PostgreSQL's query-optimiser does handle these cases quite well for me once I explain and add the appropriate indexes, yet complex source queries carry undiscountable costs (longer planning times, missed optimisations e.g. predicate pushdowns).
I find myself needing to mechanically transform and simplify SQL every now and then, and it hardly seems something out of reach of automation, yet somehow I've never been able to find software that simplifies and transforms SQL source-to-source. When I look, I only find optimisers for SQL execution plans. It's a bit hard to believe that such a thing doesn't exist, given how significant the SQL ecosystem is.