ORDER BY 子句在 PostgreSQL 文档中描述为:
ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FIRST | LAST } ] [, ...]
有人能给我一些如何使用
USING operator
的例子吗? ?是否有可能获得结果集的交替顺序?
最佳答案
一个非常简单的例子是:
> 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);
你会注意到,大部分是
<
和 >
原始类型的函数,如 integer
, date
等等,还有一些用于数组和向量等等。这些运算符(operator)都不会帮助您获得自定义订购。在大多数需要自定义订购的情况下,您可以使用类似
... ORDER BY somefunc(tablecolumn) ...
的东西来逃避。哪里somefunc
适本地映射值。因为这适用于每个数据库,这也是最常见的方式。对于简单的事情,您甚至可以编写表达式而不是自定义函数。换档
ORDER BY ... USING
在几种情况下是有意义的:somefunc
伎俩不起作用。 point
、 circle
或虚数),并且您不想在查询中使用奇怪的计算重复自己。 我将专注于复杂的数据类型:通常有不止一种方法可以以合理的方式对它们进行排序。一个很好的例子是
point
:您可以按到 (0,0) 的距离“排序”它们,或者先按 x,然后按 y 或仅按 y 或您想要的任何其他东西。当然,PostgreSQL 已经为
point
预定义了操作符。 : > 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.
ORDER BY USING
需要一个具有定义语义的运算符:显然它必须是一个二元运算符,它必须接受与参数相同的类型,并且它必须返回 bool 值。我认为它也必须是可传递的(如果 a < b 和 b < c 那么 a < c)。可能还有更多要求。但所有这些要求对于适当的 也是必要的。 btree -索引排序。这解释了包含对 的引用的奇怪错误消息。 btree .ORDER BY USING
不仅需要定义一个运算符,还需要定义一个运算符类和一个运算符族。虽然可以只用一个运算符实现排序,但 PostgreSQL 试图有效地排序并尽量减少比较。因此,即使您只指定一个运算符,也会使用多个运算符——其他运算符必须遵守某些数学约束——我已经提到了传递性,但还有更多。换档
让我们定义一些合适的东西:一个只比较
y
的点运算符。部分。第一步是创建一个可由 使用的自定义运算符族。 btree 索引访问方法。 see
> CREATE OPERATOR FAMILY xyzfam USING btree; -- superuser access required!
CREATE OPERATOR FAMILY
接下来,我们必须提供一个比较器函数,它在比较两点时返回 -1、0、+1。此函数将在内部调用!
> CREATE FUNCTION xyz_v_cmp(p1 point, p2 point) RETURNS int
AS $$BEGIN RETURN btfloat8cmp(p1[1],p2[1]); END $$ LANGUAGE plpgsql;
CREATE FUNCTION
接下来,我们为系列定义操作符类。 See the manual对数字的解释。
> 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
:> 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)
瞧 - 按 y 排序。
总结一下:
ORDER BY ... USING
是 PostgreSQL 引擎盖下的有趣外观。但是,除非您在非常特定的数据库技术领域工作,否则您不会很快需要任何东西。另一个例子可以找到 in the Postgres docs.带有示例的源代码 here和 here .此示例还展示了如何创建运算符。
关于sql - PostgreSQL 中的 "ORDER BY ... USING"子句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7205878/