oracle 执行IMMEDIATE plsql

gv8xihay  于 2023-03-29  发布在  Oracle
关注(0)|答案(2)|浏览(202)

我遇到了以下错误:
ORA-00923:未在预期位置找到FROM关键字
在尝试构建plsql脚本时:

declare 
    yearmonth varchar2(20) := &yearmonth ; 
    begin 
    execute IMMEDIATE 'CREATE TABLE tbl_board_new_method AS  
    with a as (  
    select u.*,case when ooo.terminal_number is not null then "BOX" else "NOBOX" end ISBOX  from (
    select q.*,
    CASE WHEN   substr(i.min_trn_date, 0, 8) IS NOT NULL AND  substr(i.min_trn_date, 0, 8)  <  coalesce(   substr(i.install_date, 0, 8) , q.install_date )  THEN 
    coalesce(   substr(i.min_trn_date, 0, 8) , q.install_date,  substr(i.install_date, 0, 8))  ELSE 
    coalesce(q.install_date,
    substr(i.install_date, 0, 8),
    substr(i.min_trn_date, 0, 8))  END f_install_date, 
    nvl(q.disable_date, substr(i.disable_date, 0, 8)) f_disable_date,
    q.pos_model pos_model1,
    q.pos_brand pos_brand1,
    q.pos_brand_model pos_brand_model1 ,
    CASE
      WHEN UPPER(q.pos_model) IN
      (:COMBO,
      "DIALUP",
      "LAN",
    "BRANCH") THEN
    "POS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) IN
    ("PCPOS", "TYPICAL") THEN
    "PCPOS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) IN
    ("MPOS(BT/INTERNET)",
    "MPOS") THEN
    "MPOS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) =
    "GPRS" THEN
    "GPRS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) =
    "IPG" THEN
    "IPG"
    ELSE
    "POS"
    END
    END
    END
    END
    
    from trg.tbl_merchant_info q
    left join trg.mvw_terminal_indicators i  on (q.terminal_number = i.terminal_number)
    where coalesce(q.install_date,
    substr(i.install_date, 0, 8),
    substr(i.min_trn_date, 0, 8)) is not null
    and 
    CASE WHEN   substr(i.min_trn_date, 0, 8) IS NOT NULL AND  substr(i.min_trn_date, 0, 8) <    substr(i.install_date, 0, 8)  THEN 
    coalesce(   substr(i.min_trn_date, 0, 8) , q.install_date,  substr(i.install_date, 0, 8))  ELSE 
    coalesce(q.install_date,
    substr(i.install_date, 0, 8),
    substr(i.min_trn_date, 0, 8)) END   <=  '||yearmonth||'||30
    and (nvl(q.disable_date, substr(i.disable_date, 0, 8)) is null OR  nvl(q.disable_date, substr(i.disable_date, 0, 8)) >='||yearmonth||'||01
    ) 
    and (trim(q.pos_model) is null or
    not
    (upper(q.pos_model) like "%MPOS%"  ))
    --- union 
    UNION 
    select q.*,
    CASE WHEN   substr(i.min_trn_date, 0, 8) IS NOT NULL AND  substr(i.min_trn_date, 0, 8)  <    coalesce(   substr(i.install_date, 0, 8) , q.install_date )  THEN 
    coalesce(   substr(i.min_trn_date, 0, 8) , q.install_date,  substr(i.install_date, 0, 8))  ELSE 
    coalesce(q.install_date,
    substr(i.install_date, 0, 8),
    substr(i.min_trn_date, 0, 8))  END f_install_date,
    nvl(q.disable_date, substr(i.disable_date, 0, 8)) f_disable_date,
    q.pos_model pos_model1,
    q.pos_brand pos_brand1,
    q.pos_brand_model pos_brand_model1 ,
    CASE
    WHEN UPPER(q.pos_model) IN
    ("COMBO",
    "POS",
    "DIALUP",
    "LAN",
    "BRANCH") THEN
    "POS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) IN
    ("PCPOS", "TYPICAL") THEN
    "PCPOS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) IN
    ("MPOS(BT/INTERNET)",
    "MPOS") THEN
    "MPOS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) =
    "GPRS" THEN
    "GPRS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) =
    "IPG" THEN
    "IPG"
    ELSE
    "POS"
    END
    END
    END
    END
    END FINAL_POS_MODEL
    from   trg.tbl_merchant_info q  
    left join trg.mvw_terminal_indicators i
    on (q.terminal_number = i.terminal_number)
    WHERE q.terminal_number IN (SELECT terminalno FROM trg.fct_total_aggrigate_daily d  WHERE substr(trn_date,0,6) = substr('||yearmonth||',0,6) )  
    ) u left join (select * from  trg.mvw_terminal_indicators  ooo 
    where   ooo.box_install is not null and (box_uninstall is null or  substr(ooo.box_uninstall,0,8)>= '||yearmonth||'||01) )  ooo on (ooo.terminal_number = u.terminal_number )
    a.terminal_number = t111.terminalno (+) and a.terminal_number = tt211.terminalno (+) and 
    a.terminal_number = ttt311.terminalno (+) and a.terminal_number = tttt411.terminalno (+) and a.terminal_number = ttttt511.terminalno (+)
    )
    --, pre AS (
    select terminalid, 
    case when m.scale_install is not null then 1 else 0 end   scale_install  ,
    yearmonth
    from p  left join  trg.mvw_terminal_indicators m on (p.terminal_number = m.terminal_number)';
    end ;
bwitn5fc

bwitn5fc1#

问题的一部分是sql中的双引号字符串被认为是标识符。这里是一个小测试。

-- test data
CREATE TABLE a_table (ID Number(3), COL1 VarChar2(20), COL2 VarChar2(20));
INSERT INTO a_table VALUES(1, 'AAA', 'BBB');
INSERT INTO a_table VALUES(1, 'BBB', 'CCC');
INSERT INTO a_table VALUES(1, 'CCC', 'AAA');
--
--  Creating sql comands with double and single quated strings
SET SERVEROUTPUT ON
Declare
    sq      VarChar2(1) := '''';
    myID    Number(3) := 1;
    mySql   VarChar2(1000);
    mySql2  VarChar2(1000);
Begin
    mySql := 'Select COL1, COL2  From a_table Where COL1 IN("AAA") And ID = 1';
    DBMS_OUTPUT.PUT_LINE(mySql);
    --
    mySQL2 := 'Select COL1, COL2  From a_table Where COL1 IN(' || sq || 'AAA' || sq || ') And ID = 1';
    DBMS_OUTPUT.PUT_LINE(mySql2);
End;
/
--
--  double quated string in sql throws an error 
Select COL1, COL2  From a_table Where COL1 IN("AAA") And ID = 1
--      SQL Error: ORA-00904: "AAA": invalid identifier
--
-- this one works
Select COL1, COL2  From a_table Where COL1 IN('AAA') And ID = 1
--      COL1                 COL2               
--      -------------------- --------------------
--      AAA                  BBB

你的查询太大了,我无法分析,但是大多数问题可能是双引号。(''''--〉其中四个用单引号表示),然后,在编写sql命令时该变量用于将单引号放入命令中,其中有varchar类型的值。否则Oracle尝试查找标识符。关于...
添加:除了双引号之外,代码还有一些其他问题。我从你的问题中提取了它,并将其结构化以使其更具可读性。下面的代码中注解了问题,有些代码缺失,有些错误,有些我无法理解。下面是结构化版本,问题在[26,45,107,116,124,125,126,127,127,128,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129125]和在主SELECT [行128 - 138]你会知道的东西,我没有抓住,也许使它的工作...

CREATE TABLE 
    tbl_board_new_method AS 
        
    with a as 
        (  
            Select 
                u.*,
                CASE WHEN ooo.terminal_number Is Not Null THEN "BOX" ELSE "NOBOX" END as ISBOX  
            From 
                (
                    Select 
                        q.*,
                        CASE 
                            WHEN substr(i.min_trn_date, 0, 8) IS NOT NULL AND  substr(i.min_trn_date, 0, 8)  <  coalesce(substr(i.install_date, 0, 8) , q.install_date )  
                            THEN coalesce(substr(i.min_trn_date, 0, 8) , q.install_date,  substr(i.install_date, 0, 8))  
                        ELSE 
                            coalesce(q.install_date, substr(i.install_date, 0, 8), substr(i.min_trn_date, 0, 8))  
                        END as F_INSTALL_DATE, 
                        --
                        Nvl(q.disable_date, substr(i.disable_date, 0, 8)) as F_DISABLE_DATE,
                        q.pos_model as POS_MODEL1,
                        q.pos_brand as POS_BRAND1,
                        q.pos_brand_model as POS_BRAND_MODEL1,
                        --
                        CASE
                          WHEN UPPER(q.pos_model) IN(:COMBO, "DIALUP", "LAN", "BRANCH") THEN "POS"              -- here was :COMBO -> I put "COMBO" as it is in second (unioned) query
                        ELSE
                            CASE
                                WHEN UPPER(q.pos_model) IN("PCPOS", "TYPICAL") THEN "PCPOS"
                            ELSE
                                CASE
                                    WHEN UPPER(q.pos_model) IN("MPOS(BT/INTERNET)", "MPOS") THEN "MPOS"
                                ELSE
                                    CASE
                                        WHEN UPPER(q.pos_model) = "GPRS" THEN "GPRS"
                                    ELSE
                                        CASE
                                            WHEN UPPER(q.pos_model) = "IPG" THEN "IPG"
                                        ELSE
                                            "POS"
                                        END
                                    END
                                END
                            END
                        END  as FINAL_POS_MODEL         -- this row was missing
                    From 
                        trg.tbl_merchant_info q
                    Left Join 
                        trg.mvw_terminal_indicators i ON(q.terminal_number = i.terminal_number)
                    Where 
                        coalesce(q.install_date, substr(i.install_date, 0, 8), substr(i.min_trn_date, 0, 8)) is not null And 
                        CASE 
                            WHEN substr(i.min_trn_date, 0, 8) Is Not Null And substr(i.min_trn_date, 0, 8) < substr(i.install_date, 0, 8)  
                            THEN coalesce(substr(i.min_trn_date, 0, 8) , q.install_date,  substr(i.install_date, 0, 8))  
                        ELSE 
                            coalesce(q.install_date, substr(i.install_date, 0, 8), substr(i.min_trn_date, 0, 8)) END <= ' || yearmonth || ' || 30 And
                            (
                                nvl(q.disable_date, substr(i.disable_date, 0, 8)) is null OR  nvl(q.disable_date, substr(i.disable_date, 0, 8)) >= '|| yearmonth ||' || 01
                            ) And 
                            (trim(q.pos_model) is null 
                          OR 
                            Not (Upper(q.pos_model) like "%MPOS%"))
                    --
                    --
                  UNION 
                    --
                    --
                    Select 
                        q.*,
                        CASE 
                            WHEN substr(i.min_trn_date, 0, 8) Is Not Null And  substr(i.min_trn_date, 0, 8) < coalesce(substr(i.install_date, 0, 8) , q.install_date )  
                            THEN coalesce(substr(i.min_trn_date, 0, 8) , q.install_date,  substr(i.install_date, 0, 8))  
                        ELSE 
                            coalesce(q.install_date, substr(i.install_date, 0, 8), substr(i.min_trn_date, 0, 8))  
                        END as F_INSTALL_DATE, 
                        Nvl(q.disable_date, substr(i.disable_date, 0, 8)) as F_DISABLE_DATE,
                        q.pos_model as POS_MODEL1,
                        q.pos_brand as POS_BRAND1,
                        q.pos_brand_model as POS_BRAND_MODEL1 ,
                        CASE
                            WHEN UPPER(q.pos_model) IN("COMBO", "POS", "DIALUP", "LAN", "BRANCH") THEN "POS"
                        ELSE
                            CASE
                                WHEN UPPER(q.pos_model) IN("PCPOS", "TYPICAL") THEN "PCPOS"
                            ELSE
                                CASE
                                    WHEN UPPER(q.pos_model) IN("MPOS(BT/INTERNET)", "MPOS") THEN "MPOS"
                                ELSE
                                    CASE
                                        WHEN UPPER(q.pos_model) = "GPRS" THEN "GPRS"
                                    ELSE
                                        CASE
                                            WHEN UPPER(q.pos_model) = "IPG" THEN "IPG"
                                        ELSE
                                            "POS"
                                        END
                                    END
                                END
                            END
                        END as FINAL_POS_MODEL
                    From   
                        trg.tbl_merchant_info q  
                    Left Join 
                        trg.mvw_terminal_indicators i ON(q.terminal_number = i.terminal_number)
                    Where 
                        q.terminal_number IN(   SELECT terminalno 
                                                FROM trg.fct_total_aggrigate_daily -- d -> table alias d excluded as not needed nor used in subquery
                                                WHERE substr(trn_date, 0, 6) = substr(' || yearmonth || ', 0, 6)
                                            )  
                ) u 
            Left Join 
                (
                    select 
                        * 
                    from  
                        trg.mvw_terminal_indicators ooo         -- ooo here as table alias is the same as the whole subquery alias  --> it can stay (used in where) but confusing 
                    Where 
                        ooo.box_install Is Not Null And 
                        (
                            box_uninstall Is Null OR substr(ooo.box_uninstall,0,8) >= ' || yearmonth || ' || 01
                        ) 
                )  ooo ON(ooo.terminal_number = u.terminal_number) 
        -- there should probably be WHERE clause here but I don't know what are next 2 lines - using alias [a] before it was created !?? (closing bracket in third line below ends creation of CTE named a) 
            a.terminal_number = t111.terminalno (+) and a.terminal_number = tt211.terminalno (+) and 
            a.terminal_number = ttt311.terminalno (+) and a.terminal_number = tttt411.terminalno (+) and a.terminal_number = ttttt511.terminalno (+)
        )
-- after end of creation of CTE named [a] (line 126) --> below should be the main select but you are selecting FROM p (what is p) joined with trg.mvw_terminal_indicators (nothing selected from [a])
SELECT 
    terminalid, 
    CASE 
        WHEN m.scale_install Is Not Null THEN 1 
    ELSE 0 
    END as SCALE_INSTALL,
    yearmonth       
FROM 
    p  -- what is p   -->   you are not selecting anything from (CTE) named [a]
LEFT JOIN  
    trg.mvw_terminal_indicators m ON(p.terminal_number = m.terminal_number)

仍然存在双引号问题,但可以使用任何文本编辑器解决。声明变量以保存SQL代码字符串,声明sq变量并将'''作为其值,并将["]替换为['||平方||']。然后打印代码(DBMS_OUTPUT),复制它,检查它并运行它。可能会有更多的更正要做,但你会得到错误消息,什么地方有问题。

pb3s4cty

pb3s4cty2#

你可以使用带引号的字符串,像这样:

declare 
    yearmonth varchar2(20) := &yearmonth ; 
    begin 
    execute IMMEDIATE q'[CREATE TABLE tbl_board_new_method AS  
    with a as (  
    select u.*,case when ooo.terminal_number is not null then "BOX" else "NOBOX" end ISBOX  from (
    select q.*,
    CASE WHEN   substr(i.min_trn_date, 0, 8) IS NOT NULL AND  substr(i.min_trn_date, 0, 8)  <  coalesce(   substr(i.install_date, 0, 8) , q.install_date )  THEN 
    coalesce(   substr(i.min_trn_date, 0, 8) , q.install_date,  substr(i.install_date, 0, 8))  ELSE 
    coalesce(q.install_date,
    substr(i.install_date, 0, 8),
    substr(i.min_trn_date, 0, 8))  END f_install_date, 
    nvl(q.disable_date, substr(i.disable_date, 0, 8)) f_disable_date,
    q.pos_model pos_model1,
    q.pos_brand pos_brand1,
    q.pos_brand_model pos_brand_model1 ,
    CASE
      WHEN UPPER(q.pos_model) IN
      (:COMBO,
      "DIALUP",
      "LAN",
    "BRANCH") THEN
    "POS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) IN
    ("PCPOS", "TYPICAL") THEN
    "PCPOS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) IN
    ("MPOS(BT/INTERNET)",
    "MPOS") THEN
    "MPOS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) =
    "GPRS" THEN
    "GPRS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) =
    "IPG" THEN
    "IPG"
    ELSE
    "POS"
    END
    END
    END
    END
    
    from trg.tbl_merchant_info q
    left join trg.mvw_terminal_indicators i  on (q.terminal_number = i.terminal_number)
    where coalesce(q.install_date,
    substr(i.install_date, 0, 8),
    substr(i.min_trn_date, 0, 8)) is not null
    and 
    CASE WHEN   substr(i.min_trn_date, 0, 8) IS NOT NULL AND  substr(i.min_trn_date, 0, 8) <    substr(i.install_date, 0, 8)  THEN 
    coalesce(   substr(i.min_trn_date, 0, 8) , q.install_date,  substr(i.install_date, 0, 8))  ELSE 
    coalesce(q.install_date,
    substr(i.install_date, 0, 8),
    substr(i.min_trn_date, 0, 8)) END   <=  '||yearmonth||'||30
    and (nvl(q.disable_date, substr(i.disable_date, 0, 8)) is null OR  nvl(q.disable_date, substr(i.disable_date, 0, 8)) >='||yearmonth||'||01
    ) 
    and (trim(q.pos_model) is null or
    not
    (upper(q.pos_model) like "%MPOS%"  ))
    --- union 
    UNION 
    select q.*,
    CASE WHEN   substr(i.min_trn_date, 0, 8) IS NOT NULL AND  substr(i.min_trn_date, 0, 8)  <    coalesce(   substr(i.install_date, 0, 8) , q.install_date )  THEN 
    coalesce(   substr(i.min_trn_date, 0, 8) , q.install_date,  substr(i.install_date, 0, 8))  ELSE 
    coalesce(q.install_date,
    substr(i.install_date, 0, 8),
    substr(i.min_trn_date, 0, 8))  END f_install_date,
    nvl(q.disable_date, substr(i.disable_date, 0, 8)) f_disable_date,
    q.pos_model pos_model1,
    q.pos_brand pos_brand1,
    q.pos_brand_model pos_brand_model1 ,
    CASE
    WHEN UPPER(q.pos_model) IN
    ("COMBO",
    "POS",
    "DIALUP",
    "LAN",
    "BRANCH") THEN
    "POS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) IN
    ("PCPOS", "TYPICAL") THEN
    "PCPOS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) IN
    ("MPOS(BT/INTERNET)",
    "MPOS") THEN
    "MPOS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) =
    "GPRS" THEN
    "GPRS"
    ELSE
    CASE
    WHEN UPPER(q.pos_model) =
    "IPG" THEN
    "IPG"
    ELSE
    "POS"
    END
    END
    END
    END
    END FINAL_POS_MODEL
    from   trg.tbl_merchant_info q  
    left join trg.mvw_terminal_indicators i
    on (q.terminal_number = i.terminal_number)
    WHERE q.terminal_number IN (SELECT terminalno FROM trg.fct_total_aggrigate_daily d  WHERE substr(trn_date,0,6) = substr('||yearmonth||',0,6) )  
    ) u left join (select * from  trg.mvw_terminal_indicators  ooo 
    where   ooo.box_install is not null and (box_uninstall is null or  substr(ooo.box_uninstall,0,8)>= '||yearmonth||'||01) )  ooo on (ooo.terminal_number = u.terminal_number )
    a.terminal_number = t111.terminalno (+) and a.terminal_number = tt211.terminalno (+) and 
    a.terminal_number = ttt311.terminalno (+) and a.terminal_number = tttt411.terminalno (+) and a.terminal_number = ttttt511.terminalno (+)
    )
    --, pre AS (
    select terminalid, 
    case when m.scale_install is not null then 1 else 0 end   scale_install  ,
    yearmonth
    from p  left join  trg.mvw_terminal_indicators m on (p.terminal_number = m.terminal_number)]';
    end ;

Oracle documentation here

相关问题