2010-07-15 16 views
8

Cela revient beaucoup, et je peux voir qu'il est monté sur StackOverflow pour XSLT, Ruby et Drupal mais je ne' Je le vois spécifiquement pour SQL.Comment trier en SQL, en ignorant les articles ('the', "a '," an etc)

Donc, la question est, comment trier correctement les titres quand ils commencent par "The", "A" ou "An"?

Une façon est simplement TRIM() ces chaînes:

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

qui était suggested on AskMeFi un certain temps (at-il besoin de cette fonction LOWER()?).

Je sais que j'ai également vu une sorte d'implémentation de Case/Switch, mais c'est un peu difficile pour Google.

Il existe évidemment un certain nombre de solutions possibles. Ce qui serait bien, ce sont les gourous SQL qui ont des implications sur les performances.

+0

En accord avec un commentateur sur l'une des questions SO liées: les règles peuvent s'avérer plus compliquées qu'il n'y paraît. Votre suggestion particulière, par exemple, échouerait probablement à trier correctement la liste suivante: 'The A Test',' The B Test', 'The C Test'. –

Répondre

6

Une approche que j'ai vu était d'avoir deux colonnes - l'un pour l'affichage et l'autre pour le tri:

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

Je ne l'ai pas fait de tests du monde réel, mais cela a l'avantage de pouvoir pour utiliser un index et ne nécessite pas de manipulation de chaîne chaque fois que vous voulez commander par la description. À moins que votre base de données ne prenne en charge les vues matérialisées (ce qui n'est pas le cas de MySQL), implémenter la logique comme une colonne calculée dans une vue n'apporterait aucun avantage car vous ne pouvez pas indexer la colonne calculée.

0

Je ne peux parler que pour SQL Server: vous utilisez LTRIM dans les instructions CASE. Aucune fonction LOWER n'est nécessaire car les sélections ne sont pas sensibles à la casse par défaut. Cependant, si vous voulez ignorer les articles, je vous suggère d'utiliser un dictionnaire de mots parasites et de créer un catalogue d'indexation de texte intégral. Je ne suis pas sûr que d'autres implémentations soient compatibles avec SQL.

+0

La sensibilité à la casse dépend de la collation. La recherche en texte intégral (FTS) est disponible sur MySQL, Oracle, SQL Server ... Je ne sais pas ce que PostgreSQL est mais je suis sûr qu'il a des fonctionnalités natives. Et il y a des tiers FTS comme sphinx ... –

+0

"vous utilisez LTRIM dans les instructions CASE" - cela signifie-t-il que vous faites l'équivalent de "si cela commence par '', coupez-le"? Je me demandais si cela ralentirait le processus, par opposition à un TRIM global() qui pourrait échouer la plupart du temps. – AmbroseChapel

+0

LTRIM se débarrasse des espaces de premier plan – CarneyCode

-1

LOWER est nécessaire. Alors que SELECT n'est pas sensible à la casse, ORDER BY l'est.

-3

Essayez ce qui suit:

ORDER BY remplacer (remplacer (remplacer (YOURCOLUMN, 'le' ''), 'a \' », ''), 'un', '')

Non testé!

+1

Surpris personne n'a expliqué le problème avec cela. Lors du tri, vous voulez remplacer les articles LEADING, alors que cela remplacera TOUS les articles. –

2

Je l'ai utilisé pendant des années, mais ne me souviens pas où je l'ai trouvé:

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 

Cédant:

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

Pour Postgres Plus précisément, vous pouvez utiliser regexp_replace pour faire la travailler pour vous:

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;