I don't need your query language
antonz.org
antonz.org
And there are often problems when using multiple SELECT queries in a batched statement: you can't re-use existing CTE queries. Not all client libraries support multiple result-sets. It's essentially impossible to return metadata associated with a resultset (T-SQL and TDS doesn't even support named result sets...), which means you can't opportunistically skip or omit a SELECT query in a batch because your client reader won't know how to parse/interpret an out-of-order resultset, and most importantly: you need to be careful w.r.t. transactions otherwise you'll run into concurrency issues if data changes between SELECT queries in the same batch ()
[1] https://learn.microsoft.com/en-us/ef/core/performance/effici... and https://learn.microsoft.com/en-us/ef/core/querying/single-sp...
Small price to pay for improving RDBMS throughput and eking out more from limited hardware. There is no shortage of use cases where this just makes sense. Doing all of that work in a single SQL query also makes sure there's less buffer cache thrashing.
1. The data has to be serialised into JSON on the DB server, which costs CPU.
2. It then has to be deserialised on the application server (unless your backend is written in javascript and then your throughput problem is that you're using javascript instead of a better, compiled language)
3. The network bandwidth is actually larger as you've got all those extra {} in your result set, compared to the raw data in column format
It might "look" bigger to a human as there's more columns, but the data is exactly the same. So by definition, youre doing extra CPU work of serialising/deserliazing JSON and adding all the object markers of extra characters like {} and "" and : means the payload is bigger too.
Which costs very little CPU in 2023.
> deserialised on the application server
This is true regardless. The low-level libraries are still parsing the stream into meaningful in-memory structures. With JSON, the low-level library only has to parse a variable length string, then JSON decode. I'm unfamiliar with any language in 2023 that doesn't have incredibly fast and efficient JSON parsers.
> bandwidth is actually larger as you've got all those extra
This is true, but generally negligible. I run into very few scenarios where network saturation is more of a problem than CPU or memory issues. If you have network-constrained problems, obviously optimize accordingly.
It's either better, or not. Your comment does not make it better, it's still worse. So it won't improve performance, but degrade it, even if it's negilible.
So there's no reason to do it.
Plus you've made a crazy SQL select instead of a normal one, which is harder to maintain.
So it's worse performance and worse maintenance.
i.e. don't do this, it's dumb, especially for the reasons claimed which are factually incorrect as it will not improve throughout but make it worse
Absolutely you can when the increase in something (bandwidth) in a system with surplus supply with the trade-off of optimizing a more constrained supply (CPU or memory).
> made a crazy SQL select instead of a normal one, which is harder to maintain.
Purely subjective. Myself nor the people I've hired would have a problem maintaining a more complex SQL query using CTE's and JSON serialization than not.
> it's worse performance
I cannot imagine that's the case in the context we've been discussing. An RDBMS duplicating JSON output of tuples multiple times in a single transaction is not particularly expensive compared to the alternative.
Response times are really fast like that, as you probably already know. Always fun to see <10ms round trips in the browser network tab on some requests
Also no worry about n+1 queries, as they're fundamentally impossible to do like that
Or perhaps sending DB query results directly from DB server to browser, with the API server just initializing and securing.
Thanks for pointing out how JSON from the DB is another option for moving a bit of processing elsewhere in the stack.
I'm just pointing out it doesn't achieve that.
This solution for tuples is objectively worse in every way, throughout, network bandwidth, code complexity, maintainability, error likeliness.
You're just clearly someone who can't admit when they're wrong.
Prove it.
> You're just clearly someone who can't admit when they're wrong
You don't have a good technical argument so you jump to ad-hominem's?
If the biggest issue in my product is JSON deser, I'd be a happy camper.
I suggest avoiding statements like this. Yes they help vent your frustrations but they destroy the otherwise constructive and interesting debate the two of you were having.
Absolutely you can when I can absolutely guarantee you that you’ve written worse performing queries in the past that caused more cpu issues than the overhead of working with JSONB.
That's a very bad argument for an RDBMS, since you want to make it scale vertically as much as you can (unlike your application server, horizontally scaling your database is a completely different matter, and isn't straightforward at all).
A straw man argument you've pulled out of thin air.
2. You don't have to do deserialization in the application layer. If all you're using JSON for is to convert to OOP objects, just deserialize in the db -- which again, trivial.
3a. This is wrong on many counts. If you want efficient passing of JSON, use JSONB which is the binary encode of the JSON, as a tree structure. It will not include the structural characters.
3b. Bandwidth is also cheap.
4. Don't optimize without profiling. A few extra CPU cycles is not going to make-or-break your scaling journey, you'll most likely run into larger problems before that happens.
5. You can get "non-uniform" tuples by using UNIONs and a smart flagging system that points to tuple schemas -- rather than using JSON; the difference is entirely ergonomic.
6. If you're in a low-latency environment and the CPU cycles are absolutely critical, write your own extensions to handle what you're trying to do, instead of twisting Postgres into doing your bidding.
select array_agg(e) from jsonb_array_elements_text('["a","b"]'::jsonb) e;
?Doing that means losing foreign-key referential integrity...
You can have your data stored in tables with all the constraints you might want, but then use json in queries to return the results in whatever form you want.
For anyone (like me) who is not quite able to visualize this, here is an example:
SELECT json_agg(trips)
FROM (
SELECT
json_agg(
json_build_object(
'recorded_at', created_at,
'latitude', latitude,
'longitude', longitude
)
) as trips
FROM data_tracks
GROUP by trip_log_id
)s
From StackOverflow user S-man https://stackoverflow.com/a/53087015I'm super unfamiliar with this space, and would love to know whether it is a feasible/worthy goal to replace GraphQL queries with generated SQL.
A good editor (DataGrip) helps.
I see someone else said that it scaled well for sqlite. For postgres, it very much depends. Building a json object is much, much slower than selecting a row. Updating JSON objects involves building a new one, since you need to replace the entire object, so avoid building your schema in a way that requires updating JSON objects.
(Experience is with postgres 14. To be fair, performance was generally fine up until the 100s of millions of rows)
JSON query performance in postgres though is generally quite good. If you have static data, throwing it into a JSONB column with a jsonb_path_ops GIN index (or the default if you need the extra query flexibility) scales well up to billions of rows.
It's nice being able to use datetimes, 64 bit ints, binary, etc
ORMs also tend to sneak "live" objects into unexpected places, triggering surprise DB accesses.
Not that ORMs are completely useless. We just need to stop pretending that there can be a smooth and performant automatic mapping between relational tables living in a DBMS and Business Objects living in some idealized world without storage limitations, where any connection between them is like following a pointer in RAM.
Most ORMs provide tools to write composable, reusable queries and parts thereof. These are the best parts.
ORMs, by design, bring unnecessary data over the wire for the sake of inflating parts of an object graph you don't care about 90% of the time. Most of that data will either be unused, or you are going to transform and then discard anyways. If you go out of your way to actually optimize out unused fields: now you're passing around objects with nulled-out references around your application, which is just a disaster waiting to happen.
Having a query DSL that actually maps result sets to your language's type system is the only way I've found to actually write robust, performant, maintainable code. My result sets being "too big cartesian disasters" is just not a problem I have, because I don't think in objects. I ask the database for what I want to get the job done.
This is utter nonsense. There is absolutely nothing about microservices architecture that relates to performing JOINs in SQL.
It should be a single INSERT, but through an ORM that multiplies it. The only upside of Kafka is not having the ORM…
That's being said, Kafka is not one of them.
That doesn't help with conditional-predicates - that's another major shortcoming in SQL.
ORMs 100% always do it worse
https://docs.sqlalchemy.org/en/14/orm/loading_relationships....
It's not too uncommon I run into code in other languages where I just don't understand what it does, or to write code myself that behaves in ways that surprise me. That almost never happens in SQL.
Even a big hairball of a query just takes time to figure out (unless a database-specific function with odd behavior is used).
That JavaScript framework that takes a year to understand will no longer be used in 7 years. SQL is going to be here forever and learning it is useful your whole career.
Other common entries on this list of forever tools: regular expressions, emacs, bash/shell scripting, excel, probably more I’m forgetting.
Devs always push back on the suggestion to learn something like excel (actually learning it, not just clicking around), but when they first start they really underestimate how often it’s the tool the business speaks and feels comfortable giving feedback on technical questions in.
Surely there is a lot more nuance for having a nicer database query language than comparing it to JS frontend practices.
SQL is something that'll stick for a long time, but I support attempts from people that don't want to let SQL be the endgame.
Of course don't go around deploying highly experimental shiny things on production! :P
Yes, but as often as not business people end up using Excel as a glorified text editor with built-in tabular formatting. Some of the spreadsheets I've been handed by project stakeholders would make 90s-era pre-CSS HTML using tables for formatting look clean and simple by comparison.
After writing applications in "4GL" sql tools early in my career, I've spent the entirety of the rest of my career trying to avoid writing SQL or having anything to do with the inner guts of those gigantic global variables known as relational databases.
I wholeheartedly agree that engineers massively underestimate the power of Excel.
Nothing seems more ephemeral than JavaScript framework du jour.
Oh yes, many more: Java, JCL & COBOL, Windows Forms, PhP, Wordpress, Joomla, Drupal, Perl, Visual Basic, IIS, SSIS, Ruby on Rails, and so on and so forth.
Maintaining enterprise software is a special circle of hell reserved for developers. Just sayin'.
You need to state what you want (select a, b, c) before you tell it from where to get it (from). And no tooling can predict that.
So switching this, moving from and joins in front of select, might be everything needed to fix sql.
You know I think you're right.
I suppose it could be nice if the user could specify clauses in an arbitrary order but it’d certainly add complexity.
I don’t find it difficult to jump around a bit from clause to clause while writing a query. In fact, it’s incredibly rare to write a query straight through and have it do what you want it to do.
FROM users WHERE name LIKE 'a%' SELECT name, id, location
(I should refresh the page before posting)
var result = from s in stringList where s.Contains("Tutorials") select s;
I can't stand the non-extension-method Linq syntax: the _only_ place where it offers a readability improvement over ext-methods is using `join` - but I hardly ever do that in Linq anyway.
Also, in both my code and yours, `result` will be a lazy-evaluated `IEnumerable<String>` which may be undesirable - which means it's probably a good idea to use `.ToList()` to materialize it - which means having to use ext-methods anyway - and mixing both syntaxes in the same expression is aesthetically atrocious.
Hah! I tell the juniors this all the time :D. This seems to be basically the consensus among the C# community these days as far as I can tell as well.
Read: "you create new heap-allocated closures which wreck your Linq expression's runtime performance"
Or:
"you create Linq queries that cannot be translated into SQL"
——
On a related note, it’s interesting just how unpopular so many new C# language features are (just by looking at the numbers of Thumbs-down reactions on the GitHub Issues/PRs - stuff like top-level Main. It feels like C#’s LDT wants to be like Swift, but without Swift’s willingness to ditch ill-conceived features after a few years… but I think C# would be well-served by taking an axe to some language-features by now - like keyword-Linq and CLS-compliance (honestly, do any ISAs today still lack hardware support for unsigned ints?)
I think there are some otherwise-seldom-used linq overloads for doing just that. Maybe on Join() or GroupJoin() or something like that. Query expressions use them for compilation to keep closure use down, but I don't know too much about it.
Anyway, if top-level statements are wrong, I don't ever want to be right. I had no idea there was any controversy on that. It's trivial to add the boiler-plate back in if you want it.
The main thing that bugs me is that Expression<> is stuck with language features that existed in C#4, even when there are trivial lowerings. e.g. `is not null` could be `!= null`. (This example ignores operator implementations, but most IQueryables ignore more than that already) Even better, add AST node types for the new language features.
Top level statements and the new HostBuilders are fantastic, they're much cleaner and easier to follow than the previous mess. Add Minimal APIs to the mix and C# is finally a viable choice for spinning up something quickly.
No love for let?
from item in items
let frob = Expenseive(item.P1)
where frob > 3
selec new { frob, item }...and ValueTuples are superior to Anonymous Types because you can actually return them from a function or use them as parameters - whereas Anonymous Types cannot cross method-call boundaries (excepting using generics for pass-through).
Anonymous Types in C# were a massive mistake. They should be [Obsolete]'d, IMO.
I've been just showing that *approach* of starting SQL query from "from" part is viable, because that's how Microsoft timplemented in one of two LINQ "API"s"
I'm not trying to convince anyone to use LINQ's Query Syntax.
Linq is a (reasonably) compromised, non-referentially-transparent, implementation of a restricted form of relational-algebra with side-effects permitted, so I'm not comfortable describing Linq as "monadic".
Whereas Haskell's `do` is strictly monadic.
Linq query syntax is just dumb
Also, i don't actually see the problem because you never write a query in a lineair way. Usually start with "select * from table limit 10", look at the columns and data available, and then start refining. By now, code completion works as the table is known. Wouldn't help much to write it table first.
What you describe is learned behavior to get along with a design flaw. SQL won't change, so no reason to worry.
My point is: People keep creating new versions of it, because it is not as `easy` to work with as it could be.
I like their approach of adding thoughtful quality of life improvements instead of coming up with a new language.
We're migrating from Sybase SQLAnywhere to MSSQL, and not being able to use aliases in WHERE, GROUP BY and ORDER BY is such a pain in the behind.
Almost all our non-trivial queries have to be nested multiple levels due to this, which doesn't exactly help readability.
Then again, Oracle just this year added support for booleans, so asking the incumbents to switch to a new query language seems an impossible ask.
My favorite is window aliases (I'm sure it's found in other SQL engines too). It's not only cleaner and less likely to accidentally introduce a discrepancy, but apparently also results in better performance.
> The three window functions will also share the data layout, which will improve performance.
https://duckdb.org/docs/sql/window_functions#window-clauses
I'm surprised some of the other big-name OLAPs don't provide this. *cough* Snowflake *cough*. Snowflake's query optimizer doesn't even seem to recognize common window definitions across multiple window functions.
It's been an alternative in Postgres for decades.
TABLE foo
LIMIT 100;
No SELECT with columns and no FROM keyword.An experienced person won't do that. For any moderately complex SQL query, before writing it I already have in mind the several jointures I'll need, since I usually know the tables and FK I'm working with. It's like following the edges of a graph, all in my head. But I don't know all the fields of these tables, so I rarely write their names from memory. So I have to write "SELECT 1 FROM …" and then go back to that "1" once my FROM is complete. That's not the end of the world, but it does smell.
I’m very experienced and do that kind of thing all the time.
Also, your “SELECT 1” technique seems like practically the same thing, except I guess you discover column names from autocomplete tooling rather than query output. (To my mind the difference is inconsequential.)
But if you mean any other kind of experience or expertise, you are wrong. Those do not correlate with how a person assembles a query.
I typically keep all JOINs I've ever used on that schema in a single file, one per line.
Before writing a new query I can just copy paste some JOINs, simply skimming through table names like lego bricks.
That way it's surprisingly easy to beam from domain problem to a new query that uses 10 or 20 tables.
I've just realized that it might be all archaic now, in LLM era.
You have a library of useful joins that you've checked for correctness. Saving the library as reusable code would be even more useful.
d3w (`d`elete `3 w`ords) cannot be highlighted / indicated in any way ahead of time. If the motion specifier came first, it could be.
I think something that might work better is adding a “commit” signal to operations. So you type `d3w` and the editor highlights the next three words with a strike through or red or whatnot. Then you can hit enter to commit the delete or escape to cancel it (cursor resets to start position, highlight goes away).
You can also use that with ex commands, like if you do `vap:s/foo/bar/g` you will replace `foo` with `bar` only within the block of code you visually highlighted with `ap` (which I remember as “a paragraph).
So if you want “delete three words”, do `d3w`. If you want “highlight three words” do `v3w` and then issue another command like `d` to do something with what you highlighted.
I mean, if you hit v first, that's exactly what it does.
Or is this just reversing the order so it's {motion}{verb} instead of {verb}{motion}?
It's also generally lean and follows the Unix philosophy, e.g. by using shell script, pipes, and built-in Unix utilities to do complex operations, rather than inventing a new language (vimscript) for it.
(Not affiliated with the creator, but kakoune has been my daily driver for years now.)
A good mindset to have in regards to Vim is, "Vim can do anything, even make you coffee". The trick with Vim is actually figuring out /how/ to do it.
I highly recommend you start with the VimCasts[1] video series. They're short, 5 minute, videos. With each covering a specific functionality of Vim. They straight to the point, and the author provides samples code for all videos.
The situation could certainly be better, but at least this works today.
After parsing and analysis steps, the system is going to do what it does with the statement, no?
The syntax is for the user, not the system.
This is paramount for performance.
If autocompletion is your issue, just get a better client, it's perfectly possible to autocomplete field names even before specifying database or table name.
The problem is that SQL forces you to think about what to select before you even say where you're selecting from. There's nothing a client can do to recommend columns if it doesn't know where you're selecting from. It's pretty cumbersome to have to SELECT * FROM x and then go back and erase the * to actually get auto-completions.
It basically forces you to tell it what you want before you even know what the options are.
I know that from the interpreter's standpoint, it doesn't matter which one is written first.
What I meant is that as a human, if you have to think first of the columns you want to bring in, it will guide you towards the joins that you need and only those, rather than thinking "let me join all those tables because I need _some_ data from the entities inside".
My point about "autocompletion is still position" was not connected to the first part of my comment.
I just added it as a separate point, to say "you can have autocomplete no matter the order in which you write your query"...
To me, this is a slight annoyance with an easy workaround. If the SQL spec gets updated to allow switching the clauses around, I'll be pleased. But I'm not about to change languages over it.
Is it ideal? No. But it's muscle memory now, so...
¯\_(ツ)_/¯
So, I had to move to VS Code for Vue and Svelte and as I didn't want to use 2 different IDEs I canceled my JB subscription. So far VS Code is pretty good for Goland and Rust as well, but as you said, I struggle to find something as good as DataGrip for SQL. Maybe I should just get a DataGrip license (single tool).
Edit: I forgot another issue ... DataGrip didn't support the latest SQLite version for a very long time, as the maintainer for the open source Java client wasn't working on it. When I dared to ask the JB support a second time for the status after a while, I got a stroppy reply from the responsible Jetbrains engineer, as how I dare asking twice and there's nothing Jebrains could do when the single person maintainer of an open source lib is doing other stuff with his life. Crazy.
Step 1: build the dataset you want (FROM and JOIN) with all columns.
Step 2: filter out the rows you don't want (WHERE).
Step 3: choose which columns/values you want (SELECT).
Maybe it's just me but this model makes so much more sense to me! I'm sure not every developer has the same way of thinking, but it sure does seem more logical to me.
Consider `SELECT 0 AS some_num`. This does not have a FROM clause.
While this example seems contrived, there are several examples of queries where the FROM clause is not just a listing of tables. Especially when moving into larger projects in SQL.
It makes more sense to have the select last.
That's an exaggeration. Usually I just start with Select * and build all the necessary joins. For that the tooling support works without problems and when I select the columns in the end it works too.
The documentation for EdgeDb goes into some detail about that and shows an alternative better language for data-queries.
https://www.edgedb.com/showcase/edgeql
To understand why SQL is bad, you must first be shown something better, and EdgeDb seems to be such better more composable language.
For the record, I make heavy use of SQL because relational databases are awesome and SQL is the least bad option I've found so far. But the many shortcomings of SQL still annoy me.
The syntax example on the PRQL homepage
from invoices
filter invoice_date >= @1970-01-16
derive [
transaction_fees = 0.8,
income = total - transaction_fees
]
filter income > 1
group customer_id (
aggregate [
average total,
sum_income = sum income,
ct = count,
]
)
sort [-sum_income]
take 10
join c=customers [==customer_id]
derive name = f"{c.last_name}, {c.first_name}"
select [
c.customer_id, name, sum_income
]
Trailing commas, select at the bottom, filter is both a WHERE and HAVING replacement, easy filtering of created columns, etcThe notion that SQL is not composable is either a lie or simply repeated by folks with only a cursory knowledge of SQL from 20 years ago.
Views, set-returning functions, CTEs, and more: all examples of composability in SQL.
Then of course there's the issue of security where folks tend to put all of their access constraints into their middleware AFTER the data has already been returned over the wire in bulk. Take a moment to consider role-based access control and row-level security policies. Instead of trying to track down every possible spot where a JOIN could have crept in past the code reviews (you code review your DDL and DML, right?), you set your GRANTs, REVOKEs, and POLICYs at the points in your data model that need them; restricted data never makes it into intermediate result sets let alone the final result set and the wire.
Don't misunderstand me. GRANT, REVOKE, and POLICY can be a real PITA, but that's because *security* is a PITA, not the SQL syntax to enforce it. Anyone who tells you their app solves your data security problems in the app tier with a point and click is a lying salesman.
I thought the same until a few weeks ago. Then we used the WITH operator for pre-processing and giving things human-readable names.
That helped us manage complexity. The final SELECT statement was very easy to reason about.
Not sure if this is a best (or worst) practice but it helped us ship it.
https://www.datasqrl.com/blog/sqrl-high-level-data-language-...
Sometimes a project, especially a greenfield project, looks like it will benefit from more recently invented data storage and query tech than your grandmother's SQL. That's always possible. And as developers we hope for, and work for, continued progress. But consider what may happen when the project succeeds.
If you're still on the project, you'll wake up one day and realize your oldest data is 20 years old. What happens if your storage and query engines are also 20 years old, because they didn't succeed to the extent needed to pay for maintenance and upgrades? You'll be in the software equivalent of the century-old subway system where you have to make all your replacement parts yourself, or get gouged by vendors that can't spread their costs among many customers.
Build for the ages, not for the moment!
People pay a lot of money for kdb so clearly they see some value in it despite the lack of sql.
I think I’m much more motivated by analytics queries than the kinds of thing in this example though. I find sql is poorly suited in this case because it is verbose and written backwards, and often requires many layers of subqueries. That said, one can usually still express queries in SQL that other systems do not allow.
For these kinds of queries I think there are just better ways to express them. Another issue with sql is that has some quite strange semantics.[1]
An example query I wrote yesterday is:
select group, min, max, (max-min)/1e9 range
from
(select group, min(size) min, max(size) max
from
(select time, instance, sum(size) size, regexp_replace(name,…) group
from X
group by regexp_replace(name,…), time, instance)
group by group)
order by range desc
limit 10
Which is neither pleasant to write nor iterate on interactively.With something like dplyr instead:
X %>% mutate(group=regexp_replace(name,…))
%>% group_by(group,time,instance)
%>% summarize(size=sum(size))
%>% group_by(group)
%>% summarize(min=min(size),max=max(size),range=(min-max)/1e9)
%>% arrange(-range)
%>% head(n=10)
And that can be built up interactively pretty easily by adding onto the end of the pipeline.I would also note that, due to sql being painful, the query is not exactly the one I wanted and instead I would have wanted something better capturing the change over time, but the thought of doing that in SQL seemed too unpleasant.
An example of an actual query language that tries to be better for analytics: https://prql-lang.org/
[1] from someone who spent a lot of time working on databases and sql: https://www.scattered-thoughts.net/writing/against-sql and just on semantics: https://www.scattered-thoughts.net/writing/select-wat-from-s...
Ex:
min(sum(size)) over(partition by group) min,
max(sum(size)) over(partition by group) maxIf you are forced to work with a schema that is poorly-aligned with the logical reality it intends to represent, you would definitely walk away with a bad taste in your mouth. Hacking around bad normalization is 99% of what makes SQL suck for me.
If you ever get a chance to design the whole thing yourself from zero, you should almost always insist on one big database/schema and routinely review the table structure with the business owners before you actually go to prod.
The moment you start doing things like putting data for service A into database A and service B into database B, you lose a lot of power. Sometimes this is required, but most of the time it's an org-chart alignment meme. There are ways to join these separate databases, but it starts to fall down pretty quickly. The true magic of SQL is having all of those dimensions in one place at one moment in time so you can put a pin in anything without complex distributed transactions.
many business domains are well-modeled by relational data
some are not
That is a funny way of looking at it. I see that SQL is based on the work of a computer scientist vs DSLs being made by hobbyists, and it shows.
After an initial "Uh-oh, I haven't manually written complex SQL in a while..." it all came back fast enough (Thanks, first-semester relational algebra!). Turns out, sql is well-suited for business "in-queries"!
The things that made us scratch our heads came from how the schema had evolved over time. We now have those hairballs at least 'contained' and visible. And it's all pretty readable imho.
I guess my initial unease came from using ORMs for CRUD persistence and very rare exploration. And holy moly, I'm grateful for ORMs. I wouldn't want to manually write those inserts and updates.
So, I guess it depends on what you want to accomplish with your database.
Btw: A HUGE shout-out to Dbt and Dbt cloud for letting us treat sql as code. Didn't expect to love it that much. How was this not a thing earlier?
Why not SQL?
Lack of tooling for SQL.
Yes, SQL lacks tooling. There's a ton of stuff to build a SQL client, obviously. However, on the other side:
- I have no sane way to parse SQL
- I have no sane way to comprehend SQL
Writing a SQL query system would be many months of work. Tossing together a good-enough query language with standards like JSON or YAML means I can json.loads(query) in Python and JSON.parse in JavaScript.
SQL would be an ideal fit if there was good tooling, and it fits in more places than most people realize. Web API query a whole bunch of stuff stored in all sorts of complex ways. SQL is better on paper than RESTful / AJAXy / GraphQL / etc. APIs.
It's not better if it means that the query language takes more time to build out than the entire rest of the system.
TL;DR: If you want to build a high-visibility open-source project and guarantee employment for the rest of your life, an elegant SQL parser, especially for building web APIs, would be a great thing to do.
And I don't know what you mean by "no sane way to comprehend SQL" - I guess the millions of data people in the industry are just insane?
Cobbling it together with YAML or JSON is a reasonable trade off if you're in a hurry, but I don't understand how we got to the point where we're throwing out estimates like "writing a parser is months of work" and "it's a PhD project to render some glyphs [1]"
Generally, I've only seen ORMs create the query from the object, rather than the object from the query
Or are you talking about something different?
- Reasonable performance
- Test infrastructure
- Pretty comprehensive SQL support. A lot of computation happens in the queries.
- Maintainable
- Documented
Most things can be hacked together quickly, but that's different from correct production-grade code.
I can see that if your YAML solution doesn’t have a way to express GROUP BY, so the backend doesn’t support it, then of course that’ll be extra work, but then that’s IMO a different feature.
SQL itself is a tiny language - a parser that transforms it into your YAML based AST really would be pretty small. Here’s the one I made many years ago: https://github.com/google/dotty/blob/master/efilter/parsers/...
It’s not the best quality code, and it doesn’t implement SQL92, but we did run it in production.
What I actually want is the whole dotty / efilter system, only with things like documentation.
We really do care about performance, though. From your code, this would not work:
api.apply("SELECT name FROM users WHERE age > 10", vars={"users": ({"age": 10, "name": "Bob"}, {"age": 20, "name": "Alice"}, {"age": 30, "name": "Eve"}))
It would really need to be:
query = api.compile("SELECT name FROM users WHERE age > 10")
query(vars={"users": ({"age": 10, "name": "Bob"}, {"age": 20, "name": "Alice"}, {"age": 30, "name": "Eve"})))
Or more likely, vars would be a closure which would allow it to interact with the proper data stores.
As a footnote, that looks like a really nice project. I wish it were supported, maintained, and finished.
What I want to query is a perfect fit for SQL. However, it's very much not in a database.
I also don't need a subset of SQL. I would need things like stored procedures and ideally things like virtual tables. There's a lot of computation going on in the queries. The postgres can represent 100% of what I want, but it's a big complex syntax.
In an ideal case, I could pick up pieces and run with them. I think I could reuse parts of things like a query optimizer too.
SQL (or GraphQL) is often used as a remote API: The client sends a SQL statement, the server processes it and sends the response. SQL is very powerful, but also dangerous: the statement might be very expensive, for example because an index is missing. Sure, you can shoot yourself in the foot also with Python or Java, but I argue it's harder. SQL is one more technology in your stack, one more thing to learn. And actually, there are many many SQL dialects.
I wish databases have better, faster, and standardized support for a fast procedural language. So that clients can send programs, the server processes it and sends the response. A way to access tables and indexes like a hash table or ordered map. That way, there is no border. There is no slow query due to a missing index. You have to think about how data is access, which indexes are needed. But you have everything under your control. There is no risk of a missing index, or risk of the database not picking the index it should.
(I wrote 3 relational database engines and 4 SQL parsers: HypersonicSQL, H2 database, Apache Jackrabbit Oak, PointBase Micro. I also wrote a GraphQL parser and engine, and a Key-Value store. It's not that I hate SQL.)
It’s almost impossible to write procedural queries that always perform, that is a really hard task. That’s why we use a declarative query language, I tell the database what data I need, and the database optimizer will determine the best performing algorithm to fetch the data based on all dynamic statistics it has.
Don’t underestimate how much hard work the database optimizer takes care of, I’m glad I don’t have to program all of that myself.
Better get used to this way of working, it resembles pretty much how AI assists us.
I don't think it's hard to write procedural queries that are always fast. You write a loop or map/filter/collect method. You just explicitly need to mention which index to use, is all.
But I have little faith that people who forget indexes are capable of writing procedural queries that are always fast. These less experienced devs are the ones that benefit most from the query optimizer doing the hard work. I think the real solution is for database to automatically create indexes where needed, as some database already do. And some better visual query editor like ultorg.
Declarative programming is not very popular because it’s hard to debug. You can’t step through it and inspect intermediate representations. It presents a black box to the developer.
That said, they do seem to show up around certain very complex APIs sometimes.
Besides SQL, CSS is the obvious one.
And I think many parts of otherwise functional/imperative APIs are pseudo-declarative.
For example, React is famously functional in its current form, with render functions and hooks being functions… but then common hooks take a dependency array which is declarative. And at the boundary of these hooks the code is no longer procedural, it disappears into the framework.
> I wish databases have better, faster, and standardized support for a fast procedural language.
That’s a fascinating idea. It would take someone with deep knowledge of a query engine to encapsulate it with a procedural API instead of a declarative one.
That’s not me, but I would love to see it.
I'm hoping that as WASM games momentum and WASI becomes an actual thing, some DB is going to pop up that does just that. I'd like to try myself one day.
sql is not a programming language in the traditional sense, it's a mistake to try to think of it in those terms, or demand traditional programming language type stuff from it
Learning a new language is a one-time, up-front cost. Dealing with an awkward, inexpressive query language that integrates poorly with my main language, my types or my interface description languages is an ongoing source of painful friction. Learning something new should not be nearly the barrier to adoption that it seems to be for most people!
SQL's shortcomings seem so clear and omnipresent that I legitimately do not understand why everybody seems so drawn to it. Are the usage patterns for code against a transactional database so different from the sort of Hive queries I've had to deal with for data engineering and machine learning? Is everybody happy with abstractions layered over SQL like ORMs?
Why can't we have, I don't know, some typed variant of Datalog or something instead?
(1) Switching `left join` to the default inner `join` changes query behavior. I'm guessing it's intentional on the author's part? But it feels like the wrong change to make when trying to compare syntax like-for-like.
(2) I am also in camp "SQL keywords really don't need to be uppercase", so keep fighting the good fight, brother. That said: it's an uphill battle and far from universal. Most SQL "formatters" I've used automatically uppercase everything.
(3) Dropping the alias in `Actors.name AS actor_name` is another case where you're not doing like-for-like. Just using `Actors.name` means, for example, the first example's output table will have two columns: title and name. I'd argue for most uses title and actor_name are better output column names.
Those points aside, the primary simplification seems to be switching `join ... on` to `join ... using`. Big +1 from me on that.
I have absolutely nothing against EdgeDB or its creators. As far as I can tell, it's a great product.
That's a very commonly known technique where you purposefully take only the overly simplified points that you want to counter so that's easy to build arguments or say things like "What can your language offer besides being created in the 2020s?". This is not to say the author or majority of the readers would find what EdgeQL offers, other than being created in the 2020s, valuable but at least you wouldn't be fighting a straw man.
Other responses note some (to me) esoteric enterprise use-cases for which SQL may not sufficiently describe exotic data vistas. Sure.
But most of the "shaming" one encounters seems to be about advertising some sort of magic wand product more than pointing out a substantial woe in a system that has been prominent for a half century.
EdgeQL:
select Child {name}
filter .<child[is Parent].name = 'Uma Thurman';
SQL: select child.name
from child
join parent_child_rel using (child_id)
join parent using (parent_id)
where parent.name = 'Uma Thurman';
IMO EdgeQL is going too far with the sigilsYou can either call SQL proven and battle-tested, or crusty and outdated, depending on your agenda.
Same for the fancy new alternative: It is either fresh and innovative, freed from the shackles of legacy and standard-compliance, or reinventing the wheel in a non-standardized manner.
The truth is EdgeQL is so good that you never want to go back to SQL ever after. It's even a bit depressing when you realize how much time has been spent crafting SQL queries and dancing around it. EdgeQL renders most of those struggles obsolete.
The author of this post has written a book about SQL Window Functions, and probably developed an attachment with his SQL expertise. He probably doesn't need another query language – nobody likes to return to the "beginner" level after their identity has been attached to the "expert" level.
But people who hadn't developed abusive relationships with SQL expertise, they absolutely need "your query language".
My experience with EdgeDB (Jul 26, 2022)
My eyes rolled so hard they actually flipped completely around
On the other hand, when I have to do a somewhat complex query in Elasticsearch, or MongoDB, or gorm, or Django ORM, I have to check each time in the docs how it's done.
SQL is a problem not because of the era in which it was developed, but because somehow we haven’t evolved any meaningful successors. We have a bunch of dominant programming languages and only 1 data mining language? What’s up with that? Why is there this pretense around only having one language? Multiple languages are healthy because ideas cross-pollinate. How long after MongoDB did it take database vendors/OSS projects to start adding JSON support to their SQL databases?
It's not a dinosaur, it's a shark.
Would I like to have something more streamlined and less clunky? Absolutely. But it's going to take a lot of effort for anything to become as ubiquitous as sql.
Would love to hear from anybody that's using it regularly
From table select col;
as an optional alternative to
select col from table;
This would allow autocompleting col names in editors.
Other than that I quite like sql being the standard db query language.
- barring extensions you can only select grouping expressions or aggregates
- but instead of repeating grouping expressions you can refer to a select expression (by index, some databases also allow the alias)
The "spec" order of evaluation for queries is WITH, FROM, WHERE, GROUP BY, HAVING, SELECT, DISTINCT, merge, ORDER BY, LIMIT. Although databases might decide to move SELECT after ORDER BY and LIMIT if they can, in order to avoid unnecessary evaluations.
Absolutely true. But a huge amount of queries are in fact trivial selects. And this change alone would make autocompleting them easy for various editors/IDEs.
Perfect is the enemy of the good, etc.
Change what? Make "group by" behave better how?
> `having` redundant with `where`
They filter different things, how do you make `where` perform both jobs?
> like it should always have been if you just evaluate from start to end, without any hidden reordering.
The only "hidden reordering" is an optimisation.
Yes, they absolutely got this right. But I agree with the author of TFA in that I don't want another query language. I just want this specific change to SQL. Maybe others as well. But I do not want another query language. PRQL is yet another query language.
Recently I was burned by a bad query in Google Log Explorer. There was no feedback my query was wrong, just no data.
However, I’d have said the same about JS a few years ago, and now we have TypeScript. Perhaps a language that is a strict superset of SQL and that compiles to SQL might be something worth trying.
I can't count the number of services or things I've had to use which invent their own query language instead of using SQL. In every case the language is empirically worse than SQL, especially when it's some mangled hybrid to make things "easier" coughNRQLcough. The silliest part is, if we all just fucking used SQL the tooling and integration would be much fucking easier and/or free. Not to mention, in almost no organization will you have the time or resources to not make something that's a half-implemented, poorly spec'd, rubbish version of SQL.
I think the biggest problem with SQL is that folks feel like they don't need to know it or that it's not useful. Oh dear beebs, it's fucking useful. Next time I personally need to build a rich query interface, I'm just using row level security and opening up Postgres.
> SQL has a solid standards committee that maintains and improves it.
so does c++. so does javascript. so does cobol
We built a datascience tool to quickly build data apps which can be extended from the frontend, including data wrangling and datascience functions. Most exciting part was using the PostgreSQL and SQL to process, clean and enhance data and write extensions and bring it all together.
We open sourced alpha version yesterday, more documentation to come.
For example, if you are doing DDD and your repository implementation is about SQL, adding another layer of abstraction is not worth. But if your design is less sophisticated, or you are in an early stage of the project, you may find appealing to use that abstraction.
If I could compile back and forth between SQL and "fancyql" then using fancyql feels like an absolute no brainer to me?
I'm a lot less sympathetic to the "everyone already knows it" argument after dealing with SQL queries that are many hundred lines long.
The issue is with non relational dbs like redshift that do support sql it is very easy to write an innocent query that takes hours to run if you don’t use specific keys in the query (ones used for sharding). But then some kind of warning or query plan indication would help there.
Feels like there's a universe of difference between the experience of "carefully craft the query yourself" and "describe the query and let AI write the code for it."
LLMs work by hallucinating mashups of existing code examples stolen from webpages. Writing correct SQL for complex cases definitely needs real understanding, not just elaborate typeahead.
With LLM's, no one is ever going to need any query language starting effing now.
And good riddance to all of them too, I've yet to see one that made any kind of sense from the ease of use perspective.
I like SQL, but it has a few disadvantages compared to Datalog.
- In Datalog, queries and the data itself are homoiconic; the structure for both is exactly the same. Uses first-class variables to represent unknowns.
- Easy to compose queries (just tack on another predicate)
Of course it has the disadvantages that it's not widely supported (outside of Datomic/Clojure/Prolog ecosystem?), and not as popular, and maybe even more difficult to optimize [citation needed].
I would love to see a new Datalog-based DB. SQL-but-slightly-different-syntax is "lipstick on a pig" as they say, not very compelling IMO (and not really novel either, you can see it reinvented in every ORM).
„Select … from …“
it would be much better to write
„From … select …“.
PRQL got that right: https://prql-lang.org/