我正在尝试在oracle中创建一个使用case语句的虚拟列但是如果我调用SYSDATE函数它会给我这个错误:
ORA-54002: only pure functions can be specified in a virtual column expression
这是查询:
alter table t_requirements ADD
REQUIREMENT_STATE varchar2(30)
generated always as(
CASE
WHEN t_requirements.activation_date- SYSDATE - 5 <= 0 AND
t_requirements.activation_date - SYSDATE > 0 THEN 'Exist'
WHEN t_requisiti.activation_date - SYSDATE <=0 THEN 'Active'
END) virtual;
答案 0 :(得分:6)
您正在使用SYSDATE
来构建虚拟列。这是不允许的,因为SYSDATE
不是确定性的,即它并不总是返回相同的值。想象一下,您在此列上构建索引。一秒钟后,索引已经无效了!
您似乎应该编写一个包含此ad hoc计算列的视图。
答案 1 :(得分:3)
sysdate
不具有确定性。它的值每次运行时都会有所不同。虚拟列必须是确定性的。否则会出现奇怪的情况,即查询记录会改变其价值。相当正确的Oracle不允许这样做。
在这种情况下,我们仍然需要使用查询(可能作为表格的视图)来显示派生值。
select r.*
, cast(
CASE
WHEN r.activation_date- SYSDATE - 5 <= 0 AND
r.activation_date - SYSDATE > 0 THEN 'Exist'
WHEN r.activation_date - SYSDATE <=0 THEN 'Active'
else 'Inactive'
END
as varchar2(30)) as REQUIREMENT_STATE
from requirements r
;
顺便提一下,您的CASE声明是否需要ELSE?在activation_date
大于SYSDATE + 5
答案 2 :(得分:1)
您可以使用SYSDATE
来支持虚拟列。在查询时计算虚拟列。如果您创建一个函数ISACTIVE_FROM_TO
,例如:
CREATE OR REPLACE FUNCTION ISACTIVE_FROM_TO (p_active_from IN DATE, p_active_to IN DATE)
RETURN number
DETERMINISTIC
IS
BEGIN
RETURN (CASE WHEN SYSDATE BETWEEN NVL (p_active_from, SYSDATE) AND NVL (p_active_to, SYSDATE) THEN 1 ELSE 0 END);
EXCEPTION
WHEN OTHERS THEN
RAISE VALUE_ERROR;
END;
/
在具有ACTIVE_FROM和ACTIVE_TO日期列的表上定义您的虚拟列:
alter table xyz
add ISACTIVE NUMBER(1)
GENERATED ALWAYS AS (ISACTIVE_FROM_TO"(ACTIVE_FROM,ACTIVE_TO));
该表将根据sysdate
动态计算值。该函数是确定性的...给出相同的from / to date和sysdate它将始终返回相同的值。该函数需要具有确定性关键字。
当sysdate接近ACTIVE_TO日期/时间时,表的连续查询将导致ISACTIVE值从1变为0 ....因为该函数根据移动SYSDATE计算值。操作与单独的视图非常相似。