【问题标题】:How to sort in SQL, ignoring articles ('the", "a', "an" etc)如何在 SQL 中排序,忽略文章(“the”、“a”、“an”等)
【发布时间】:2011-03-16 05:15:51
【问题描述】:

这出现了很多,我可以看到它出现在 StackOverflow 上的 XSLTRubyDrupal,但我没有看到它专门用于 SQL。

所以问题是,当标题以“The”、“A”或“An”开头时,如何正确排序?

一种方法是简单地 TRIM() 那些字符串:

ORDER BY TRIM( 
  LEADING 'a ' FROM 
  TRIM( 
    LEADING 'an ' FROM 
    TRIM( 
      LEADING 'the ' FROM LOWER( title ) 
      ) 
    ) 
  )

不久前是suggested on AskMeFi(它需要LOWER() 函数吗?)。

我知道我也看到了某种 Case/Switch 的实现,但这对 Google 来说有点困难。

显然有许多可能的解决方案。有什么好处是 SQL 专家权衡哪些对性能有影响。

【问题讨论】:

  • 同意评论者对其中一个链接的 SO 问题的看法:规则可能比看起来更复杂。例如,您的特定建议可能无法正确排序以下列表:The A TestThe B TestThe C Test

标签: sql mysql sorting switch-statement trim


【解决方案1】:

我见过的一种方法是设置两列——一列用于显示,另一列用于排序:

description  |  sort_desc
----------------------------
The the      | the, The
A test         | test, A
I, Robot      | i, Robot

我还没有做过任何真实世界的测试,但是这样做的好处是能够使用索引,并且每次您想按描述排序时都不需要进行字符串操作。除非您的数据库支持物化视图(MySQL 不支持),否则将逻辑实现为视图中的计算列不会提供任何好处,因为您无法索引计算列。

【讨论】:

    【解决方案2】:

    我已经用了很多年了,但不记得在哪里找到了它:

    SELECT 
    CASE
        WHEN SUBSTRING_INDEX(Title, ' ', 1) IN ('a', 'an', 'the') 
        THEN CONCAT( SUBSTRING( Title, INSTR(Title, ' ') + 1 ), ', ', SUBSTRING_INDEX(Title, ' ', 1) ) 
        ELSE Title 
        END AS TitleSort,
    Title AS OriginalTitle 
    FROM yourtable 
    ORDER BY TitleSort 
    

    产量:

    TitleSort                  | OriginalTitle
    ------------------------------------------------------
    All About Everything       | All About Everything
    Beginning Of The End, The  | The Beginning Of The End
    Interesting Story, An      | An Interesting Story
    Very Long Story, A         | A Very Long Story
    

    【讨论】:

      【解决方案3】:

      特别是对于 Postgres,您可以使用 regexp_replace 为您完成工作:

      BEGIN;
      CREATE TEMPORARY TABLE book (name VARCHAR NOT NULL) ON COMMIT DROP;
      INSERT INTO book (name) VALUES ('The Hitchhiker’s Guide to the Galaxy');
      INSERT INTO book (name) VALUES ('The Restaurant at the End of the Universe');
      INSERT INTO book (name) VALUES ('Life, the Universe and Everything');
      INSERT INTO book (name) VALUES ('So Long, and Thanks for All the Fish');
      INSERT INTO book (name) VALUES ('Mostly Harmless');
      INSERT INTO book (name) VALUES ('A book by Douglas Adams');
      INSERT INTO book (name) VALUES ('Another book by Douglas Adams');
      INSERT INTO book (name) VALUES ('An omnibus of books by Douglas Adams');
      
      SELECT name FROM book ORDER BY name;
      SELECT name, regexp_replace(lower(name), '^(an?|the) (.*)$', '\2, \1') FROM book ORDER BY 2;
      SELECT name FROM book ORDER BY regexp_replace(lower(name), '^(an?|the) (.*)$', '\2, \1');
      COMMIT;
      

      【讨论】:

        【解决方案4】:

        我只能代表 SQL Server:您在 CASE 语句中使用 LTRIM。不需要 LOWER 函数,因为默认情况下选择不区分大小写。但是,如果您想忽略文章,那么我建议您使用干扰词词典并设置全文索引目录。我不确定其他实现是否 SQL 支持这个。

        【讨论】:

        • 区分大小写取决于排序规则。全文搜索 (FTS) 在 MySQL、Oracle、SQL Server 上可用……不知道 PostgreSQL 是什么,但我确信它具有本机功能。还有像斯芬克斯这样的第 3 方 FTS...
        • “你在 CASE 语句中使用 LTRIM”——这是否意味着你做了相当于“如果它以 'the ' 开头,则修剪它”?我想知道这是否会减慢进程,而不是一揽子 TRIM() 可能在大多数情况下都会失败。
        • LTRIM 去掉了前导空格
        【解决方案5】:

        LOWER 是必需的。 SELECT 不区分大小写,ORDER BY 是。

        【讨论】:

          【解决方案6】:

          尝试以下方法:

          订购方式 replace(replace(replace(YOURCOLUMN,'THE',''),'a\'',''),'an','')

          未测试!

          【讨论】:

          • 很惊讶没有人解释这个问题。排序时,您要替换 LEADING 文章,而这将替换所有文章。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-09
          相关资源
          最近更新 更多