在PostgreSQL中的“ORDER BY … USING”子句

ORDER BY子句在Postgresql文档中描述为:
ORDER BY expression [ ASC | DESC | USING operator ] [ NULLS { FirsT | LAST } ] [,...]

有人可以给我一些例子如何使用USING运算符?是否可以获得结果集的交替顺序?

一个非常简单的例子是:
> 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);

你会注意到,和>原始类型的函数,如整数,日期等,一些更多的数组和向量等。这些运算符都不会帮助您获得自定义排序。

在大多数情况下,需要定制排序,你可以使用类似的东西… ORDER BY somefunc(tablecolumn)… wherefunc适当地映射值。因为它适用于每个数据库,这也是最常见的方式。对于简单的事情,你甚至可以写一个表达式而不是自定义函数

开关齿轮

ORDER BY … USING在以下情况下有意义:

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

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

当然,Postgresql有预定义的运算符:

> 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.

点的简单运算符是“下面”和“上面”运算符< ^和> ^。他们只是简单地比较点的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需要一个具有定义语义的运算符:显然它必须是一个二进制运算符,它必须接受与参数相同的类型,并且必须返回boolean。我认为它也必须是可传递的(如果a< b和b< c,那么a< c)。可能有更多的要求。但是所有这些要求对于正确的btree-index排序也是必要的。这解释了包含对btree的引用的奇怪的错误消息。 ORDER BY USING还不仅需要定义一个运算符,还需要运算符类和运算符族。虽然可以实现只有一个操作符排序,Postgresql尝试有效排序和最小化比较。因此,即使你只指定一个操作符,其他操作符也必须遵守某些数学约束 – 我已经提到了传输性,但还有更多。 开关Gears 让我们定义一些合适的:一个运算符,它只比较y部分。 第一步是创建一个可以由btree索引访问方法使用的自定义操作符系列。 see

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

接下来,我们必须提供一个比较器函数,当比较两个点时返回-1,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表示:这是小于测试的运算符。

现在运算符< ^和'> ^’可以用于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)

Voila – 按y排序。

总结:ORDER BY … USING是一个有趣的外观下的Postgresql。但是没有什么你会需要很快,除非你在非常具体的数据库技术领域工作。

一个示例可以找到in the Postgres docs.,其源代码为示例herehere.此示例还显示了如何创建运算符。

相关文章

项目需要,有个数据需要导入,拿到手一开始以为是mysql,结果...
本文小编为大家详细介绍“怎么查看PostgreSQL数据库中所有表...
错误现象问题原因这是在远程连接时pg_hba.conf文件没有配置正...
因本地资源有限,在公共测试环境搭建了PGsql环境,从数据库本...
wamp 环境 这个提示就是说你的版本低于10了。 先打印ph...
psycopg2.OperationalError: SSL SYSCALL error: EOF detect...