Active Record(Postgres)中是否可以按属性的特定值或数组值对对象进行排序?
让我说我首先要显示带有某些标签的内容,然后继续使用类似的标签,继续使用没有标签的内容。这打算在具有无限滚动的页面上使用,因此首先显示最相关的内容,然后在向下滚动时显示不太相关的内容是有意义的。
Order
通过提供属性和DESC或ASC来工作,但是如果我想通过一组特定属性的值对它们进行排序呢?
答案 0 :(得分:3)
听起来你想说的话是:
“对
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
。
请参阅this simple demo。
随着列表的增长,性能将显着更糟糕。这是你可以使用的一些值,最好不是几十,当然不是几百。此外,标准SQL不要求数据库支持ORDER BY
子句中的表达式,因此这可能不是特别便携。在ActiveRecord中表达它取决于你。
如果PostgreSQL为idx(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');