【问题标题】:Facing strange issue while executing Oracle Stored procedure执行 Oracle 存储过程时遇到奇怪的问题
【发布时间】:2020-01-17 23:26:43
【问题描述】:

我在执行 Oracle 存储过程时遇到了一个奇怪的问题。在将所选数据插入另一个数据时,我能够选择令人烦恼的数据 表。

下面是导致问题的查询。

BEGIN
EXECUTE IMMEDIATE
'INSERT INTO STG_MEMBER_MONTH_1
(
 MEMBER_ID
,EMPLOYER_GROUP_ID
,MEMBER_BIRTH_DATE
,SPAN_FROM_DATE
,GROUP_ID_FINAL
,GROUP_SIZE
,NAME_TO_BE_USED
,MEM_DOB
,MM
,MEMBER_AGE_FINAL
,ELIG_YEAR
,ELIG_MONTH
,AGE_BAND
)
WITH CTE_Member_Month_Group_Id_Final AS (
SELECT
 a.MEMBER_ID
,a.EMPLOYER_GROUP_ID
,a.MEMBER_BIRTH_DATE
,a.SPAN_FROM_DATE
b.ACCOUNT_NUM as GROUP_ID_FINAL
from STG_MEMBER_MONTH_2 a LEFT JOIN
(SELECT DISTINCT GRP_ID,ACCOUNT_NUM from ACCOUNT_MAPPING)b
ON a.EMPLOYER_GROUP_ID= b.GRP_ID)

,CTE_Member_Month_Group_Name as (
    SELECT a.*,b.GROUP_SIZE,b.GROUP_NAME as NAME_TO_BE_USED 
    from CTE_Member_Month_Group_Id_Final  a
    LEFT JOIN APP_CALENDAR b
    ON a.GROUP_ID_FINAL= b.GROUP_ID
)
,CTE_Max_DOB AS (
     SELECT a.MEMBER_ID,b.MEMBER_BIRTH_DATE AS MEM_DOB from
       (SELECT MEMBER_ID,max(SPAN_FROM_DATE) as SPAN_FROM_DATE from CTE_Member_Month_Group_Name
        GROUP BY MEMBER_ID)
     LEFT OUTER JOIN CTE_Member_Month_Group_Name b
     ON a.MEMBER_ID = b.MEMBER_ID
     AND a.SPAN_FROM_DATE = b.SPAN_FROM_DATE)
,CTE_Age_Band_Prev AS (
     SELECT a.*,b.MEM_DOB,1 as "MM"
    ,trunc(months_between(a.SPAN_FROM_DATE,B.MEM_DOB)/12) as "MEMBER_AGE_FINAL"
    ,extract(year from a.SPAN_FROM_DATE)                  as "ELIG_YEAR"
    ,extract(month from a.SPAN_FROM_DATE)                 as "ELIG_MONTH"
    from CTE_Member_Month_Group_Name a
    LEFT OUTER JOIN CTE_Max_DOB  b
    ON a.MEMBER_ID=b.MEMBER_ID
)
,CTE_Age_Band AS (
    SELECT a.*,
    CASE
        WHEN ltrim("MEMBER_AGE_FINAL") < 1 
        THEN 'Less than one year'
        WHEN ltrim("MEMBER_AGE_FINAL") > 17 and ltrim("MEMBER_AGE_FINAL") <=29 
        THEN '18 - 29 years'
        WHEN ltrim("MEMBER_AGE_FINAL") > 29 and ltrim("MEMBER_AGE_FINAL") <=39 
        THEN '29 - 39 years'
        ELSE 'More than 40 years'
    END as "AGE_BAND"
    from CTE_Age_Band_Prev a

)
SELECT * from CTE_Age_Band';
END;
/

我可以毫无问题地从 CTE_Age_Band 中选择所有内容,但无法将所选数据插入表 STG_MEMBER_MONTH_1。 我收到以下错误消息

ORA-06550: LINE 57,column 1:
PLS-00103: Encountered the symbol "," when expecting one of the following:

如果我从上面的语句中删除了最后一个 CTE CTE_Age_Band 并从插入语句中删除了列 AGE_BAND,它将被执行而没有任何错误。 修改后的逻辑如下图:

BEGIN
EXECUTE IMMEDIATE
'INSERT INTO STG_MEMBER_MONTH_1
(
 MEMBER_ID
,EMPLOYER_GROUP_ID
,MEMBER_BIRTH_DATE
,SPAN_FROM_DATE
,GROUP_ID_FINAL
,GROUP_SIZE
,NAME_TO_BE_USED
,MEM_DOB
,MM
,MEMBER_AGE_FINAL
,ELIG_YEAR
,ELIG_MONTH
)
WITH CTE_Member_Month_Group_Id_Final AS (
SELECT
 a.MEMBER_ID
,a.EMPLOYER_GROUP_ID
,a.MEMBER_BIRTH_DATE
,a.SPAN_FROM_DATE
b.ACCOUNT_NUM as GROUP_ID_FINAL
from STG_MEMBER_MONTH_2 a LEFT JOIN
(SELECT DISTINCT GRP_ID,ACCOUNT_NUM from ACCOUNT_MAPPING)b
ON a.EMPLOYER_GROUP_ID= b.GRP_ID)

,CTE_Member_Month_Group_Name as (
SELECT a.*,b.GROUP_SIZE,b.GROUP_NAME as NAME_TO_BE_USED from CTE_Member_Month_Group_Id_Final  a
LEFT JOIN APP_CALENDAR b
ON a.GROUP_ID_FINAL= b.GROUP_ID
)
,CTE_Max_DOB AS (
SELECT a.MEMBER_ID,b.MEMBER_BIRTH_DATE AS MEM_DOB from
       (SELECT MEMBER_ID,max(SPAN_FROM_DATE) as SPAN_FROM_DATE from CTE_Member_Month_Group_Name
        GROUP BY MEMBER_ID)
LEFT OUTER JOIN CTE_Member_Month_Group_Name b
ON a.MEMBER_ID = b.MEMBER_ID
AND a.SPAN_FROM_DATE = b.SPAN_FROM_DATE)
,CTE_Age_Band_Prev AS (
   SELECT a.*,b.MEM_DOB,1 as "MM"
   ,trunc(months_between(a.SPAN_FROM_DATE,B.MEM_DOB)/12) as "MEMBER_AGE_FINAL"
   ,extract(year from a.SPAN_FROM_DATE)                  as "ELIG_YEAR"
   ,extract(month from a.SPAN_FROM_DATE)                 as "ELIG_MONTH"
   from CTE_Member_Month_Group_Name a
   LEFT OUTER JOIN CTE_Max_DOB  b
   ON a.MEMBER_ID=b.MEMBER_ID
)
SELECT * from CTE_Age_Band_Prev';
END;
/

看起来最后一个 CTE 'CTE_Age_Band' 中有一些愚蠢的错误,我无法弄清楚。

【问题讨论】:

  • 即使通过语法着色,您也应该看到错误。
  • 那是什么?我对甲骨文很陌生。只是在做。从 sql server 到 oracle 的转换。

标签: oracle stored-procedures


【解决方案1】:

问题在于 SQL 字符串中的字符串文字。要将单引号放入字符串中,您需要将单引号加倍,即将其中两个并排放置:

BEGIN
EXECUTE IMMEDIATE
'INSERT INTO STG_MEMBER_MONTH_1
(
 MEMBER_ID
,EMPLOYER_GROUP_ID
,MEMBER_BIRTH_DATE
,SPAN_FROM_DATE
,GROUP_ID_FINAL
,GROUP_SIZE
,NAME_TO_BE_USED
,MEM_DOB
,MM
,MEMBER_AGE_FINAL
,ELIG_YEAR
,ELIG_MONTH
,AGE_BAND
)
WITH CTE_Member_Month_Group_Id_Final AS (
SELECT
 a.MEMBER_ID
,a.EMPLOYER_GROUP_ID
,a.MEMBER_BIRTH_DATE
,a.SPAN_FROM_DATE
b.ACCOUNT_NUM as GROUP_ID_FINAL
from STG_MEMBER_MONTH_2 a LEFT JOIN
(SELECT DISTINCT GRP_ID,ACCOUNT_NUM from ACCOUNT_MAPPING)b
ON a.EMPLOYER_GROUP_ID= b.GRP_ID)

