PostgreSQL中的“ORDER BY ... USING”子句

时间:2011-08-26 14:06:29

标签: sql postgresql sql-order-by

ORDER BY子句在PostgreSQL文档中描述为:

ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...]

有人可以举例说明如何使用USING operator吗?是否可以获得结果集的交替顺序?

4 个答案:

答案 0 :(得分:43)

一个非常简单的例子是:

> SELECT * FROM tab ORDER BY col USING <

但这很无聊,因为传统的ORDER BY col ASC是你无法得到的。

标准目录也没有提到任何令人兴奋的奇怪的比较函数/运算符。您可以获得它们的列表:

    > SELECT amoplefttype::regtype, amoprighttype::regtype, amopopr::regoper 
      FROM pg_am JOIN pg_amop ON pg_am.oid = pg_amop.amopmethod 
      WHERE amname = 'btree' AND amopstrategy IN (1,5);

您会注意到,<>等基本类型主要有integerdate函数,而对于数组和向量则更多,等等。这些运营商都不会帮助您获得自定义订购。

大多数需要自定义排序的情况下,您可以使用... ORDER BY somefunc(tablecolumn) ...之类的内容,somefunc适当地映射值。因为这适用于每个数据库,这也是最常见的方式。对于简单的事情,您甚至可以编写表达式而不是自定义函数。

切换档次

ORDER BY ... USING在某些情况下有意义:

  • 排序非常罕见,somefunc技巧不起作用。
  • 您使用的是非原始类型(如pointcircle或虚数)并且您不想在奇怪的计算中重复自己的查询。
  • 您要排序的数据集非常大,需要或甚至需要索引支持。

我将专注于复杂的数据类型:通常有多种方法可以合理的方式对它们进行排序。一个很好的例子是point:你可以通过距离(0,0),或者通过 x ,然后通过 y 或者只是“命令”它们。通过 y 或您想要的任何其他内容。

当然,PostgreSQL 拥有<{1}}的预定义运算符:

point

但默认情况下, none 声明可用于 > CREATE TABLE p ( p point ); > SELECT p <-> point(0,0) FROM p; (见上文):

ORDER BY

> SELECT * FROM p ORDER BY p; ERROR: could not identify an ordering operator for type point TIP: Use an explicit ordering operator or modify the query. 的简单运算符是“下方”和“上方”运算符point<^。他们只比较了>^部分。但是:

y

> SELECT * FROM p ORDER BY p USING >^; ERROR: operator > is not a valid ordering operator TIP: Ordering operators must be "<" or ">" members of __btree__ operator families. 需要一个具有已定义语义的运算符:显然它必须是二元运算符,它必须接受与参数相同的类型,并且必须返回boolean。我认为它也必须是可传递的(如果&lt; b和b&lt; c然后a&lt; c)。可能有更多要求。但所有这些要求对于正确的 btree - 索引排序也是必要的。这解释了包含对 btree 的引用的奇怪错误消息。

ORDER BY USING还不仅需要定义一个运算符,还需要运算符类运算符族。虽然一个可以只用一个运算符实现排序,但PostgreSQL会尝试有效排序并最小化比较。因此,即使只指定了一个操作符,也会使用多个操作符 - 其他操作符必须遵守某些数学约束 - 我已经提到过传递性,但还有更多操作符。

切换Gears

让我们定义一些合适的东西:一个只比较ORDER BY USING部分的点的运算符。

第一步是创建一个可由 btree 索引访问方法使用的自定义运算符族。 see

y

接下来我们必须提供一个比较器函数,在比较两个点时返回-1,0,+ 1。这个函数在内部调用!

    > CREATE OPERATOR FAMILY xyzfam USING btree;   -- superuser access required!
    CREATE OPERATOR FAMILY

