In a legacy system we want to copy a lot of productive data/tables in other tables in a stored procedure.
That all copied data is consistent with each other, we want to use the <tableName> as of scn <scnNumber>.
The SQL seemed to be correct in the stored procedure, but compiling failed with ORA-00984: column not allowed here. A lot of other queries compile without any problem.
After reducing the SQL to a simple PL/SQL block and building up the SQL I found the "problem cause" - as of scn v_scn does not work with any (following) table alias:
declare
     v_scn number := 29058161423; -- in productive code calculated 
begin
    insert into temp_currency (currency_id, currency_code, currency_rate, currency_version)
    with rates_now as (
         select icr.currencyrate_currencyid currencyId, max(icr.currencyrate_date) mostRecentDate
         from t_currencyrate as of scn v_scn icr
         group by icr.currencyrate_currencyid
    )
    select cur.currency_id, cur.currency_code, 1.23 currencyrate_rate, cur.currency_version       
    from t_currency as of scn v_scn cur
    join rates_now ran
        on ran.currencyId = cur.currency_id
    join t_currencyrate as of scn v_scn  cra
        on ran.currencyId = cra.currencyrate_currencyid
            and ran.mostRecentDate = cra.currencyrate_date;
 end;
 /
This returns:
ORA-00984: column not allowed here
Following the link https://stackoverflow.com/a/51878828/26515477 and using as of scn(v_scn) brought the same error:
declare
     v_scn number := 29058161423; -- in productive code calculated 
begin
    insert into temp_currency (currency_id, currency_code, currency_rate, currency_version)
    with rates_now as (
         select icr.currencyrate_currencyid currencyId, max(icr.currencyrate_date) mostRecentDate
         from t_currencyrate as of scn(v_scn) icr
         group by icr.currencyrate_currencyid
    )
    select cur.currency_id, cur.currency_code, 1.23 currencyrate_rate, cur.currency_version       
    from t_currency as of scn(v_scn) cur
    join rates_now ran
        on ran.currencyId = cur.currency_id
    join t_currencyrate as of scn(v_scn) cra
        on ran.currencyId = cra.currencyrate_currencyid
            and ran.mostRecentDate = cra.currencyrate_date;
 end;
 /
Currently I found only these solutions
With Dynamic SQL, String Concatenation and Hard Coded SCN
... with dynamic SQL - here with ... as of scn(<scnValue>)::
declare
     v_scn number := 2905861122894; -- in productive code calculated
begin
    execute immediate ' -- has to be dynamic SQL, else ORA-00984: column not allowed here
        insert into temp_currency (currency_id, currency_code, currency_rate, currency_version)
        with rates_now as (
            select icr.currencyrate_currencyid currencyId, max(icr.currencyrate_date) mostRecentDate 
            from t_currencyrate as of scn(' || v_scn || ') icr
            group by icr.currencyrate_currencyid
        )
        select cur.currency_id, cur.currency_code, 1.23 currencyrate_rate, cur.currency_version
        from t_currency as of scn(' || v_scn || ') cur
        join rates_now ran
             on ran.currencyId = cur.currency_id
        join t_currencyrate as of scn(' || v_scn || ')  cra
             on ran.currencyId = cra.currencyrate_currencyid
                 and ran.mostRecentDate = cra.currencyrate_date
     '; 
end; 
/
or with ... as of scn <scnValue>:
declare
     v_scn number := 2905861122894; -- in productive code calculated
begin
    execute immediate ' -- has to be dynamic SQL, else ORA-00984: column not allowed here
        insert into temp_currency (currency_id, currency_code, currency_rate, currency_version)
        with rates_now as (
            select icr.currencyrate_currencyid currencyId, max(icr.currencyrate_date) mostRecentDate 
            from t_currencyrate as of scn ' || v_scn || ' icr
            group by icr.currencyrate_currencyid
        )
        select cur.currency_id, cur.currency_code, 1.23 currencyrate_rate, cur.currency_version
        from t_currency as of scn ' || v_scn || ' cur
        join rates_now ran
             on ran.currencyId = cur.currency_id
        join t_currencyrate as of scn ' || v_scn || ' cra
             on ran.currencyId = cra.currencyrate_currencyid
                 and ran.mostRecentDate = cra.currencyrate_date
     '; 
end; 
/
These solutions have the disadvantage, if there are ' somewhere in the regular SQL I have to escape these or use (partial) q string literals. I find that awkward.
With Dynamic SQL and Repeating Input Variable
declare
     v_scn number := 2905861122894; -- in productive code calculated 
begin
    execute immediate ' -- has to be dynamic SQL, else ORA-00984: column not allowed here
        insert into temp_currency (currency_id, currency_code, currency_rate, currency_version)
        with rates_now as (
             select icr.currencyrate_currencyid currencyId, max(icr.currencyrate_date) mostRecentDate
             from t_currencyrate as of scn :1 icr
             group by icr.currencyrate_currencyid 
        )             
        select cur.currency_id, cur.currency_code, 1.23 currencyrate_rate, cur.currency_version
        from t_currency as of scn :1 cur
        join rates_now ran
            on ran.currencyId = cur.currency_id 
        join t_currencyrate as of scn :1 cra 
            on ran.currencyId = cra.currencyrate_currencyid
                and ran.mostRecentDate = cra.currencyrate_date
     ' using v_scn, v_scn, v_scn;
end;
/
Above code is the same, no matter if I used :1 or :v_scn and as of scn :... or as of scn(:...) - I have to repeat the value in the using term for every occurrence! And still: if there are ' somewhere in the regular SQL I have to escape these or use (partial) q string literals. I find both awkward.
Is there any other working solution without "akward" disadvantages?
You can get ORA-00984: column not allowed here when using ANSI joins in a flashback query. This is Bug 32568211 on Oracle Support, but it doesn't really give any details.
Try rewriting your query with Oracle syntax:
insert into temp_currency (currency_id, currency_code, currency_rate, currency_version)
    with rates_now as (
         select icr.currencyrate_currencyid currencyId, max(icr.currencyrate_date) mostRecentDate
         from t_currencyrate as of scn v_scn icr
         group by icr.currencyrate_currencyid
    )
    select cur.currency_id, cur.currency_code, 1.23 currencyrate_rate, cur.currency_version       
    from t_currency as of scn v_scn cur,
         rates_now ran,
         t_currencyrate as of scn v_scn cra
    where ran.currencyId = cur.currency_id
      and ran.currencyId = cra.currencyrate_currencyid
      and ran.mostRecentDate = cra.currencyrate_date
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With