,CTE_Member_Month_Group_Name as (
    SELECT a.*,b.GROUP_SIZE,b.GROUP_NAME as NAME_TO_BE_USED 
    from CTE_Member_Month_Group_Id_Final  a
    LEFT JOIN APP_CALENDAR b
    ON a.GROUP_ID_FINAL= b.GROUP_ID
)
,CTE_Max_DOB AS (
     SELECT a.MEMBER_ID,b.MEMBER_BIRTH_DATE AS MEM_DOB from
       (SELECT MEMBER_ID,max(SPAN_FROM_DATE) as SPAN_FROM_DATE from CTE_Member_Month_Group_Name
        GROUP BY MEMBER_ID)
     LEFT OUTER JOIN CTE_Member_Month_Group_Name b
     ON a.MEMBER_ID = b.MEMBER_ID
     AND a.SPAN_FROM_DATE = b.SPAN_FROM_DATE)
,CTE_Age_Band_Prev AS (
     SELECT a.*,b.MEM_DOB,1 as "MM"
    ,trunc(months_between(a.SPAN_FROM_DATE,B.MEM_DOB)/12) as "MEMBER_AGE_FINAL"
    ,extract(year from a.SPAN_FROM_DATE)                  as "ELIG_YEAR"
    ,extract(month from a.SPAN_FROM_DATE)                 as "ELIG_MONTH"
    from CTE_Member_Month_Group_Name a
    LEFT OUTER JOIN CTE_Max_DOB  b
    ON a.MEMBER_ID=b.MEMBER_ID
)
,CTE_Age_Band AS (
    SELECT a.*,
    CASE
        WHEN ltrim("MEMBER_AGE_FINAL") < 1 
        THEN ''Less than one year''
        WHEN ltrim("MEMBER_AGE_FINAL") > 17 and ltrim("MEMBER_AGE_FINAL") <=29 
        THEN ''18 - 29 years''
        WHEN ltrim("MEMBER_AGE_FINAL") > 29 and ltrim("MEMBER_AGE_FINAL") <=39 
        THEN ''29 - 39 years''
        ELSE ''More than 40 years''
    END as "AGE_BAND"
    from CTE_Age_Band_Prev a

)
SELECT * from CTE_Age_Band';
END;
/

【讨论】:

  • @bob-jarvis-reinstate-monica...你成就了我的一天。太感谢了。 Oracle 与 sql server 特别是过程执行有点不同。谢谢
  • “有点不同”? Oracle 是很多不同的,在很多方面比你意识到的要多得多。它们与根本不同。由于 rdbms 的架构和设计非常基本的方式,其中一个中的“最佳实践”通常是另一个中的“最差实践”。相似之处以 SELECT * FROM MYTABLE; 开头和结尾;
  • 确实想知道您为什么在这里使用EXECUTE IMMEDIATE,因为我认为您没有理由在这里需要它。 ?????
  • @Bob Jarvis - 恢复 Monica .. 我正在使用相同的程序即时创建 stg_member_month_2。我在第一个 cte 中使用过这个表。
  • 也许STG_MEMBER_MONTH_2 应该是一个全局临时表或类似的东西。至少构建一次并在运行时截断它,但不要经历不得不重新创建索引、访问权限等的痛苦——这也是一个大到足以让玛丽女王通过的安全漏洞。只是一个想法......
猜你喜欢
  • 2020-05-27
  • 2011-10-11
  • 1970-01-01
  • 2011-07-03
  • 2011-02-18
  • 2016-11-13
  • 2022-11-18
  • 1970-01-01
相关资源
最近更新 更多