Here's that, also the literal() has to be against the regular value 1
and not the string else it casts as string:

from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session, aliased
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import Select
import re


@compiles(Select, "oracle")
def _add_search_hints(element, compiler, **kw):
    text = compiler.visit_select(element, **kw)
    for prefix, _ in element._prefixes:
        prefix = prefix.text
        text = re.sub(r'SELECT %s' % prefix, "%s SELECT" % prefix, text)
    return text

Base = declarative_base()


class JobMst(Base):
    __tablename__ = 'jobmst'

    jobmst_id = Column(Integer, primary_key=True)
    jobmst_name = Column(String(50))
    jobmst_prntid = Column(Integer)
    jobmst_type = Column(String(10))

e = create_engine("oracle://scott:tiger@oracle1120", echo=True)
Base.metadata.create_all(e)

s = Session(e)

j2 = aliased(JobMst, name="j2")

j1 = s.query(
    JobMst.jobmst_id, JobMst.jobmst_name, JobMst.jobmst_prntid,
    JobMst.jobmst_type, literal(1).label("lvl")
).filter(JobMst.jobmst_prntid == None).cte(recursive=True, name="j1")
j1 = j1.union_all(
    s.query(
        j2.jobmst_id, j2.jobmst_name,
        j2.jobmst_prntid, j2.jobmst_type, j1.c.lvl + literal(1)).join(
        j1, j2.jobmst_prntid == j1.c.jobmst_id
    ).filter(j2.jobmst_prntid != None)
)

stmt = s.query(j1).prefix_with(
    "SEARCH DEPTH FIRST BY JOBMST_NAME SET DISP_SEQ"
).order_by(text("DISP_SEQ"))

stmt.all()


please modify the database URL and optionally the column names if they
are wrong and run this as is.



