IN() 子句中的 PostgreSQL ORDER BY 值

Posted

技术标签:

【中文标题】IN() 子句中的 PostgreSQL ORDER BY 值【英文标题】:PostgreSQL ORDER BY values in IN() clause 【发布时间】:2011-10-12 22:52:08 【问题描述】:

好的,有一些关于如何做到这一点的答案。但是所有的答案都假设查询是全选的。如果您有一个独特的选择,这些方法将不再有效。

有关该方法,请参见此处:Simulating mysql's ORDER BY FIELD() in Postgresql

基本上我有

SELECT DISTINCT id 
FROM items 
WHERE id IN (5,2,9) 
ORDER BY
 CASE id
  WHEN 5 THEN 1 
  WHEN 2 THEN 2
  WHEN 9 THEN 3
 END

当然,这会打破并说

"PGError: ERROR: for SELECT DISTINCT, ORDER BY 表达式必须 出现在选择列表中”

有什么方法可以按照 IN 子句中值的顺序对 PostgreSQL 中的查询结果进行排序?

【问题讨论】:

"ORDER BY 表达式必须出现在选择列表中" - 所以只需将表达式移动到 SELECT 列表:) 【参考方案1】:

您可以将其包装到派生表中:

SELECT *
FROM (
  SELECT DISTINCT id 
  FROM items 
  WHERE id IN (5,2,9) 
) t
ORDER BY
 CASE id
  WHEN 5 THEN 1 
  WHEN 2 THEN 2
  WHEN 9 THEN 3
 END

【讨论】:

【参考方案2】:

来自documentation:

提示:没有聚合表达式的分组可以有效地计算 列中的一组不同值。这也可以使用 DISTINCT 子句(参见Section 7.3.3)。

SQL 查询:

SELECT id 
FROM items 
WHERE id IN (5,2,9) 
GROUP BY id
ORDER BY
    CASE id
        WHEN 5 THEN 1 
        WHEN 2 THEN 2
        WHEN 9 THEN 3
    END;

【讨论】:

【参考方案3】:

我在 postgres PL/PGSQL 中创建了这个函数,它更容易使用。

-- Function: uniqueseperategeomarray(geometry[], double precision)

-- DROP FUNCTION uniqueseperategeomarray(geometry[], double precision);

CREATE OR REPLACE FUNCTION manualidsort(input_id int, sort_array int[])
  RETURNS int AS
$BODY$
DECLARE
input_index int;
each_item int;
index int;
BEGIN
index := 1;
  FOREACH each_item IN ARRAY sort_array
  LOOP
    IF each_item = input_id THEN
      RETURN index;
    END IF;
    index := index+1;
  END LOOP;
END;
$BODY$
  LANGUAGE plpgsql;
ALTER FUNCTION manualidsort(int, int[])
  OWNER TO staff;

当你运行查询时,像这样去......

SELECT * FROM my_table ORDER BY manualidsort(my_table_id, ARRAY[25, 66, 54])

【讨论】:

【参考方案4】:

环顾四周,我找不到这个问题的完整解决方案。

我认为更好的解决方案是使用这个查询

SELECT *
FROM items
WHERE id IN (5,2,9) 
ORDER BY idx(array[5,2,9]::integer[], items.id)

如果您使用的是 PostgreSQL >= 9.2,您可以启用 idx 功能来启用扩展。

CREATE EXTENSION intarray;

否则,您可以使用以下方法创建它:

CREATE OR REPLACE FUNCTION idx(anyarray, anyelement)
  RETURNS INT AS 
$$
  SELECT i FROM (
     SELECT generate_series(array_lower($1,1),array_upper($1,1))
  ) g(i)
  WHERE $1[i] = $2
  LIMIT 1;
$$ LANGUAGE SQL IMMUTABLE;

我真的建议在查询中使用::integer[],因为如果你动态创建数组,它可能没有元素导致ids(array[], items.id),这会在PostgreSQL 上引发异常。

【讨论】:

以上是关于IN() 子句中的 PostgreSQL ORDER BY 值的主要内容,如果未能解决你的问题,请参考以下文章

Postgresql - 超过 3000 个值的 IN 子句优化

PostgreSQL in 子句忽略大小写值

在 WHERE IN 子句中使用 JSONB 数组中的值

带有 dapper 和 postgresql 的“WHERE x IN y”子句抛出 42601:在 \"$1\" 处或附近出现语法错误

在使用IN子句的postgreSql查询中用作表达式的子查询返回的多行

PostgreSQL order by 排序问题