postgresql plpgsql编译器:为什么它没有找到歧义

时间:2013-01-26 23:30:23

标签: postgresql runtime-error plpgsql ambiguity

为什么会出现此运行时错误?

错误:列引用“到达”不明确    第6行:((演员('05:00'为时间)> =到达时的情况)
   DETAIL:它可以指PL / pgSQL变量或表格列。

问题是,case语句在查询中,我从一个名为“到达”列的表中进行选择。我有 not 声明了一个名为arri的变量。为什么PG不能简单地检查是否没有声明这样的变量,并断定引用必须是列?

我附上以下代码。我看到的唯一表面冲突是在这个函数返回的传出表的定义中,其中有一个名为“到达”的列,并且在最终选择中使用列名对照临时表TT。

CREATE or replace function GetHourlyView
(v_whichDate date)
returns TABLE
(
stagecoach,
arrive time,
depart time,
t5am int,t6am int,t7am int,t8am int,t9am int,t10am int, t11am int,
t12pm int, t1pm int, t2pm int t3pm int,t4pm int,t5pm int,t6pm int, 
t7pm int, t8pm int, t9pm int, t10pm int, t11pm int
)
as $body$
declare v_dow int := date_part('dow',v_whichDate);
begin

drop table if exists TT;
create temp table TT
(stagecoach varchar(25),
arrive time,
depart time,
t5am int,t6am int,t7am int,t8am int,t9am int,t10am int, t11am int,
t12pm int, t1pm int, t2pm int t3pm int,t4pm int,t5pm int,t6pm int, 
t7pm int, t8pm int, t9pm int, t10pm int, t11pm int
) without OIDS on commit drop;

insert into TT 
select * from
GetDailySchedule( v_whichDate);

-- (arrive=depart) means 'cancelled'
delete from TT where TT.arrive=TT.depart;   

return QUERY
select 
TT.stagecoach, 
arrive, 
depart,
case when ( (cast('05:00' as time) >=  arrive) and  (cast('05:00' as time) <  depart )) then 1    else 0 end as t5am,
case when ( (cast('06:00' as time) >=  arrive) and  (cast('06:00' as time) <  depart )) then 1 else 0 end as t6am,


<snip>
.
.
.
case when ( (cast('23:00' as time) >=  arrive) and  (cast('23:00' as time) <  depart )) then 1    else 0 end as t11pm
from TT
;

drop table TT;
end
$body$
LANGUAGE 'plpgsql'

1 个答案:

答案 0 :(得分:1)

实际上它非常简单:函数体内的任何地方都可以看到函数参数(动态SQL除外)。对于所有参数都是如此:IN, OUT, INOUT, VARIADIC以及RETURNS TABLE子句中使用的任何列名。
你还有其他一些小错误。

  • 通过符合表格的列名称避免冲突:tt.arrive而不仅仅是arrive
  • stagecoachRETURNS TABLE缺少类型。
  • 最后不要单引plpgsql。这是一个标识符。

我还建议你调整你的语法风格。你生活在对立的世界。惯例是大写SQL关键字和小写标识符,而不是相反。请记住,PostgreSQL会自动将不带引号的标识符转换为小写。

除此之外,您的功能可以大大简化到纯SQL查询。我把它包装成一个SQL函数:

CREATE OR REPLACE FUNCTION gethourlyview(v_whichdate date)
  RETURNS TABLE (
    stagecoach text, arrive time, depart time
   , t5am  int, t6am  int, t7am int, t8am  int, t9am  int, t10am int, t11am int
   , t12pm int, t1pm  int, t2pm int, t3pm  int, t4pm  int, t5pm  int, t6pm  int
   , t7pm  int, t8pm  int, t9pm int, t10pm int, t11pm int
   ) AS
$body$
   SELECT tt.stagecoach
         ,tt.arrive -- "depart" would cause conflict
         ,tt.depart
         ,CASE WHEN '05:00'::time >= tt.arrive
                AND '05:00'::time <  tt.depart THEN 1 ELSE 0 END -- AS t5am
         ,...
         ,CASE WHEN '23:00'::time >= tt.arrive
                AND '23:00'::time <  tt.depart THEN 1 ELSE 0 END -- AS t11pm
   FROM   getdailyschedule($1) tt
   WHERE  tt.arrive IS DISTINCT FROM tt.depart;
$body$ LANGUAGE sql;

无需创建临时表。你可以在一个声明中完成所有这些。

相关问题