Hello,

I'm working with an EXASOL database 
(https://github.com/blue-yonder/sqlalchemy_exasol) and have an insert 
statement containing a common table expression. In a very simplified way:


from sqlalchemy import MetaData, Table, Column, Integer, select

metadata = MetaData()


table_A = Table("table_A", metadata,
              Column("int", Integer))

table_B = Table("table_B", metadata,
              Column("int", Integer))

table_C = Table("table_C", metadata,
              Column("int", Integer))


cte = select(
    columns=[table_A.c.int],
    from_obj=table_A).cte("cte")
query = select(
    columns=[table_B.c.int],
    from_obj=table_B.join(cte, onclause=table_B.c.int == cte.c.int))
insert = table_C.insert().from_select(['int'], query)


If you print the insert statement you will end up with

WITH cte AS
(SELECT "table_A".int AS int
FROM "table_A")
 INSERT INTO "table_C" (int) SELECT "table_B".int
FROM "table_B" JOIN cte ON "table_B".int = cte.int

But the EXASOL dialect will complain (syntax error, unexpected INSERT_, 
expecting SELECT_ or TABLE_ or VALUES_ or '(') because the expected syntax 
would be the WITH statement before the SELECT directly:

INSERT INTO "table_C" (int)
WITH cte AS
(SELECT "table_A".int AS int
FROM "table_A")
SELECT "table_B".int
FROM "table_B" JOIN cte ON "table_B".int = cte.int

The sqlalchemy-exasol dialect should handle this difference to standard SQL 
syntax. But it would be quite hard to handle this differently because the 
section in the code is embeded deep into complex methods:
* before INSERT: 
https://bitbucket.org/zzzeek/sqlalchemy/src/55ad10370f9eb50795e136aac595193168982e92/lib/sqlalchemy/sql/compiler.py?at=master#compiler.py-2049
* before SELECT: 
https://bitbucket.org/zzzeek/sqlalchemy/src/55ad10370f9eb50795e136aac595193168982e92/lib/sqlalchemy/sql/compiler.py?at=master#compiler.py-1750

One option to handle this would be to refactor the following line
https://bitbucket.org/zzzeek/sqlalchemy/src/55ad10370f9eb50795e136aac595193168982e92/lib/sqlalchemy/sql/compiler.py?at=master#compiler.py-1664
with

toplevel = self._is_toplevel_select()


and a method containing

def _is_toplevel_select(self):
    return not self.stack


which could be overwritten in sqlalchemy-exasol with something like:

def _is_toplevel_select(self):
    stack = [element for element in self.stack
             if isinstance(element["selectable"], FromClause)]
    return not stack


and with the visit_insert method accordingly:
https://bitbucket.org/zzzeek/sqlalchemy/src/55ad10370f9eb50795e136aac595193168982e92/lib/sqlalchemy/sql/compiler.py?at=master#compiler.py-1960


This might not a proper solution since I do not know the compiler module 
very good.

I would be very happy if you have some thoughts about this and if you think 
it would be of some use to allowing the sqlalchemy-exasol dialect to handle 
this without reimplementing the big visit_insert/select/update/delete 
methods for the corner case.


Best regards,
Joerg

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to