0

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

错误:列引用“到达”不明确第 6 行:case when ((cast('05:00' as time) >=arrive)
详细信息: 它可以引用 PL/pgSQL 变量或表列。

问题是,case 语句在查询中,我正在从一个表中进行选择,该表确实有一个名为“arrive”的列。我还没有声明一个名为到达的变量。为什么 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'
4

1 回答 1

1

这真的很简单:函数参数在函数体内随处可见(动态 SQL 除外)。对于所有参数都是如此:INOUTINOUTVARIADICRETURNS TABLE子句中使用的任何列名。
您还有其他几个小错误。

  • 通过表限定列名避免冲突:tt.arrive而不是仅仅arrive.
  • stagecoachin缺少类型RETURNS 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;

无需创建临时表。您可以在一个语句中完成所有操作。

于 2013-01-27T18:59:09.300 回答