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

问题描述

此简单函数返回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设置正确的排序顺序。

create or replace function testfunction2 (_lang_code tlang_code)
returns table (
    id        bigint,title     varchar
)
stable language sql as $$
    select 
        id,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或将大小写移动到整个句子都是对问题的微妙但实用的解决方案。

解决方法

考虑到您正在使用参数_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_codevarchar的类型更改为tlang_code。>

,

按如下所示为订单写案:

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;
$$;
,

@doctore解决方案强制使用PL / PGSQL函数,当包含整个选择语句时,这另一种移动大小写的方法也会执行。他们俩都远非优雅,但证明这个问题有道理。

很遗憾,我没有在原始函数中找到语法错​​误的原因。

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
$$;

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...