听起来你想说这样的话:
“按blah
以下顺序对列中的项目进行排序:('fred', 'bob', 'joe', [others], NULL)
”
如果是这样,那在 SQL 中是不可能的。ActiveRecord 可能会在上面添加一些东西,但我不确定你会如何表达它。
在 PostgreSQL 中,您可能会将其写为ORDER BY ... CASE
,类似于:
SELECT ...
FROM ...
ORDER BY CASE
WHEN the_col = 'fred' THEN 1
WHEN the_col = 'bob' THEN 2
WHEN the_col = 'joe' THEN 3
WHEN the_col IS NOT NULL THEN 99999
END;
(除非您指定,否则NULL
按默认顺序对任何值进行排序,如果没有匹配项则生成)。ASC
NULLS FIRST
CASE
NULL
请参阅这个简单的演示。
随着列表的增长,性能会急剧下降。这可以用于几个值,最好不是十,当然也不是数百。此外,标准 SQL 不要求数据库支持ORDER BY
子句中的表达式,因此这可能不是特别便携。在 ActiveRecord 中表达它取决于你。
如果 PostgreSQLidx(element, array)
为任意数组提供了一个函数,比如模块idx
中为整数数组提供的函数,intarray
那么你可以稍微简化一下,但是......它没有。所以你需要一个完整的长度CASE
。
但是,您可以将它包装在一个接受数组参数的 SQL 或 PL/PgSQL 函数中。这可能会让你从 AR 中调用它,尽管它可能会使效率情况变得更糟,因为它对每个元组执行两个低效的数组排序和扫描操作:
http://sqlfiddle.com/#!12/0885d/1
-- See http://stackoverflow.com/questions/8798055
CREATE FUNCTION array_search(needle ANYELEMENT, haystack ANYARRAY)
RETURNS INT AS '
SELECT i
FROM generate_subscripts($2, 1) AS i
WHERE $2[i] = $1
ORDER BY i'
LANGUAGE sql STABLE;
CREATE OR REPLACE FUNCTION case_sort(e anyelement, a anyarray)
RETURNS integer
AS '
SELECT CASE
-- Yes, this wastes time searching the array twice.
-- You could use PL/PgSQL to avoid that, but it would
-- probably be slower over-all.
WHEN array_search(e, a) IS NOT NULL THEN array_search(e,a)
-- maxint
WHEN e IS NOT NULL then 2147483647
END;'
LANGUAGE sql STABLE;
SELECT *
FROM order_demo
ORDER BY case_sort(sortcol, ARRAY['fred','joe','bob']);
或者,正如 Mu 在评论中所建议的那样,您可以看到 ActiveRecord 是否可以比数组更容易地处理可变参数函数:
CREATE OR REPLACE FUNCTION case_sort(e anyelement, VARIADIC a anyarray)
RETURNS integer
AS '/* function body unchanged from above */'
LANGUAGE sql STABLE;
SELECT *
FROM order_demo
ORDER BY case_sort(sortcol, 'fred', 'joe','bob');
每个更新的演示:http ://sqlfiddle.com/#!12/84ed8/1