创建oracle函数时出现问题

时间:2018-07-24 14:09:29

标签: oracle oracle11g oracle10g

我创建了一个需要输入month(11)和year(2018)的函数,它将返回下个月的第一个星期日。

Create or replace function get_effectivedate (par_Month in int,Par_Year in int);

Return date

Is 

    startDate varchar;
    edate date;

    begin
    startDate := par_Month+Par_Year;
    edate     := select  next_day(add_months(trunc(startDate, 'MM'), 1), 'Sunday') as EffectiveDate from dual; 

     return edate;
     end;

此功能在运行时提示我,并且在编译时引发一些错误。

错误:

LINE/COL  ERROR
--------- -------------------------------------------------------------
7/1       PLS-00103: Encountered the symbol "BEGIN" when expecting one of the following:     := . ( @ % ; not null range with default character The symbol ";" was substituted for "BEGIN" to continue. 
9/14      PLS-00103: Encountered the symbol "SELECT" when expecting one of the following:     ( - + case mod new not null <an identifier>    <a double-quoted delimited-identifier> <a bind variable>    continue avg count current exists max min prior sql stddev    sum variance execute forall merge time timestamp interval    date <a string literal with character set specification>    <a number> <a single-quoted SQL string> pipe    <an alternatively-quoted string literal with character set specification>    <an alternat
11/2      PLS-00103: Encountered the symbol "RETURN" 
Errors: check compiler log

Function GET_EFFECTIVEDATE compiled

LINE/COL  ERROR
--------- -------------------------------------------------------------
7/1       PLS-00103: Encountered the symbol "BEGIN" when expecting one of the following:     := . ( @ % ; not null range with default character The symbol ";" was substituted for "BEGIN" to continue. 
9/14      PLS-00103: Encountered the symbol "SELECT" when expecting one of the following:     ( - + case mod new not null <an identifier>    <a double-quoted delimited-identifier> <a bind variable>    continue avg count current exists max min prior sql stddev    sum variance execute forall merge time timestamp interval    date <a string literal with character set specification>    <a number> <a single-quoted SQL string> pipe    <an alternatively-quoted string literal with character set specification>    <an alternat
11/2      PLS-00103: Encountered the symbol "RETURN" 
Errors: check compiler log

Function GET_EFFECTIVEDATE compiled

LINE/COL  ERROR
--------- -------------------------------------------------------------
7/1       PLS-00103: Encountered the symbol "BEGIN" when expecting one of the following:     := . ( @ % ; not null range with default character The symbol ";" was substituted for "BEGIN" to continue. 
9/14      PLS-00103: Encountered the symbol "SELECT" when expecting one of the following:     ( - + case mod new not null <an identifier>    <a double-quoted delimited-identifier> <a bind variable>    continue avg count current exists max min prior sql stddev    sum variance execute forall merge time timestamp interval    date <a string literal with character set specification>    <a number> <a single-quoted SQL string> pipe    <an alternatively-quoted string literal with character set specification>    <an alternat
11/2      PLS-00103: Encountered the symbol "RETURN" 
Errors: check compiler log

enter image description here

2 个答案:

答案 0 :(得分:2)

您有几个问题:

  • 您在create ...行上有一个分号;
  • 您正在使用替换变量(用&表示)-提示您输入该变量;
  • 您正在使用int而不是number作为参数类型(这并不是一个错误,但是通常使用本机类型会更好);
  • 您的startdate局部变量被声明为varchar而不是varchar2,它可以工作,但不建议使用,但是无论哪种方式,您都必须指定字符串的最大长度(即{{ 1}});
  • 您要将两个数字与startdate varchar2(6);相加,并将其结果(即2029)放入字符串变量中;
  • 您正在使用该字符串变量-如果您忽略+-作为数字而不是日期,但是&将不起作用;
  • 如果您已经是每月的第一天,那么trunc毫无意义。

您可以这样简单地完成此操作:

trunc

然后将其称为:

create or replace function get_effectivedate (par_month in number, par_year in number)
return date
is 
begin
  return next_day(
    add_months(
      -- converts the two number to a single string, and then converts that to a date
      to_date(to_char(par_year, 'FM0000') || to_char(par_month, 'FM00'), 'YYYYMM'),
      1),
    'Sunday');
end;
/

或今年以来所有月份通过CTE:

select get_effectivedate(11, 2018) from dual;

GET_EFFECT
----------
2018-12-02

将两个参数都显式转换为字符串可以控制前导零,因此可以确保传入1和234会转换为字符串'with cte (year, month) as ( select 2018, level from dual connect by level <= 12 ) select year, month, get_effectivedate(month, year) from cte; YEAR MONTH GET_EFFECT ---------- ---------- ---------- 2018 1 2018-02-04 2018 2 2018-03-04 2018 3 2018-04-08 2018 4 2018-05-06 2018 5 2018-06-03 2018 6 2018-07-08 2018 7 2018-08-05 2018 8 2018-09-02 2018 9 2018-10-07 2018 10 2018-11-04 2018 11 2018-12-02 2018 12 2019-01-06 01',因此当它们为串联起来形成'0234',以匹配格式模型。

如果您未明确指定日期,那么'023401'会为您提供每月的第一天。


如果月份的第一天本身是星期日,则上面的函数将获取第二个星期日,您在注释中说的是您真正想要的。 (通知2018-07-08)。如果您确实只是想要第一个星期日而不作进一步调整,则可以执行以下任一操作:

to_date()

或更简单地说:

  return next_day(
    add_months(
      -- converts the two numbers to a single string, and then converts that to a date
      to_date(to_char(par_year, 'FM0000') || to_char(par_month, 'FM00'), 'YYYYMM'),
      1) - 1, -- find first day of next month, then go back one day to last day of this month
    'Sunday'); -- find next Sunday from that day

两个都给L

  return next_day(
    last_day(
      -- converts the two numbers to a single string, and then converts that to a date
      to_date(to_char(par_year, 'FM0000') || to_char(par_month, 'FM00'), 'YYYYMM')
      ), -- find last day of this month
    'Sunday'); -- find next Sunday from that day

答案 1 :(得分:0)

您要调用startDate变量,因此删除与号,

&是符号for prompting user's input。将代码行更改为:

edate     := select  next_day(add_months(trunc(startDate, 'MM'), 1), 'Sunday') as EffectiveDate from dual; 
  

&value是用户输入的参数