SQLGlot: SQL parser, transpiler, optimizer – translate to Presto, Spark, Hive
github.com
github.com
The SQL is a monstrous language. Is there any trick that keeps the code simple?
[1] https://github.com/tobymao/sqlglot/blob/main/sqlglot/parser.... [2] https://github.com/duckdb/duckdb/blob/master/third_party/lib... [3] https://github.com/google/zetasql/blob/master/zetasql/parser...
select ... (select ...) as some_alias, ...
from ...
also, can't see SOME/ANY/ALLhttps://github.com/tobymao/sqlglot/blob/main/tests/fixtures/... https://github.com/tobymao/sqlglot/blob/main/tests/fixtures/...
You can see what it took to add this in this commit.
https://github.com/tobymao/sqlglot/commit/ab49a3a2964bdff3a3...
Was confused seeing these mentions of a select.py and why there would be any noticeable amount of semicolons in a Python file.
The code looks good
https://github.com/tobymao/sqlglot/blob/main/tests/fixtures/...
I can even parse and optimize TPC-H https://github.com/tobymao/sqlglot/blob/main/tests/fixtures/....
SQLGlot's parser handles a superset of SQL, so it's much more flexible than any one engine.
Something that I'm working on is a pure python SQL engine https://github.com/tobymao/sqlglot/blob/main/sqlglot/executo.... It does the whole shebang, parsing, optimizations, logical planning, physical execution.
I have a personal question if you don't mind -- I do some SQL query generation and transpilation for both work and hobby. One headache I've run into recently is generating nested EXISTS() subqueries.
Imagine you have something like this:
// WHERE Name = 'Audioslave'
{
type: "binary_op",
operator: "equal",
column: { path: [], name: "Name" },
value: { type: "scalar", value: "Audioslave" },
}
This is all fine, but what if you want to say "A binary operation on related entities": {
type: "binary_op",
operator: "equal",
column: { path: ["Albums", "Tracks"], name: "AlbumId" },
value: { type: "scalar", value: 40 },
},
Which you want to generate something like: WHERE EXISTS(SELECT 1 FROM Albums WHERE Albums.ForeignKey = t.PrimaryKey
AND EXISTS(SELECT 1 FROM Tracks WHERE Tracks.ForeignKey = Albums.PrimaryKey AND AlbumId = 40))
How to do this is giving me a headache for a lot of reasons and I can't seem to come up with a good way.
Any tips, references, or search terms to google?Thank you, look forward to digging in more + gave your repo a star!
i'm not exactly sure what you're asking though, in terms of sql generation, it's not difficult for me because i just take in sql and output sql from the ast
How permissive is the parser? Do you need to know the exact dialect up front or can it make some intelligent guesses for unknown UDFs etc?
We implement the core statistical model in SQL, and then use SQLGlot to transpile to the target execution engine. One big motivation was to futureproof our work - we're no longer tied down to Spark, and so when the 'next big thing' (GPU accelerated SQL for analytics?) comes along, it should be relatively straightforward to support it by writing another adaptor.
Working on this has highlighted some of the really tricky problems associated with translating between SQL engines, and we haven't hit any major problems, so kudos to the author!
[1] https://github.com/moj-analytical-services/splink/tree/splin...
First, the SQL involves complex analytical queries on large datasets that need careful pipelining, caching and optimisation. I wasn't sure the extent to which this was possible in sqlalchemy.
Second, it was important that our implementation of the em algorithm (a iterative numerical approach for maximising a likelihood function) was readable/understandable and I felt that readers of the code were more likely to know SQL than sqlalchemy. Certainly i was more comfortable expressing it in SQL than another (i.e. sqlalchemy's) API.
Third, our API allows the user to inject SQL to customise their data linking models and it felt more natural for this to be directly executed rather than go through an abstraction layer.
I'm not a sqlalchemy expert, but my sense is thats it's more appropriate for transaction/atomic SQL than for complex analytical queries
I can't say that I ever had to implement an EM algorithm that way though, so I can't say how complicated that would be. Certainly it'll take some more effort than writing it in a familiar SQL dialect. The main reason to do it would be that sqlalchemy has pretty good support for quite a lot of databases.
[0] https://datastation.multiprocess.io/blog/2022-04-11-sql-pars...