【问题标题】:postgres `order by` argument typepostgres `order by` 参数类型
【发布时间】:2016-01-30 10:15:37
【问题描述】:

Postgresql 中order by 子句的参数类型是什么?

我遇到了一个非常奇怪的行为(使用 Postgresql 9.5)。即查询

select * from unnest(array[1,4,3,2]) as x order by 1;

按预期生成1,2,3,4。但是查询

select * from unnest(array[1,4,3,2]) as x order by 1::int;

产生1,4,3,2,这看起来很奇怪。同样,每当我将1::int 替换为任何函数(例如greatest(0,1))甚至case 运算符时,结果都是无序的(与what I would expect 相反)。

那么order by 的参数应该具有哪种类型,以及如何获得预期的行为?

【问题讨论】:

  • 什么预期的行为?向您的问题添加一些示例数据和预期输出

标签: postgresql sql-order-by


【解决方案1】:

这是预期的 (and documented) 行为:

sort_expression 也可以是列标签或输出列的编号

所以表达式:

order by 1

按结果集的第一列排序(由 SQL 标准定义)

然而表达式:

order by 1::int

按常数值1排序,基本等同于:

order by 'foo'

通过为order by 使用一个常量值,所有行都具有相同的排序值,因此并未真正排序。

要按表达式排序,只需使用它:

order by 
    case 
       when some_column = 'foo' then 1
       when some_column = 'bar' then 2
       else 3
    end

上面是根据case表达式的result对结果进行排序的。

【讨论】:

  • 好的,但是我该如何插入例如案例运算符?
  • @overdawn:看看我的编辑,这就是你要找的吗?
  • 我试过select * from unnest(array[1,4,3,2]) as x order by case when true then 1 end; 但它不起作用(实际上这就是我问这个问题的原因;))
  • case when true then 1 end 没有任何意义,这是一种非常复杂的混淆常数的方法1 您要解决的真正问题是什么?也许您应该编辑您的问题并添加一些示例数据和基于该数据的预期输出。
  • 实际上我有一个带有整数参数的函数,它指示要在 order by 子句中使用的列。但我没有看到case when true then 1 end 的问题——这只是你的例子的(残酷的)简化。它对我不起作用。如果成功了,我的问题就迎刃而解了。
【解决方案2】:

实际上我有一个带有整数参数的函数,它指示要在 order by 子句中使用的列。

在所有列都属于同一类型的情况下,这可以工作::

SELECT ....
ORDER BY 
  CASE function_to_get_a_column_number()
    WHEN 1 THEN column1
    WHEN 2 THEN column2
    .....
    WHEN 1235 THEN column1235
END

如果列的类型不同,可以试试:

SELECT ....
ORDER BY 
  CASE function_to_get_a_column_number()
    WHEN 1 THEN column1::varchar
    WHEN 2 THEN column2::varchar
    .....
    WHEN 1235 THEN column1235::varchar
END

但是这些“变通办法”太可怕了。除了返回列号的函数之外,您还需要其他方法。 也许是动态 SQL?

【讨论】:

    【解决方案3】:

    我想说动态 SQL(感谢 @kordirko 和其他人的提示)是我最初想到的问题的最佳解决方案:

    create temp table my_data (
      id serial,
      val text
    );
    
    insert into my_data(id, val)
    values (default, 'a'), (default, 'c'), (default, 'd'), (default, 'b');
    
    create function fetch_my_data(col text)
    returns setof my_data as
    $f$
    begin
     return query execute $$
       select * from my_data
       order by $$|| quote_ident(col);
    end
    $f$ language plpgsql;
    
    select * from fetch_my_data('val'); -- order by val
    select * from fetch_my_data('id'); -- order by id
    

    一开始我认为这可以在order by 子句的参数中使用case 表达式来实现——sort_expression。让我感到困惑的棘手部分来了:当sort_expression一种标识符(列名或列号)时,在对结果进行排序时使用相应的列。但是当sort_expression某个值 时,我们实际上使用该值本身(为每一行计算)对结果进行排序。这是@a_horse_with_no_name 的改写答案。

    所以当我查询... order by 1::int 时,在某种程度上我已经为每一行分配了值 1,然后尝试对一个数组进行排序,这显然是无用的。

    some workarounds without dynamic queries,但它们需要编写更多代码并且似乎没有任何明显优势。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多