SQL: Tri par nom de domaine de messagerie
-
06-07-2019 - |
Question
Quelle est l'instruction SQL la plus courte et / ou la plus efficace pour trier une table avec une colonne d'adresse électronique en fonction de son fragment de nom DOMAIN?
C’est essentiellement ignorer tout ce qui se trouve avant " @ " dans les adresses e-mail et insensible à la casse. Ignorons les noms de domaine internationalisés pour celui-ci.
Ciblez à: MySQL, MSSQL, Oracle
Exemple de données à partir de TABLE1
id name email ------------------------------------------ 1 John Doe johndoe@domain.com 2 Jane Doe janedoe@helloworld.com 3 Ali Baba ali@babaland.com 4 Foo Bar foo@worldof.bar.net 5 Tarrack Ocama me@am-no-president.org
Commande par courrier électronique
SELECT * FROM TABLE1 COMMANDER PAR EMAIL ASC
id name email ------------------------------------------ 3 Ali Baba ali@babaland.com 4 Foo Bar foo@worldof.bar.net 2 Jane Doe janedoe@helloworld.com 1 John Doe johndoe@domain.com 5 Tarrack Ocama me@am-no-president.org
Trier par domaine
SELECT * FROM TABLE1 ORDER BY ?????? ASC
id name email ------------------------------------------ 5 Tarrack Ocama me@am-no-president.org 3 Ali Baba ali@babaland.com 1 John Doe johndoe@domain.com 2 Jane Doe janedoe@helloworld.com 4 Foo Bar foo@worldof.bar.net
MODIFIER:
Je ne demande pas une seule instruction SQL qui fonctionnera sur les 3 moteurs SQL ou plus. Toute contribution est la bienvenue. :)
La solution
Essayez ceci
Requête (pour SQL Server):
select * from mytbl
order by SUBSTRING(email,(CHARINDEX('@',email)+1),1)
Requête (pour Oracle):
select * from mytbl
order by substr(email,INSTR(email,'@',1) + 1,1)
Requête (pour MySQL)
pygorex1 already answered
Sortie:
email nom d'utilisateur
5 Tarrack Ocama me@am-no-president.org
3 Ali Baba ali@babaland.com
1 John Doe johndoe@domain.com
2 Jane Doe janedoe@helloworld.com
4 Foo Bar foo@worldof.bar.net
Autres conseils
Pour MySQL:
select email, SUBSTRING_INDEX(email,'@',-1) AS domain from user order by domain desc;
Pour la casse:
select user_id, username, email, LOWER(SUBSTRING_INDEX(email,'@',-1)) AS domain from user order by domain desc;
Si vous souhaitez que cette solution évolue, vous ne devriez pas essayer d'extraire des sous-colonnes. Les fonctions par ligne sont notoirement lentes car la table devient de plus en plus grande.
Dans ce cas, la droite chose à faire est de déplacer le coût d'extraction de select
(où cela se produit souvent) vers insert / update
où il se produit moins (dans la plupart des bases de données normales). En assumant les coûts uniquement sur insert
et update
, vous augmentez considérablement l'efficacité globale de la base de données, car il s'agit du seul point besoin de le faire (c’est-à-dire que c’est le seul moment où les données changent).
Pour ce faire, divisez l'adresse électronique en deux colonnes distinctes dans la table, utilisateur_email
et domaine_email
). Vous pouvez ensuite le scinder dans votre application avant l'insertion / la mise à jour ou utiliser un déclencheur (ou des colonnes pré-calculées si votre SGBD le prend en charge) dans la base de données pour le faire automatiquement.
Ensuite, vous effectuez un tri sur domaine_email
et, lorsque vous souhaitez obtenir l'adresse électronique complète, vous utilisez nom_email | '@' | domaine_email
.
Vous pouvez également conserver la colonne email
et utiliser un déclencheur pour dupliquer uniquement la partie de domaine dans domaine_email
. Vous n'aurez donc jamais à vous soucier de la concaténation des colonnes. obtenir l'adresse e-mail complète.
Il est parfaitement acceptable de revenir de 3NF pour des raisons de performances, à condition que vous sachiez ce que vous faites. Dans ce cas, les données des deux colonnes ne peuvent pas être désynchronisées simplement parce que les déclencheurs ne le permettent pas. C'est un bon moyen d'échanger de l'espace disque (relativement bon marché) contre des performances (nous toujours voulons plus que cela).
Et si vous n'aimez pas du tout revenir à 3NF, la solution email_name / email_domain
résoudra ce problème.
Cela suppose également que vous souhaitiez simplement gérer les adresses électroniques de la forme a @ b
- il existe d'autres adresses électroniques valides, mais je ne me souviens pas en avoir vu l'une à l'état sauvage pendant des années.
Pour SQL Server, vous pouvez ajouter une colonne calculée à votre table en extrayant le domaine dans un champ séparé. Si vous conservez cette colonne dans la table, vous pouvez l'utiliser comme n'importe quel autre champ et même y mettre un index pour accélérer les choses, si vous interrogez beaucoup par nom de domaine:
ALTER TABLE Table1
ADD DomainName AS
SUBSTRING(email, CHARINDEX('@', email)+1, 500) PERSISTED
Votre table aurait alors une colonne supplémentaire "quotName". qui contient quelque chose après "& @" connectez-vous à votre adresse e-mail.
En supposant que vous deviez vraiment gérer MySQL, Oracle et MSSQL .. le moyen le plus efficace pourrait consister à stocker le nom du compte et le nom du domaine dans deux champs distincts. Le vous pouvez faire votre commande:
select id,name,email from table order by name
select id,name,email,account,domain from table order by email
select id,name,email,account,domain from table order by domain,account
comme le souligne donnie, les fonctions de manipulation des chaînes ne sont pas standard .. C’est pourquoi vous devrez conserver les données redondantes!
J'ai ajouté un compte et un domaine à la troisième requête, car je me sers pour rappeler tous les SGBD ne trieront pas une requête sur un champ qui ne figure pas dans les champs sélectionnés.
Pour postgres, la requête est:
SELECT * FROM table
ORDER BY SUBSTRING(email,(position('@' in email) + 1),252)
La valeur 252
est le domaine le plus long autorisé (car la longueur maximale d'un e-mail est 254
, y compris la partie locale, le @
et le domaine.
Voir ceci pour plus de détails: Quel est le longueur maximale d'une adresse e-mail valide?
Vous allez devoir utiliser les fonctions de manipulation de texte pour analyser le domaine. Ensuite, commandez par la nouvelle colonne.
MySQL, une combinaison intelligente de right () et instr ()
SQL Server, right () et patindex ()
Et, comme l’a dit quelqu'un d'autre, si vous avez un nombre d'enregistrements décent à élevé, le fait de placer votre champ d'e-mail dans des fonctions vous permettant de ne pas utiliser d'index dans cette colonne. Vous pouvez donc envisager de créer une colonne calculée contenant le domaine.
Si vous avez des millions d'enregistrements, je vous suggère de créer une nouvelle colonne avec un nom de domaine uniquement.
Ceci fonctionnera avec Oracle:
select id,name,email,substr(email,instr(email,'@',1)+1) as domain
from table1
order by domain asc
Ma suggestion serait (pour mysql):
SELECT
LOWER(email) AS email,
SUBSTRING_INDEX(email, '@', + 1) AS account,
REPLACE(SUBSTRING_INDEX(email, '@', -1), CONCAT('.',SUBSTRING_INDEX(email, '.', -1)),'') -- 2nd part of mail - tld.
AS domain,
CONCAT('.',SUBSTRING_INDEX(email, '.', -1)) AS tld
FROM
********
ORDER BY domain, email ASC;
La réponse originale pour SQL Server ne fonctionnait pas pour moi ....
Voici une version pour SQL Server ...
select SUBSTRING(email,(CHARINDEX('@',email)+1),len(email)), count(*)
from table_name
group by SUBSTRING(email,(CHARINDEX('@',email)+1),len(email))
order by count(*) desc
travaillez plus intelligemment, pas plus fort:
SELECT REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING(emails.email, POSITION('@' IN emails.email)+1)),'.',2)) FROM emails