接下来,我们定义该族的运算符类。 See the manual有关数字的解释。

    > CREATE FUNCTION xyz_v_cmp(p1 point, p2 point) RETURNS int 
      AS $$BEGIN RETURN btfloat8cmp(p1[1],p2[1]); END $$ LANGUAGE plpgsql;
    CREATE FUNCTION

此步骤结合了多个运算符和函数,并定义了它们之间的关系和含义。例如 > CREATE OPERATOR CLASS xyz_ops FOR TYPE point USING btree FAMILY xyzfam AS OPERATOR 1 <^ , OPERATOR 3 ?- , OPERATOR 5 >^ , FUNCTION 1 xyz_v_cmp(point, point) ; CREATE OPERATOR CLASS 表示:这是OPERATOR 1测试的运算符。

现在可以在less-than中使用运算符<^>^

ORDER BY USING

Voila - 按 y 排序。

总结一下: > INSERT INTO p SELECT point(floor(random()*100), floor(random()*100)) FROM generate_series(1, 5); INSERT 0 5 > SELECT * FROM p ORDER BY p USING >^; p --------- (17,8) (74,57) (59,65) (0,87) (58,91) 是PostgreSQL的一个有趣的外观。但是除非你在非常特定的数据库技术领域工作,否则你很快就会需要。

可以找到in the Postgres docs.的另一个示例,其中包含示例herehere的源代码。此示例还说明了如何创建运算符。

答案 1 :(得分:4)

样品:

CREATE TABLE test
(
  id serial NOT NULL,
  "number" integer,
  CONSTRAINT test_pkey PRIMARY KEY (id)
)

insert into test("number") values (1),(2),(3),(0),(-1);

select * from test order by number USING > //gives 3=>2=>1=>0=>-1

select * from test order by number USING < //gives -1=>0=>1=>2=>3

因此,它相当于descasc。但您可以使用自己的运算符,这是USING

的基本功能

答案 2 :(得分:1)

很好的答案,但他们没有提到一个真正有价值的USING案例。

使用非默认运算符族创建索引时,例如varchar_pattern_ops(〜&gt;〜,〜&lt;〜,〜&gt; =〜...)而不是&lt;,&gt;,&gt; = ...然后,如果您基于索引进行搜索并且想要在order by子句中使用index,则需要使用适当的运算符指定USING。

这可以用这样的例子说明:

CREATE INDEX index_words_word ON words(word text_pattern_ops); 

让我们比较这两个问题:

SELECT * FROM words WHERE word LIKE 'o%' LIMIT 10;

SELECT * FROM words WHERE word LIKE 'o%' ORDER BY word LIMIT 10;

他们的执行差异接近100倍,500K字DB!并且在非C语言环境中结果可能也不正确。

这怎么可能发生?

使用LIKE和ORDER BY子句进行搜索时,实际上是在进行此调用:

SELECT * FROM words WHERE word ~>=~ 'o' AND word ~<~'p' ORDER BY word USING < LIMIT 10;

您的索引是以〜&lt;〜运算符为基础创建的,因此PG不能在给定的ORDER BY子句中使用给定的索引。要完成任务,必须将查询重写为此表单:

SELECT * FROM words WHERE word ~>=~ 'o' AND word ~<~'p' ORDER BY word USING ~<~ LIMIT 10;

SELECT * FROM words WHERE word LIKE 'o%' ORDER BY word USING ~<~ LIMIT 10;

答案 3 :(得分:0)

  

可选择添加关键字ASC(升序)或DESC   在ORDER BY子句中的任何表达式之后(降序)。如果不   指定,默认情况下采用ASC。或者,具体的   可以在USING子句中指定排序运算符名称。一个   排序运算符必须小于或大于某些成员   B树操作员家庭。 ASC通常等同于USING&lt;和DESC   通常相当于USING&gt;。

PostgreSQL 9.0

我认为它可能看起来像这样(我现在没有postgres来验证这一点,但稍后会验证)

SELECT Name FROM Person
ORDER BY NameId USING >