将串联与 ORDER BY 相结合

Posted

技术标签:

【中文标题】将串联与 ORDER BY 相结合【英文标题】:Combining concatenation with ORDER BY 【发布时间】:2013-09-13 10:24:34 【问题描述】:

我在 Postgre (9.1.9) 中将串联与 order by 结合起来遇到了麻烦。 假设,我有一个包含 3 个字段的表格边框:

            Table "borders"
    Column     |         Type         | Modifiers 
---------------+----------------------+-----------
 country1      | character varying(4) | not null
 country2      | character varying(4) | not null
 length        | numeric              | 

前两个字段是国家代码,第三个字段是这些国家之间的边界长度。 主键在前两个字段中定义。

我需要选择一个对整个表具有唯一值的列,此外,该列应按降序选择。 为此,我将关键字段与分隔符连接起来,否则两个不同的行可能会给出相同的结果,例如 (AB, C 和 A, BC)。

所以我运行以下查询:

select  country1||'_'||country2 from borders order by 1;

但是,在结果中,我看到排序中省略了“_”字符。 结果如下所示:

 ?column? 
----------
 A_CH
 A_CZ
 A_D
 AFG_IR
 AFG_PK
 AFG_TAD
 AFG_TJ
 AFG_TM
 AFG_UZB
 A_FL
 A_H
 A_I
 .
 .

您可以看到结果被排序,好像字符串中不存在'_'。

如果我使用字母(比如“x”)作为分隔符 - 顺序是正确的。但是我必须使用一些没有出现在 country1 和 country2 字段中的特殊字符,以避免争用。

我应该怎么做,以便在排序过程中考虑到“_”字符。


编辑

原来串联与问题无关。问题是 order by 只是忽略了 '_' 字符。

【问题讨论】:

_ 字符可能与排序相关,depending on your collation settings. 谢谢,这是我不知道的,从这里的答案中学到的。 【参考方案1】:

当您执行以下操作时会发生什么?

 select  country1||'_'||country2 from borders order by country1||'_'||country2

我对按 1 排序的知识只进行序数排序。它不会对连接的列执行任何操作。当然,我说的是 SQL Server 知识,所以如果我离题了,请告诉我。

已编辑:好的;当我发布我的帖子时,刚刚看到了帕拉多的帖子。也许您可以从此查询创建一个视图(给它一个列名),然后重新查询该视图,按该列排序?或执行以下操作:

select country_group from (
    select  country1||'_'||country2 as country_group from borders
    ) a
order by country_group

【讨论】:

我更新了一个问题,如果我使用字母作为分隔符,则顺序是正确的,所以问题不在1的顺序中 Jutky,很公平。尝试上述编辑过的建议,然后按您喜欢的方式订购。似乎@Roman 的回答也可以。【参考方案2】:

只需按两列排序:

SELECT  country1||'_'||country2 FROM borders ORDER BY country1, country2;

除非您使用聚合或窗口,否则 PostgreSQL 允许按列排序,即使您没有将它们包含在 SELECT 列表中。

正如另一个答案中所建议的,您还可以更改组合列的排序规则,但如果可以的话,对普通列进行排序会更快,特别是如果您对它们有索引。

【讨论】:

恐怕这不会涵盖所有情况。我会进一步检查。感谢您的简单建议。 查询正确,会“一网打尽”。更大的问题是为什么 PostgreSql 会这样。 这行不通。例如,您有两行(“A B”、“C”)和(“A”、“B”)。在您的解决方案中,第二行将在第一行之前。但实际上,字符串“A_B”应该在“A B_C”之后。 ping @RobertCo. @RobertCo The bigger question is why is PostgreSql behaving that way. 这也让我很困扰。 @jutky “那样做”是什么意思?排序顺序由排序规则定义,因此行的顺序应取决于它。【参考方案3】:
select country1 || '_' || country2 collate "C" as a
from borders
order by 1

sql fiddle demo

根据 cmets 中讨论的注释:

1.) COLLATE "C" 适用于ORDER BY 子句,只要它通过位置参数别名 引用SELECT 子句中的表达式。如果您重复ORDER BY 中的表达式,如果您想相应地影响排序顺序,还需要重复COLLATE 子句。

sql fiddle demo

2.) 在_ 不影响排序顺序的排序规则中,使用fog's query 更有效,因为它利用了现有索引 (primary key is defined on the first two fields)。 但是,如果_ 有影响,则需要对组合表达式进行排序:

sql fiddle demo

查询性能(在 Postgres 9.2 中测试):sql fiddle demo

PostgreSQL Collation Support in the manual.

【讨论】:

好,现在考虑到特殊字符,但它在字母之后排序。为什么,'_'的ASCII码比字母的ASCII码少? 哦,我明白了,字符不是按ASCII码排序的。它们按区域设置排序,并且字母排在特殊字符之前。有没有办法按字符的 ASCII 码对字符串进行排序? @jutky 我认为更好的方法是使用雾解决方案 正如我对他的回答所评论的那样,它并没有涵盖所有情况。 好吧 OP 需要按 country1_country2 对行进行排序,而不是按 country1、country2 排序,正如他在 cmets 中所说的那样去雾化答案 - 例如你有两行(“AB”、“C” ) 和 ("A","B")。在您的解决方案中,第二行将在第一行之前。但实际上,字符串 "A_B" 应该在 "A B_C" 之后 - sqlfiddle.com/#!1/50f30/2

以上是关于将串联与 ORDER BY 相结合的主要内容,如果未能解决你的问题,请参考以下文章

结合order by 解CTF某题

oracle SQL语句中结合order by子句使用rownum

Mysql 排序Order by与分页limit结合的数据异常问题

分布式中采用Logback的MDC机制与AOP切面结合串联日志

浅谈ORDER BY分类

ORDER BY Oracle 中的串联名称?