如何根据数组元素的顺序对查询结果进行排序?

Posted

技术标签:

【中文标题】如何根据数组元素的顺序对查询结果进行排序?【英文标题】:How to order query result according to the order of array elements? 【发布时间】:2015-04-11 04:42:21 【问题描述】:

我在 Postgres 9.4 中有这个查询:

select id from question where id = any(
    array_cat(
        ARRAY[0,579489,579482,579453,561983,561990,562083]::integer[], 
        (select array(
            select id from question where id not in 
                (0,579489,579482,579453,561983,561990,562083)
            and status in (1, -1) 
            and created_at > 1426131436 order by id desc offset 0 limit 10 )
        )::integer[]
    )
)

返回:

   id
--------
 561983
 561990
 562083
 579453
 579482
 579489
 580541
 580542
 580543
 580544
 580545
 580546
 580547
 580548
 580549
 580550
(16 rows)

但它的顺序不正确。我需要根据子数组的结果排序的结果:

array_cat(
        ARRAY[0,579489,579482,579453,561983,561990,562083]::integer[], 
        (select array(
            select id from question where id not in 
                (0,579489,579482,579453,561983,561990,562083)
            and status in (1, -1) 
            and created_at > 1426131436 order by id desc offset 0 limit 10 )
        )::integer[]
    )

我该怎么做?

【问题讨论】:

你的 Postgres 版本? 【参考方案1】:

基础知识:

PostgreSQL unnest() with element number

由于您使用的是 Postgres 9.4,因此您可以使用新的 WITH ORDINALITY

WITH t AS (
   SELECT *
   FROM   unnest('0,579489,579482,579453,561983,561990,562083'::int[])
                  WITH ORDINALITY AS t(id, rn)
   )
(
SELECT id
FROM   question
JOIN   t USING (id)
ORDER  BY t.rn
)
UNION ALL
(
SELECT id
FROM   question
LEFT   JOIN t USING (id)
WHERE  t.id IS NULL
AND    status IN (1, -1) 
AND    created_at > 1426131436
ORDER  BY id DESC
LIMIT  10
);

解释

    由于您两次使用相同的数组,我在查询前添加了一个 CTE,您可以在其中提供数组一次unnest()它立即WITH ORDINALITY根据数组元素的顺序获取行号(rn)。

    不要将子查询填充到数组中并将其转换回来,而是直接使用它。便宜得多。排序顺序直接来源于id

    使用LEFT JOIN / IS NULL,而不是使用NOT IN(这对于NULL 值可能会很棘手)从给定数组中排除ID:

    Select rows which are not present in other table

    只需将两个部分附加UNION ALL。在 UNION ALL 查询的每条腿上,括号必须有单独的 ORDER BY

    Sum results of a few queries and then find top 5 in SQL

    最后的SELECT 中的JOINquestion 现在是多余的,我把它去掉了。

【讨论】:

我不知道,这似乎很完美:) @mathieu:我更进一步。现在应该很快了。 我真的不需要答案,因为我不是问题的作者,但我找到了实现这个有趣的方法...... Postgres 提供了如此多的可能性,很难全部了解:) @ErwinBrandstetter 它工作。我认为它在 9.4 中很完美,非常感谢。 对此进行一些更改:从问题 q 中选择 q.id 加入(从 unnest 中选择*(array_cat(数组[0,579489,579482,579453,561983,561990,562083]::integer[ ], (select array( select id from question where id not in (0,579489,579482,579453,561983,561990,562083) 和状态在 (1, -1) 和 created_at > 1426131436 order by id desc offset 0 limit 10 ) )::integer[] ) ) WITH ORDINALITY as ids(id, rn) ) as tmp on q.id = tmp.id order by tmp.rn【参考方案2】:
ORDER BY idx(your_array, your_element)

ORDER BY your_array # your_element

intarray

select id from question where id = any(
    array_cat(
        ARRAY[0,579489,579482,579453,561983,561990,562083]::integer[], 
        (select array(
            select id from question where id not in 
                (0,579489,579482,579453,561983,561990,562083) and status in (1, -1) 
                and created_at > 1426131436 order by id desc offset 0 limit 10 )
        )::integer[]
    ) 
) ORDER BY array_cat(
    ARRAY[0,579489,579482,579453,561983,561990,562083]::integer[], 
    (select array(
        select id from question where id not in 
            (0,579489,579482,579453,561983,561990,562083) and status in (1, -1) 
            and created_at > 1426131436 order by id desc offset 0 limit 10 )
    )::integer[]
) # id

【讨论】:

以上是关于如何根据数组元素的顺序对查询结果进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

java中怎么 对数组里的 元素 按出现的顺序排序

根据元素的频率对数组进行排序

如何根据另一个列表中元组元素的顺序对元组列表进行排序?

根据子列表中的第二个元素按字母顺序对列表进行排序,但不区分大小写[重复]

JS对象数组多条件排序

如何根据特定顺序对休眠结果进行排序