1

It is possible in Active Record (Postgres) to order objects by a particular value or array of values of an attribute?

Lets say I first want to show the contents with certain tag, then continue with a similar tag, the continue with contents with no tag. This is intend to use on a page with infinite scrolling, so it makes sense to show first the most relevant content and then the less relevant content as he scrolls down.

Order does work by giving an attribute and DESC or ASC, but what If I want to sort them by a set of values of a particular attribute instead?

4

1 回答 1

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按默认顺序对任何值进行排序,如果没有匹配项则生成)。ASCNULLS FIRSTCASENULL

请参阅这个简单的演示

随着列表的增长,性能会急剧下降。这可以用于几个值,最好不是十,当然也不是数百。此外,标准 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

于 2013-07-26T02:39:41.040 回答