在 ORDER BY 和 LIMIT 子句中使用列值

Mag*_*o C 4 postgresql order-by

我在 Postgres 9.3 数据库中有这个表:

在此处输入图片说明

我需要使用列的内容order,并limit进行排序和筛选此表。该表将按列排序first_name

最终结果将如下图所示:

在此处输入图片说明

注意:对不起,如果这对你来说很简单,但我无法解决这个问题。所有邮件地址均由 www.mockaroo.com 生成。如果您的地址在此列表中,请不要怪我。

orderlimit列将始终具有相同的数据。order可能是ascdesclimit可能是任何整数值(但所有行都将是相同的值。它来自分组查询。

Erw*_*ter 8

询问

虽然您的解决方案很聪明,但它对性能不利,因为必须为每一行单独计算要排序的值。更重要的是,您的查询不能使用普通索引。

我建议将技巧移至LIMIT子句并使用UNION ALL. 通过这种方式,查询总体上变得更便宜,并且可以使用索引(这会破坏不能使用的竞争对手)。

WITH l AS (
   SELECT CASE WHEN ordr = 'a' THEN lim ELSE 0 END AS lim_a
        , CASE WHEN ordr = 'd' THEN lim ELSE 0 END AS lim_d
   FROM   test
   LIMIT  1
   )
(SELECT * FROM test ORDER BY first_name      LIMIT (SELECT lim_a FROM l))
UNION ALL
(SELECT * FROM test ORDER BY first_name DESC LIMIT (SELECT lim_d FROM l));
Run Code Online (Sandbox Code Playgroud)

两者之一SELECT得到LIMIT 0并且永远不会被执行。您会在EXPLAIN ANALYZE输出中看到“从未执行过” 。

在 Postgres 9.4 的快速测试(50k 中的 35 行)中,没有索引的速度大约是两倍,但有索引的速度快了几个数量级。显然,差异随着表的大小而增加。

表格布局

不要使用保留关键字作为标识符(正如您已经发现的那样):limandordr而不是limitand order

不要用多余的值来膨胀你的表。如果你不能避免存储limordr每一行,至少让它变小。基本布局:

CREATE TABLE test (
  id         int
, lim        int
, ordr       "char" CHECK (ordr IN ('a', 'd'))
, first_name text
, email      text
);
Run Code Online (Sandbox Code Playgroud)

"char"作为一个简单的枚举类型是完美的,并且只占用 1 个字节。
创建索引:

CREATE INDEX test_first_name_idx ON test(first_name);
Run Code Online (Sandbox Code Playgroud)

细节:

SQL小提琴。