当前位置: 首页 > 面试题库 >

PostgreSQL中的“ RDER BY”(使用)子句

欧君之
2023-03-14
问题内容

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

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);

您会注意到,主要有<>函数用于基本类型,例如integerdate等等,还有更多函数用于数组和向量等等。这些操作员都无法帮助您获得自定义订购。

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

换档

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需要具有定义的语义的运算符:显然,它必须是二进制运算符,它必须接受与参数相同的类型,并且必须返回布尔值。我认为它也必须是可传递的(如果a
<b和b <c则a <c)。可能还有更多要求。但是,所有这些要求对于正确的 btree
-index排序也是必需的。这解释了奇怪的错误消息,其中包含对 btree 的引用。

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

换档

让我们定义一个合适的东西:一个只比较y零件的点运算符。

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

    > 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

接下来,我们为家庭定义操作员类别。有关数字的说明,请参见手册。

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

Voila-按 y 排序。

总结一下: ORDER BY ... USING在PostgreSQL的幕后, 是一个有趣的外观。但是除非您在数据库技术的 非常
特定的领域中工作,否则您很快将不需要任何东西。

可以在Postgres文档中找到另一个示例。在这里和这里的示例源代码。此示例还显示了如何创建运算符。



 类似资料:
  • 问题内容: 我正在尝试使用该子句从表中检索数据。我想从中获取除存在的行以外的所有行。据我了解,以下内容不起作用: 我可以使用的唯一方法似乎是从相同的表中选择,或者从不同的表中选择具有相同列名的列。 有人可以解释一下如何最好地使用解释子句吗? 问题答案: 您的查询似乎完全有效: 列 名 与查询无关。只有 数据类型 必须匹配。您的查询的输出列名称为,仅因为它是first中的列名称。您可以使用任何别名。

  • 问题内容: 我有这样的查询: 出现以下错误: 在MySql中,这是有效的,但显然在Postgresql中是无效的。据我所知,原因是查询部分的评估晚于该部分。是否有解决此问题的常用解决方法? 问题答案: 正如您所经历的那样,MySQL的支持是非标准的。正确的方法是重新打印SELECT子句中使用的相同表达式:

  • 问题内容: 可以说我有这样的第一张桌子 分支表 第二张桌子是这样的 余额表 我想查询余额表,其中每一行包含分支表的名称。例如分支表中的“ 123456ABC”,我想从余额表中获取“ ABC”行 我怎样才能做到这一点?到目前为止,我还没有尝试过这个查询 有什么建议吗? 问题答案: 你应该 转换 了的名称模式: 联接看起来更易读:

  • 问题内容: 假设我有此表:named = the_table, 其结构为: PostgreSQL的: MySQL: 然后我插入了表格: 现在该表如下所示: 当我执行此查询时: 然后在mysql中,我得到: 在PostgreSQL中,我得到了错误: 我的问题: 这个错误是什么意思?什么是集合函数? 当它在MySQL中工作时,为什么不能在postgreSQL中工作? 问题答案: 您需要使用AGGREG

  • 问题内容: 我在SO上找到了一些主题,但是仍然找不到适合我的查询的设置。 这是查询,在本地主机上运行得很好: 但是在Heroku上,我 遇到了-GROUP BY子句 上面的错误, 或者在聚合函数中使用 。 然后,我在某处读到,我应该指定表中的所有列,因此我尝试了以下操作: 但这在本地主机上不起作用,在Heroku上也不行… 什么是查询的正确配置? 问题答案: 我认为您正在尝试在同一列上进行汇总和分

  • 我需要在应用程序中使用多个时区。 基本上,我的系统生成数据,来自地球上任何地方的客户都可以访问它。 由于我的数据有一个关联的时间戳,我考虑了以下策略来处理时区。 在邮件中: > 使用类型为我的时间戳创建我的表。不允许使用不带时区的时间戳,因为在我的情况下,混合使用和就像是一个定时炸弹。 将我的PG服务器系统的时区设置为`UTC。 在中设置(如果系统的TZ是UTC,可能就不需要了,但我有点偏执,这没