我正在使用PostgreSQL和Rails 3.2。我的一次数据库迁移具有以下内容:
execute <<-SQL
CREATE INDEX users_multi_idx
ON users (lower(left(fname, 1)), fname)
WHERE deleted_at IS NULL;
SQL
在某些dbs上迁移时,我们收到以下错误:
== AddFnameIndexToUsers: migrating ===========================================
-- execute(" CREATE INDEX users_multi_idx\n ON users (lower(left(fname, 1)), fname)\n WHERE deleted_at IS NULL;\n")
rake aborted!
An error has occurred, this and all later migrations canceled:
PG::Error: ERROR: function left(character varying, integer) does not exist
LINE 2: ON users (lower(left(fname, 1)), fname)
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
: CREATE INDEX users_multi_idx
ON users (lower(left(fname, 1)), fname)
WHERE deleted_at IS NULL;
奇怪的是,这并不会发生在所有dbs上,只有一些(暂存)。关于这个索引执行有什么问题的任何建议?
答案 0 :(得分:9)
你标记了它postgresql-9.1,但我强烈怀疑你在这里处理旧版本。当你提问时,你会得到什么:
SELECT version();
版本9.1引入了 left()
。对于旧版本,使用以下代码替换left(fname, 1)
substr(fname, 1, 1)
如果由于某种原因(like @Wize)无法修改查询,则可以在9.1之前为旧版本创建插件替换:
CREATE OR REPLACE FUNCTION public.left(text, int)
RETURNS text LANGUAGE sql STABLE COST 30 AS
'SELECT substr($1, 1, $2)';
在版本升级后,这通常不会导致冲突,因为默认schema search path在pg_catalog
之前有public
(隐式),所以用户 - 一旦系统函数退出,定义的函数就会停止运行 - 除非明确地进行模式限定。但无论如何,你应该在版本升级后删除它。
我添加了这个,建议对@Wize提供的一些改进:
出于多种原因使用LANGUGAE sql
(而不是plpgsql
):
使用函数波动率STABLE
,这是合适的并有助于提升绩效。
使用$n
表示法引用函数参数,因为旧版本的SQL函数不支持参数名称。
显式创建public
架构中的函数。否则,它可能在当前用户“私有”架构中创建,而不适用于其他用户。这取决于您的schema search path,这应该是最适合您的。
使用数据类型text
,这是默认字符类型,与left()
或substr()
返回相同。适用于varchar
。
答案 1 :(得分:1)
为9.1
之前的Posgres版本创建以下功能CREATE OR REPLACE FUNCTION left(s character varying,i int)
RETURNS character varying AS
$BODY$
BEGIN
return substr(s, 1, i);
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;