postgres `order by` 参数类型
postgres `order by` argument type
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
,这看起来很奇怪。同样,每当我用任何函数(例如 greatest(0,1)
)甚至 case
运算符替换 1::int
时,结果都是无序的(与 what I would expect 相反)。
那么 order by
的参数应该具有哪种类型,我如何获得预期的行为?
这是预期的 (and documented) 行为:
A sort_expression
can also be the column label or number of an output column
所以表达式:
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
表达式的结果对结果进行排序
Actually I have a function with an integer argument which indicates the column to be used in the order by clause.
在所有列都是同一类型的情况下,这可以工作::
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
但是这些 "workarounds" 太可怕了。除了返回列号的函数之外,您还需要其他方法。
也许是动态 SQL ?
我会说动态 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
子句 - sort_expression
的参数中使用 case 表达式来实现。令我困惑的棘手部分来了:当sort_expression
是一种标识符(列名或列号)时,使用相应的列排序结果。但是当 sort_expression
是 某个值 时,我们实际上使用该值本身(为每一行计算)对结果进行排序。这是@a_horse_with_no_name 改写后的回答。
所以当我查询 ... order by 1::int
时,在某种程度上我已经为每一行分配了值 1,然后尝试对一个数组进行排序,这显然是无用的。
有some workarounds without dynamic queries,但是需要写更多的代码,似乎没有什么明显的优势。
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
,这看起来很奇怪。同样,每当我用任何函数(例如 greatest(0,1)
)甚至 case
运算符替换 1::int
时,结果都是无序的(与 what I would expect 相反)。
那么 order by
的参数应该具有哪种类型,我如何获得预期的行为?
这是预期的 (and documented) 行为:
A
sort_expression
can also be the column label or number of an output column
所以表达式:
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
表达式的结果对结果进行排序
Actually I have a function with an integer argument which indicates the column to be used in the order by clause.
在所有列都是同一类型的情况下,这可以工作::
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
但是这些 "workarounds" 太可怕了。除了返回列号的函数之外,您还需要其他方法。
也许是动态 SQL ?
我会说动态 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
子句 - sort_expression
的参数中使用 case 表达式来实现。令我困惑的棘手部分来了:当sort_expression
是一种标识符(列名或列号)时,使用相应的列排序结果。但是当 sort_expression
是 某个值 时,我们实际上使用该值本身(为每一行计算)对结果进行排序。这是@a_horse_with_no_name 改写后的回答。
所以当我查询 ... order by 1::int
时,在某种程度上我已经为每一行分配了值 1,然后尝试对一个数组进行排序,这显然是无用的。
有some workarounds without dynamic queries,但是需要写更多的代码,似乎没有什么明显的优势。