在PostgreSQL中,如何通过varchar在切换时选择带大小写的排序

在PostgreSQL中,如何通过varchar在切换时选择带大小写的排序,postgresql,sql-order-by,case-when,postgresql-12,collate,Postgresql,Sql Order By,Case When,Postgresql 12,Collate,此简单函数返回title字符串的有序列表 创建或替换函数testfunction1() 返回表( id bigint, lang_代码tlang_代码, 标题varchar ) 稳定语言sql as$$ 挑选 id、语言代码、标题 从…起 可测试 订购人 标题对照“es_es”; $$; 从testfunction()中选择*; id |语言代码|标题| --|---------|----------------| 12 | DE | NOCH FESTZULEGEN| 16 | DE | NO

此简单函数返回
title
字符串的有序列表

创建或替换函数testfunction1()
返回表(
id bigint,
lang_代码tlang_代码,
标题varchar
)
稳定语言sql as$$
挑选
id、语言代码、标题
从…起
可测试
订购人
标题对照“es_es”;
$$;
从testfunction()中选择*;
id |语言代码|标题|
--|---------|----------------|
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 |待定|
9 | EN |待定|
13 | EN |待定|
11 | FR | D|TERMINER|
15 | FR | D|TERMINER|
7 | FR | D|TERMINER|
但是,当我尝试使用
collate
引入排序顺序时,我无法获得正确的语法,无法根据参数
\u lang\u code
设置正确的排序顺序

创建或替换函数testfunction2(\u lang\u code tlang\u code)
返回表(
id bigint,
lang_代码tlang_代码,
标题varchar
)
稳定语言sql as$$
挑选
id、语言代码、标题
从…起
可测试
哪里
语言代码=\u语言代码
订购人
书名整理
案例语言代码
当“恩”然后“恩我们”
当“是”然后“是”
当“FR”时,则为“FR\u FR”
当“DE”之后是“DE_DE”
结束asc;
$$;
错误是
SQL错误[42601]:错误:在“case”处或附近出现语法错误

我尝试在
order by
子句中到处定位该案例,但未成功。也许“en_US”不是一个标量值


编辑 我在Laurenz Albe评论之后添加了
where lang_code=\u lang_code
。从我真正的问题转移到这个简化的例子时,这是一个遗漏的条款

但是,
案例的问题仍然是相同的SQL错误


解决方案 正如@Lorenz Albe在评论中指出的那样,
“en_US”
是一个标识符,而不是标量值。这可以防止
case 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;
$$;

考虑到您正在使用参数
\u lang\u 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;$$
现在,您可以执行测试,甚至取消注释
raiseexception
,以确定合适的“最终查询”:


PD:我已将
\u lang\u code
lang\u code
的类型更改为
varchar
,因为我假设
tlang\u code
是一个自定义代码。

@doctore解决方案强制使用PL/PGSQL函数,这也是在包含整个select语句时移动案例的另一种方法。他们两人都很不优雅,但证明了这个问题是有道理的

不幸的是,我还没有在我的原始函数中找到语法错误的原因

创建或替换函数testfunction3(\u lang\u code char(2))
返回表(
id bigint,
语言代码字符(2),
标题varchar
)
稳定语言plpgsql as$$
开始
案例语言代码
那什么时候
返回查询
挑选*
来自测试表t
其中t.lang\u code=\u lang\u code
订单由t.标题核对“en_US”;
那么什么时候“是”呢
返回查询
挑选*
来自测试表t
其中t.lang\u code=\u lang\u code
按t.title排序,核对“es_es”;
“FR”是什么时候
返回查询
挑选*
来自测试表t
其中t.lang\u code=\u lang\u code
订单由t.标题核对“fr_fr”;
“德”是什么时候
返回查询
挑选*
来自测试表t
其中t.lang\u code=\u lang\u code
按t.标题排序,核对“de_de”;
终例;
结束
$$;

不起作用。正如我所说,我测试了(几乎)所有内容:-)现在的错误是
SQL错误[42P21]:错误:显式排序规则“en_-US”和“es_-es”之间的排序规则不匹配这是另一个问题。上述解决方案仅适用于您在问题中提到的语法错误。这是相同的问题。解析器希望在
之后有一个标量,而不是子句的一部分,即“所有结果表达式的数据类型必须转换为单个输出类型”。我甚至尝试在括号之间加上
title collate“en_US”
。您试图为同一排序过程混合不同的
collate
值,这就是为什么“第一次查询”可以工作(它只有一次)但下一次却不行的基本原因。你需要改变方法,使用合适的
整理
,考虑到
语言代码
值,并以你想要的方式“混合不同的块”(每种语言一个“块”)。我不确定我是否理解你的评论。显然,我不想混合排序顺序,我只想根据
\u lang\u code
参数选择一个或另一个。这显然是Postgre12(?)中引入的
collate
子句的一个特点。我不知道你说的“chunks”是什么意思,我可以从一开始就切换整个select语句,但失去了使用SQL函数的好处。Akhilesh Mishra的方法导致“混合”或设置两倍的排序顺序,但这只是语法错误的产物。好吧,我现在理解了“整个流程”。这就是为什么我包含了一个答案,以允许您处理您的用例
select testfunction2('EN')
select testfunction2('ES')