SQL: Ordenar por nombre de dominio de correo electrónico
-
06-07-2019 - |
Pregunta
¿Cuál es la instrucción SQL más corta y / o eficiente para ordenar una tabla con una columna de dirección de correo electrónico por su fragmento de nombre DOMINIO?
Eso esencialmente ignora lo que sea que esté antes de " @ " en las direcciones de correo electrónico y no distingue entre mayúsculas y minúsculas. Ignoremos los nombres de dominio internacionalizados para este.
Destino en: mySQL, MSSQL, Oracle
Datos de muestra 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
Ordenar por correo electrónico
SELECCIONAR * DE LA TABLA 1 ORDENAR POR CORREO ELECTRÓNICO 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
Ordenar por dominio
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
EDITAR:
No estoy pidiendo una sola declaración SQL que funcione en los 3 o más motores SQL. Cualquier contribución es bienvenida. :)
Solución
Prueba esto
Consulta (para servidor SQL):
select * from mytbl
order by SUBSTRING(email,(CHARINDEX('@',email)+1),1)
Consulta (para Oracle):
select * from mytbl
order by substr(email,INSTR(email,'@',1) + 1,1)
Consulta (para MySQL)
pygorex1 already answered
Salida:
nombre de correo electrónico de identificación
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
Otros consejos
Para MySQL:
select email, SUBSTRING_INDEX(email,'@',-1) AS domain from user order by domain desc;
Para mayúsculas y minúsculas:
select user_id, username, email, LOWER(SUBSTRING_INDEX(email,'@',-1)) AS domain from user order by domain desc;
Si desea que esta solución se escale, no debería intentar extraer subcolumnas. Las funciones por fila son notoriamente lentas a medida que la tabla se hace más y más grande.
Lo correcto en este caso es mover el costo de extracción de select
(donde sucede mucho) a insert / update donde ocurre menos (en la mayoría de las bases de datos normales). Al incurrir en el costo solo en
insert
y update
, aumenta en gran medida la eficiencia general de la base de datos, ya que ese es el solo momento en el que necesita hacerlo (es decir, es el único momento en que los datos cambian).
Para lograr esto, divida la dirección de correo electrónico en dos columnas distintas en la tabla, email_user
y email_domain
). Luego, puede dividirlo en su aplicación antes de la inserción / actualización o usar un activador (o columnas precalculadas si su DBMS lo admite) en la base de datos para hacerlo automáticamente.
Luego ordena en email_domain
y, cuando desea la dirección de correo electrónico completa, usa email_name | '@' | email_domain
.
Alternativamente, puede mantener la columna email
completa y usar un disparador para duplicar solo la parte del dominio en email_domain
, luego nunca tendrá que preocuparse por concatenar las columnas a obtener la dirección de correo electrónico completa.
Es perfectamente aceptable revertir de 3NF por razones de rendimiento siempre que sepa lo que está haciendo. En este caso, los datos en las dos columnas no se pueden desincronizar simplemente porque los desencadenantes no lo permiten. Es una buena manera de intercambiar espacio en disco (relativamente barato) por rendimiento ( siempre queremos más de eso).
Y, si eres del tipo al que no le gusta revertir de 3NF, la solución email_name / email_domain
lo solucionará.
Esto también supone que solo desea manejar las direcciones de correo electrónico del formulario a @ b
: hay otras direcciones de correo electrónico válidas, pero no recuerdo haber visto ninguna de ellas en la naturaleza durante años.
Para SQL Server, puede agregar una columna calculada a su tabla con extractos del dominio en un campo separado. Si persiste esa columna en la tabla, puede usarla como cualquier otro campo e incluso ponerle un índice, para acelerar las cosas, si consulta mucho por nombre de dominio:
ALTER TABLE Table1
ADD DomainName AS
SUBSTRING(email, CHARINDEX('@', email)+1, 500) PERSISTED
Entonces, su tabla tendría una columna adicional " DomainName " que contiene cualquier cosa después de " @ " inicie sesión en su dirección de correo electrónico.
Suponiendo que realmente debe atender a MySQL, Oracle y MSSQL ... la forma más eficiente podría ser almacenar el nombre de la cuenta y el nombre de dominio en dos campos separados. El puede hacer su pedido:
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
como señala donnie, las funciones de manipulación de cadenas no son estándar ... ¡es por eso que tendrás que mantener los datos redundantes!
Agregué cuenta y dominio a la tercera consulta, ya que creo que no todos los DBMS ordenarán una consulta en un campo que no está en los campos seleccionados.
Para postgres la consulta es:
SELECT * FROM table
ORDER BY SUBSTRING(email,(position('@' in email) + 1),252)
El valor 252
es el dominio más largo permitido (ya que la longitud máxima de un correo electrónico es 254
incluyendo la parte local, el @
y el dominio.
Vea esto para más detalles: ¿Cuál es el longitud máxima de una dirección de correo electrónico válida?
Tendrá que usar las funciones de manipulación de texto para analizar el dominio. Luego ordene por la nueva columna.
MySQL, una combinación inteligente de right () y instr ()
SQL Server, right () y patindex ()
Y, como dijo alguien más, si tiene un recuento de registros decente a alto, ajustando su campo de correo electrónico en funciones donde la cláusula lo hará para que el RDBMS no pueda usar ningún índice que pueda tener en esa columna. Por lo tanto, es posible que desee considerar crear una columna calculada que contenga el dominio.
Si tiene millones de registros, le sugiero que cree una nueva columna solo con el nombre de dominio.
Esto funcionará con Oracle:
select id,name,email,substr(email,instr(email,'@',1)+1) as domain
from table1
order by domain asc
Mi sugerencia sería (para 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 respuesta original para SQL Server no funcionó para mí ...
Aquí hay una versión para 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
trabaja de manera más inteligente, no más duro:
SELECT REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING(emails.email, POSITION('@' IN emails.email)+1)),'.',2)) FROM emails