On Thu, Apr 26, 2018 at 5:42 PM, Mike Bayer <[email protected]> wrote:
> the issue is that your original query ends with:
>
>         SEARCH DEPTH FIRST BY JOBMST_NAME SET DISP_SEQ
>             SELECT *
>             FROM J1 ORDER BY DISP_SEQ
>
> and I gave you:
>
>           SEARCH DEPTH FIRST BY JOBMST_NAME SET DISP_SEQ
>          SELECT
>              j1.jobmst_id,
>              j1.jobmst_name,
>              j1.jobmst_prntid,
>              j1.jobmst_type,
>              j1.lvl
>             FROM j1 ORDER BY DISP_SEQ
>
> I apologize for this mistake.
>
> Basically it's not appropriate to use select.with_prefix() in this
> particular case as it applies prefixes subsequent to the SELECT
> keyword.  The SQLAlchemy Oracle dialect does not currently have
> support for special strings added in front of the SELECT keyword.    I
> can provide you with a recipe that allows for this to be possible,
> however, as a practical matter, this query is Oracle-specific in any
> case, is there a reason you can't just use text() ?   The reason
> text() exists is for when one has the exact SQL they want already and
> there is no need to work it into the expression language.
>
> If you want to continue using the expression language I can show you a
> recipe to add those special keywords to the left side of the SELECT
> keyword.
>
>
>
>
>
>
>
> On Thu, Apr 26, 2018 at 5:33 PM, Mike Bayer <[email protected]> wrote:
>> OK, your original SQL works, will find the difference
>>
>> On Thu, Apr 26, 2018 at 5:32 PM, Mike Bayer <[email protected]> wrote:
>>> Jeremy -
>>>
>>> This whole thread is based on an exact SQL that you have asked for,
>>> and that was the query I gave you.   Going back to the script I
>>> posted, the SQL output when I run it via query.all() vs. just
>>> query.statement.compile() is identical except for the label names
>>> applied to the final column names, which is not the cause of this
>>> error.
>>>
>>> please give me **the exact SQL statement that you know runs
>>> correctly** and I will show you how to render it.
>>>
>>>
>>> On Thu, Apr 26, 2018 at 5:30 PM, Jeremy Flowers
>>> <[email protected]> wrote:
>>>> Does this need to be submitted as an error on Git somewhere?
>>>>
>>>> On Thu, Apr 26, 2018 at 10:29 PM, Jeremy Flowers
>>>> <[email protected]> wrote:
>>>>>
>>>>> I can confirm. I copied and pasted Mike's Python verbatim, and got exactly
>>>>> same issues with generated SQL
>>>>>
>>>>> On Thu, Apr 26, 2018 at 10:21 PM, Jeremy Flowers
>>>>> <[email protected]> wrote:
>>>>>>
>>>>>> I hacked the parameterised query:
>>>>>> This works..
>>>>>> WITH j1(jobmst_id, jobmst_name, jobmst_prntid, jobmst_type, lvl) AS (
>>>>>>    (SELECT jobmst.jobmst_id AS jobmst_id, jobmst.jobmst_name AS
>>>>>> jobmst_name, jobmst.jobmst_prntid AS jobmst_prntid, jobmst.jobmst_type AS
>>>>>> jobmst_type, 1 AS lvl
>>>>>>     FROM jobmst
>>>>>>     WHERE jobmst.jobmst_prntid IS NULL
>>>>>> )
>>>>>> UNION ALL
>>>>>> SELECT j2.jobmst_id AS j2_jobmst_id, j2.jobmst_name AS j2_jobmst_name,
>>>>>> j2.jobmst_prntid AS j2_jobmst_prntid, j2.jobmst_type AS j2_jobmst_type,
>>>>>> j1.lvl + 1 As lvl
>>>>>> FROM jobmst j2
>>>>>> JOIN j1 ON j2.jobmst_prntid = j1.jobmst_id
>>>>>> WHERE j2.jobmst_prntid IS NOT NULL
>>>>>> )
>>>>>>  SEARCH DEPTH FIRST BY JOBMST_NAME SET DISP_SEQ
>>>>>> SELECT j1.jobmst_id, j1.jobmst_name, j1.jobmst_prntid, j1.jobmst_type,
>>>>>> j1.lvl
>>>>>> FROM j1 ORDER BY DISP_SEQ
>>>>>>
>>>>>> So, the AS names are ok it seems... But, the SELECT should come after
>>>>>> DISP_SEQ too
>>>>>>
>>>>>> On Thu, Apr 26, 2018 at 10:17 PM, Jeremy Flowers
>>>>>> <[email protected]> wrote:
>>>>>>>
>>>>>>> Mike I know what the problem is.
>>>>>>> The SQL emitted by SQLAlchemy is wrong!
>>>>>>> This is why I get: ORA-00923: FROM keyword not found where expected. You
>>>>>>> only get error code when you try to execute the code - with first(), 
>>>>>>> all(),
>>>>>>> slice()
>>>>>>> Look for the <----- in the generated code.... (x4)
>>>>>>>
>>>>>>> ====
>>>>>>> This is my Original SQL:
>>>>>>>
>>>>>>> WITH J1(JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, LVL) AS  (
>>>>>>>   SELECT * FROM (
>>>>>>>     SELECT JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, 1
>>>>>>>     FROM TIDAL.JOBMST
>>>>>>>     WHERE JOBMST_PRNTID IS NULL
>>>>>>>   )
>>>>>>> UNION ALL
>>>>>>> SELECT J2.JOBMST_ID, J2.JOBMST_NAME, J2.JOBMST_PRNTID, J2.JOBMST_TYPE,
>>>>>>> J1.LVL + 1
>>>>>>> FROM TIDAL.JOBMST J2
>>>>>>> INNER JOIN J1 ON J2.JOBMST_PRNTID = J1.JOBMST_ID
>>>>>>> WHERE J2.JOBMST_PRNTID IS NOT NULL
>>>>>>> )
>>>>>>> SEARCH DEPTH FIRST BY JOBMST_NAME SET DISP_SEQ
>>>>>>> SELECT *
>>>>>>> FROM J1
>>>>>>> ORDER BY DISP_SEQ
>>>>>>> ===
>>>>>>>
>>>>>>> This is the code output by printing the Oracle dialect:
>>>>>>>
>>>>>>> WITH j1(jobmst_id, jobmst_name, jobmst_prntid, jobmst_type, lvl) AS .
>>>>>>> <----- Look no opening parenthesis
>>>>>>>    (SELECT jobmst.jobmst_id AS jobmst_id, jobmst.jobmst_name AS
>>>>>>> jobmst_name, jobmst.jobmst_prntid AS jobmst_prntid, jobmst.jobmst_type 
>>>>>>> AS
>>>>>>> jobmst_type, :param_1 AS lvl
>>>>>>>     FROM jobmst
>>>>>>>     WHERE jobmst.jobmst_prntid IS NULL
>>>>>>>
>>>>>>> <!----- LOOK no closing parenthesis
>>>>>>> UNION ALL
>>>>>>> SELECT j2.jobmst_id AS j2_jobmst_id, j2.jobmst_name AS j2_jobmst_name,
>>>>>>> j2.jobmst_prntid AS j2_jobmst_prntid, j2.jobmst_type AS j2_jobmst_type,
>>>>>>> j1.lvl + :lvl_1 AS anon_1 .   <!----- the AS names should match what's
>>>>>>> inside WITH()
>>>>>>> FROM jobmst j2
>>>>>>> JOIN j1 ON j2.jobmst_prntid = j1.jobmst_id
>>>>>>> WHERE j2.jobmst_prntid IS NOT NULL
>>>>>>> )
>>>>>>> SELECT SEARCH DEPTH FIRST BY JOBMST_NAME SET DISP_SEQ j1.jobmst_id,
>>>>>>> j1.jobmst_name, j1.jobmst_prntid, j1.jobmst_type, j1.lvl .  <----- There
>>>>>>> should be no SELECT before SEARCH (my why prefix - should be suffix)
>>>>>>> FROM j1 ORDER BY DISP_SEQ
>>>>>>>
>>>>>>> ===
>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>> --
>>>> 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.

-- 
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