我正在尝试在varchar列的转换中创建一个索引。我正在做这样的事情:
CREATE INDEX date_index ON table_name (CAST(varchar_column AS DATE));
我收到了错误:functions in index expression must be marked IMMUTABLE
但是我不明白为什么,迄今为止的演员表并不依赖于时区或类似的东西(这会使得时区的演员阵容给出这个误差)。
任何帮助?
答案 0 :(得分:12)
您的第一个错误是将日期存储为varchar列。你不应该这样做。
问题的正确解决方法是将列转换为真正的date
列。
现在我很确定该声明的答案是“我没有设计数据库,我无法更改它”,所以这是一个解决方法:
CAST
和to_char()
不是不可变的,因为它们可以根据当前会话的设置为相同的输入值返回不同的值。
如果您知道表格中所有值的格式一致(如果您有 - 将意味着您可以将列转换为真正的date
列),那么您可以创建自己的函数来转换varchar到日期并标记为不可变。
create or replace function fix_bad_datatype(the_date varchar)
returns date
language sql
immutable
as
$body$
select to_date(the_date, 'yyyy-mm-dd');
$body$
ROWS 1
/
使用该定义,您可以在表达式上创建索引:
CREATE INDEX date_index ON table_name (fix_bad_datatype(varchar_column));
但你有在查询中使用该函数调用,以便Postgres使用它:
select *
from foo
where fix_bad_datatype(varchar_column) < current_date;
请注意,如果varchar列中只有一个“非法”值,则此方法将严重失败。 唯一合理的解决方案是将日期存储为date
s,
答案 1 :(得分:2)
请提供数据库版本,表ddl和一些示例数据。
让你自己的不可变函数做你想要的,像这样吗?还要考虑在文档中创建一个新的强制转换,看看它是否适合你。
create table emp2 (emp2_id integer, hire_date VARCHAR(100));
insert into emp2(hire_date)
select now();
select cast(hire_date as DATE)
from emp2
CREATE FUNCTION my_date_cast(VARCHAR) RETURNS DATE
AS 'select cast($1 as DATE)'
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT;
CREATE INDEX idx_emp2_hire_date ON emp2 (my_date_cast(hire_date));