sql - PostgreSQL 中的 "ORDER BY ... USING"子句

标签 sql postgresql sql-order-by

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伎俩不起作用。
  • 您使用非原始类型(如 pointcircle 或虚数),并且您不想在查询中使用奇怪的计算重复自己。
  • 您要排序的数据集非常大,需要甚至需要索引的支持。

  • 我将专注于复杂的数据类型:通常有不止一种方法可以以合理的方式对它们进行排序。一个很好的例子是 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.带有示例的源代码 herehere .此示例还展示了如何创建运算符。

    关于sql - PostgreSQL 中的 "ORDER BY ... USING"子句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7205878/

    相关文章:

    java - 选择哪里.... ms sql 2005 中需要电气状态

    sql - 在六边形区域中选择相邻单元格

    mysql - 全文搜索生成错误结果

    MYSQL GROUP BY/ORDER BY 混淆

    c# - WPF AvalonEdit SQL xhsd 请求

    postgresql - PostgreSQL 中不同命令行提示符的含义?

    postgresql - 在 Postgres 中创建一个触发器,它将一条记录插入到另一个带有添加列的表中

    mysql 精细具体命令类别

    sql - 几个 ORDER BY 条件,最后一个很昂贵 - 如何优化它?

    mysql - 将 mysql 查询转换为 postgresql 查询