Как сортировать в SQL, игнорируя статьи («the», «a», «an» и т. Д.) - PullRequest
8 голосов
/ 15 июля 2010

Это часто встречается, и я вижу, что оно появляется в StackOverflow для XSLT , Ruby и Drupal , но я не вижу этого специальнодля SQL.

Итак, вопрос в том, как правильно отсортировать заголовки, когда они начинаются с "The", "A" или "An"?

Один из способов - просто TRIM () эти строки:

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

, который был предложен на AskMeFi некоторое время назад (нужна ли эта функция LOWER()?).

Я знаю, что ятакже видел какую-то реализацию Case / Switch, но это немного сложно для Google.

Очевидно, что есть ряд возможных решений.Что было бы хорошо, так это взвешивание гуру SQL, влияющее на производительность.

Ответы [ 6 ]

6 голосов
/ 15 июля 2010

Один из подходов, которые я видел, состоял в том, чтобы иметь два столбца - один для отображения, а другой для сортировки:

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

Я не проводил никаких реальных испытаний, но у него есть преимущество, заключающееся в возможности использовать индекс и не требует манипулирования строками каждый раз, когда вы хотите упорядочить по описанию. Если ваша база данных не поддерживает материализованные представления (чего нет в MySQL), реализация логики как вычисляемого столбца в представлении не даст никакой выгоды, поскольку вы не можете индексировать вычисляемый столбец.

2 голосов
/ 24 июня 2015

Я использовал это в течение многих лет, но не могу вспомнить, где я нашел это:

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
0 голосов
/ 24 октября 2017

В частности, для 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;
0 голосов
/ 14 июня 2013

Попробуйте следующее:

ORDER BY replace (заменить (заменить (YOURCOLUMN, 'THE', ''), 'a \' ',' '),' an ',' ')

Не проверено!

0 голосов
/ 11 декабря 2010

LOWER необходимо. * * * * * * * * * * * * * * * * * * * * * * * *

ORDER BY
0 голосов
/ 15 июля 2010

Я могу говорить только за SQL Server: вы используете LTRIM в инструкциях CASE. Функция LOWER не требуется, потому что выборки по умолчанию не чувствительны к регистру. Однако, если вы хотите игнорировать статьи, я бы посоветовал вам использовать словарь шумных слов и настроить каталог полнотекстовой индексации. Я не уверен, что другие реализации SQL поддерживают это.

...