如何在 PostgreSQL 中通过 varchar 选择带有 case-when 开关的整理顺序
How to order by a varchar choosing the collate order with a case-when switch, in PostgreSQL
这个简单的函数returns title
个字符串的有序列表。
create or replace function testfunction1 ()
returns table (
id bigint,
lang_code tlang_code,
title varchar
)
stable language sql as $$
select
id, lang_code, title
from
testable
order by
title collate "es_ES";
$$;
select * from testfunction ();
id|lang_code|title |
--|---------|----------------|
12|DE |NOCH FESTZULEGEN|
16|DE |NOCH FESTZULEGEN|
8|DE |NOCH FESTZULEGEN|
14|ES |POR DETERMINAR |
6|ES |POR DETERMINAR |
10|ES |POR DETERMINAR |
5|EN |TO BE DETERMINED|
9|EN |TO BE DETERMINED|
13|EN |TO BE DETERMINED|
11|FR |À DÉTERMINER |
15|FR |À DÉTERMINER |
7|FR |À DÉTERMINER |
但是,当我尝试使用 collate
引入归类顺序时,我无法获得正确的语法来根据参数 _lang_code
.[=22 设置正确的归类顺序=]
create or replace function testfunction2 (_lang_code tlang_code)
returns table (
id bigint,
lang_code tlang_code,
title varchar
)
stable language sql as $$
select
id, lang_code, title
from
testable
where
lang_code = _lang_code
order by
title collate
case _lang_code
when 'EN' then "en_US"
when 'ES' then "es_ES"
when 'FR' then "fr_FR"
when 'DE' then "de_DE"
end asc;
$$;
错误是SQL Error [42601]: ERROR: syntax error at or near "case"
。
我尝试将大小写放在 order by
子句的任何位置,但都没有成功。也许“en_US”不被视为标量值?
编辑
我在 Laurenz Albe 评论后添加了 where lang_code = _lang_code
。从我的实际问题转换为这个简化示例时,这是一个缺失的子句。
然而,case
的问题仍然存在 SQL 错误。
解决方案
正如@Lorenz Albe 在评论中指出的那样,"en_US"
是标识符,而不是标量值。这可以防止 case-when
结构在其任何 when
分支中返回它。所以没有 SQL 方法恰好存在。
作为解决方法,来自@doctore 的动态 SQL 或移动大小写以包含整个句子,都是解决问题的不优雅但实用的解决方案。
写下您的案例以通过如下方式订购:
create or replace function testfunction2 (_lang_code tlang_code)
returns table (
id bigint,
lang_code tlang_code,
title varchar
)
stable language sql as $$
select
id, lang_code, title
from
testtable
order by
case _lang_code
when 'EN' then title collate "en_US"
when 'ES' then title collate "es_ES"
when 'FR' then title collate "fr_FR"
when 'DE' then title collate "de_DE"
end asc;
$$;
考虑到您正在使用参数 _lang_code
选择要过滤的“内部语言”。以下 PL/SQL 代码允许您动态更改最终查询中的 collate
:
create or replace function testfunction2 (_lang_code varchar)
returns table (
id bigint,
lang_code varchar,
title varchar
)
language plpgsql
as $$
declare
final_collate varchar;
final_query varchar;
begin
if (_lang_code = 'EN') then
final_collate := 'en_US';
elsif (_lang_code = 'ES') then
final_collate := 'es_ES';
end if;
-- Include other use cases you need
final_query := 'select t.id, t.lang_code, t.title ' ||
'from test_table t ' ||
'where t.lang_code = ''' || _lang_code || ''' ' ||
'order by t.title collate "' || final_collate || '" asc';
--raise exception 'Final query: %', final_query;
return query
execute final_query;
end;$$
现在您可以执行测试甚至取消注释 raise exception
以确定合适的“最终查询”:
select testfunction2('EN')
select testfunction2('ES')
PD: 我已经将 _lang_code
和 lang_code
的类型更改为 varchar
因为我假设 tlang_code
是定制一个。
@doctore 解决方案强制使用 PL/PGSQL 函数,因此另一种移动 case-when 以包含整个 select 句子的方法也是如此。他们都谈不上优雅,但证明这个问题是有道理的。
很遗憾,我还没有找到我原来函数中语法错误的原因。
create or replace function testfunction3 (_lang_code char(2))
returns table (
id bigint,
lang_code char(2),
title varchar
)
stable language plpgsql as $$
begin
case _lang_code
when 'EN' then
return query
select *
from testtable t
where t.lang_code = _lang_code
order by t.title collate "en_US";
when 'ES' then
return query
select *
from testtable t
where t.lang_code = _lang_code
order by t.title collate "es_ES";
when 'FR' then
return query
select *
from testtable t
where t.lang_code = _lang_code
order by t.title collate "fr_FR";
when 'DE' then
return query
select *
from testtable t
where t.lang_code = _lang_code
order by t.title collate "de_DE";
end case;
end
$$;
这个简单的函数returns title
个字符串的有序列表。
create or replace function testfunction1 ()
returns table (
id bigint,
lang_code tlang_code,
title varchar
)
stable language sql as $$
select
id, lang_code, title
from
testable
order by
title collate "es_ES";
$$;
select * from testfunction ();
id|lang_code|title |
--|---------|----------------|
12|DE |NOCH FESTZULEGEN|
16|DE |NOCH FESTZULEGEN|
8|DE |NOCH FESTZULEGEN|
14|ES |POR DETERMINAR |
6|ES |POR DETERMINAR |
10|ES |POR DETERMINAR |
5|EN |TO BE DETERMINED|
9|EN |TO BE DETERMINED|
13|EN |TO BE DETERMINED|
11|FR |À DÉTERMINER |
15|FR |À DÉTERMINER |
7|FR |À DÉTERMINER |
但是,当我尝试使用 collate
引入归类顺序时,我无法获得正确的语法来根据参数 _lang_code
.[=22 设置正确的归类顺序=]
create or replace function testfunction2 (_lang_code tlang_code)
returns table (
id bigint,
lang_code tlang_code,
title varchar
)
stable language sql as $$
select
id, lang_code, title
from
testable
where
lang_code = _lang_code
order by
title collate
case _lang_code
when 'EN' then "en_US"
when 'ES' then "es_ES"
when 'FR' then "fr_FR"
when 'DE' then "de_DE"
end asc;
$$;
错误是SQL Error [42601]: ERROR: syntax error at or near "case"
。
我尝试将大小写放在 order by
子句的任何位置,但都没有成功。也许“en_US”不被视为标量值?
编辑
我在 Laurenz Albe 评论后添加了 where lang_code = _lang_code
。从我的实际问题转换为这个简化示例时,这是一个缺失的子句。
然而,case
的问题仍然存在 SQL 错误。
解决方案
正如@Lorenz Albe 在评论中指出的那样,"en_US"
是标识符,而不是标量值。这可以防止 case-when
结构在其任何 when
分支中返回它。所以没有 SQL 方法恰好存在。
作为解决方法,来自@doctore 的动态 SQL 或移动大小写以包含整个句子,都是解决问题的不优雅但实用的解决方案。
写下您的案例以通过如下方式订购:
create or replace function testfunction2 (_lang_code tlang_code)
returns table (
id bigint,
lang_code tlang_code,
title varchar
)
stable language sql as $$
select
id, lang_code, title
from
testtable
order by
case _lang_code
when 'EN' then title collate "en_US"
when 'ES' then title collate "es_ES"
when 'FR' then title collate "fr_FR"
when 'DE' then title collate "de_DE"
end asc;
$$;
考虑到您正在使用参数 _lang_code
选择要过滤的“内部语言”。以下 PL/SQL 代码允许您动态更改最终查询中的 collate
:
create or replace function testfunction2 (_lang_code varchar)
returns table (
id bigint,
lang_code varchar,
title varchar
)
language plpgsql
as $$
declare
final_collate varchar;
final_query varchar;
begin
if (_lang_code = 'EN') then
final_collate := 'en_US';
elsif (_lang_code = 'ES') then
final_collate := 'es_ES';
end if;
-- Include other use cases you need
final_query := 'select t.id, t.lang_code, t.title ' ||
'from test_table t ' ||
'where t.lang_code = ''' || _lang_code || ''' ' ||
'order by t.title collate "' || final_collate || '" asc';
--raise exception 'Final query: %', final_query;
return query
execute final_query;
end;$$
现在您可以执行测试甚至取消注释 raise exception
以确定合适的“最终查询”:
select testfunction2('EN')
select testfunction2('ES')
PD: 我已经将 _lang_code
和 lang_code
的类型更改为 varchar
因为我假设 tlang_code
是定制一个。
@doctore 解决方案强制使用 PL/PGSQL 函数,因此另一种移动 case-when 以包含整个 select 句子的方法也是如此。他们都谈不上优雅,但证明这个问题是有道理的。
很遗憾,我还没有找到我原来函数中语法错误的原因。
create or replace function testfunction3 (_lang_code char(2))
returns table (
id bigint,
lang_code char(2),
title varchar
)
stable language plpgsql as $$
begin
case _lang_code
when 'EN' then
return query
select *
from testtable t
where t.lang_code = _lang_code
order by t.title collate "en_US";
when 'ES' then
return query
select *
from testtable t
where t.lang_code = _lang_code
order by t.title collate "es_ES";
when 'FR' then
return query
select *
from testtable t
where t.lang_code = _lang_code
order by t.title collate "fr_FR";
when 'DE' then
return query
select *
from testtable t
where t.lang_code = _lang_code
order by t.title collate "de_DE";
end case;
end
$$;