SQL: сортировка по имени домена электронной почты - PullRequest
18 голосов
/ 28 ноября 2009

Какой самый короткий и / или эффективный оператор SQL для сортировки таблицы со столбцом адреса электронной почты по фрагменту имени DOMAIN?

Это, по сути, игнорирование того, что стоит перед "@" в адресах электронной почты и без учета регистра. Давайте проигнорируем интернационализированные доменные имена для этого.

Цель: mySQL, MSSQL, Oracle

Пример данных от 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

Заказ по электронной почте
SELECT * FROM TABLE1 ORDER BY 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

Заказ по домену
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

EDIT:
Я не прошу ни одного оператора SQL, который будет работать на всех трех или более механизмах SQL. Любой вклад приветствуется. :)

Ответы [ 13 ]

20 голосов
/ 28 ноября 2009

Попробуйте это

Запрос (для сервера Sql):

select * from mytbl
order by SUBSTRING(email,(CHARINDEX('@',email)+1),1)

Запрос (для Oracle):

select * from mytbl
order by substr(email,INSTR(email,'@',1) + 1,1)

Запрос (для MySQL)

pygorex1 already answered

Выход:

идентификатор электронной почты

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
17 голосов
/ 28 ноября 2009

Для MySQL:

select email, SUBSTRING_INDEX(email,'@',-1) AS domain from user order by domain desc;

Для нечувствительного к регистру:

select user_id, username, email, LOWER(SUBSTRING_INDEX(email,'@',-1)) AS domain from user order by domain desc;
8 голосов
/ 28 ноября 2009

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

В этом случае правильное нужно сделать, чтобы переместить стоимость извлечения с select (где это часто происходит) на insert/update, где это происходит меньше (в большинстве обычных баз данных). Взяв на себя расходы только на insert и update, вы значительно увеличите общую эффективность базы данных, поскольку это только момент времени, когда вам нужно это сделать (т.е. это единственный раз, когда при изменении данных).

Чтобы добиться этого, разделите адрес электронной почты на два отдельных столбца в таблице, email_user и email_domain). Затем вы можете либо разделить его в своем приложении перед вставкой / обновлением, либо использовать триггер (или предварительно вычисленные столбцы, если ваша СУБД поддерживает это) в базе данных, чтобы сделать это автоматически.

Затем вы сортируете по email_domain и, когда вам нужен полный адрес электронной почты, вы используете email_name|'@'|email_domain.

Кроме того, вы можете сохранить полный столбец email и использовать триггер для дублирования только части домена в email_domain, тогда вам не нужно беспокоиться о объединении столбцов для получения полного адреса электронной почты.

Вполне допустимо вернуться из 3NF по соображениям производительности, если вы знаете, что делаете. В этом случае данные в двух столбцах не могут быть синхронизированы просто потому, что триггеры этого не допустят. Это хороший способ обменять дисковое пространство (относительно дешево) на производительность (мы всегда хотим большего).

И, если вы совсем не любите возвращаться из 3NF, решение email_name/email_domain исправит это.

Это также предполагает, что вы просто хотите обрабатывать адреса электронной почты в форме a@b - есть другие действительные адреса электронной почты, но я не могу вспомнить, чтобы кто-нибудь видел их в дикой природе в течение многих лет.

4 голосов
/ 28 ноября 2009

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

ALTER TABLE Table1
  ADD DomainName AS 
     SUBSTRING(email, CHARINDEX('@', email)+1, 500) PERSISTED

Так что теперь ваша таблица будет иметь дополнительный столбец «DomainName», который содержит что-либо после знака «@» в вашем адресе электронной почты.

2 голосов
/ 24 февраля 2016

Для postgres запрос:

SELECT * FROM table
ORDER BY SUBSTRING(email,(position('@' in email) + 1),252)

Значение 252 является самым длинным разрешенным доменом (поскольку максимальная длина электронного письма составляет 254, включая локальную часть, @ и домен.

См. Это для более подробной информации: Какова максимальная длина действующего адреса электронной почты?

2 голосов
/ 28 ноября 2009

Предполагая, что вы действительно должны обслуживать MySQL, Oracle и MSSQL. Наиболее эффективным способом может быть сохранение имени учетной записи и имени домена в двух отдельных полях. Вы можете сделать свой заказ:

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

как указывает Донни, функции манипуляции со строками не являются стандартными ... поэтому вам придется сохранять избыточность данных!

Я добавил учетную запись и домен к третьему запросу, так как хочу напомнить, что не все СУБД будут сортировать запрос по полю, которого нет в выбранных полях.

1 голос
/ 19 июня 2016

Оригинальный ответ для SQL Server не работал для меня ....

Вот версия для 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
1 голос
/ 14 апреля 2015

Мое предложение будет (для 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;
А потом просто добавьте ГДЕ ...
1 голос
/ 28 ноября 2009

Это будет работать с Oracle:

select id,name,email,substr(email,instr(email,'@',1)+1) as domain
from table1
order by domain asc
1 голос
/ 28 ноября 2009

Если у вас есть миллион записей, я предлагаю вам создать новый столбец только с именем домена.

...