20

用域名片段对包含电子邮件地址列的表进行排序的最短和/或有效的 SQL 语句是什么?

这基本上忽略了电子邮件地址中“@”之前的任何内容并且不区分大小写。让我们忽略这个的国际化域名。

目标:mySQL、MSSQL、Oracle

样本数据来自TABLE1

身份证 姓名 电子邮件
------------------------------------------
 1 约翰·多伊 johndoe@domain.com
 2 简·多伊 janedoe@helloworld.com
 3 阿里巴巴 ali@babaland.com
 4 Foo 酒吧 foo@worldof.bar.net
 5 Tarrack Ocama me@am-no-president.org

通过电子邮件订购
SELECT * FROM TABLE1 ORDER BY EMAIL ASC

身份证 姓名 电子邮件
------------------------------------------
 3 阿里巴巴 ali@babaland.com
 4 Foo 酒吧 foo@worldof.bar.net
 2 简·多伊 janedoe@helloworld.com
 1 约翰·多伊 johndoe@domain.com
 5 Tarrack Ocama me@am-no-president.org

按域排序
SELECT * FROM TABLE1 ORDER BY ?????? ASC

身份证 姓名 电子邮件
------------------------------------------
 5 Tarrack Ocama me@am-no-president.org
 3 阿里巴巴 ali@babaland.com
 1 约翰·多伊 johndoe@domain.com
 2 简·多伊 janedoe@helloworld.com
 4 Foo 酒吧 foo@worldof.bar.net

编辑:
我不是要求一个适用于所有 3 个或更多 SQL 引擎的 SQL 语句。欢迎任何贡献。:)

4

13 回答 13

23

试试这个

查询(对于 Sql Server):

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
于 2009-11-28T06:43:57.523 回答
17

对于 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;
于 2009-11-28T04:22:18.077 回答
8

如果您希望此解决方案完全扩展,则不应尝试提取子列。随着表变得越来越大,每行函数的速度非常慢。

在这种情况下,正确的做法是将提取成本从select(经常发生的地方)转移到insert/update发生较少的地方(在大多数普通数据库中)。insert通过仅在和上产生成本update,您可以大大提高数据库的整体效率,因为这是您需要执行此操作的唯一时间点(即,这是数据更改的唯一时间)

为了实现这一点,请将电子邮件地址拆分为表中的两个不同列,email_user以及email_domain)。然后,您可以在插入/更新之前将其拆分到您的应用程序中,或者在数据库中使用触发器(或预先计算的列,如果您的 DBMS 支持它)来自动执行此操作。

然后你进行排序email_domain,当你想要完整的电子邮件地址时,你使用email_name|'@'|email_domain.

或者,您可以保留完整email列并使用触发器仅复制 中的域部分email_domain,然后您无需担心连接列以获取完整的电子邮件地址。

如果您知道自己在做什么,出于性能原因从 3NF 恢复是完全可以接受的。在这种情况下,两列中的数据不能仅仅因为触发器不允许而不同步。这是用磁盘空间(相对便宜)换取性能(我们总是想要更多)的好方法。

而且,如果你是那种根本不喜欢从 3NF 恢复的人,那么email_name/email_domain解决方案会解决这个问题。

这也是假设您只想处理表单的电子邮件地址a@b- 还有其他有效的电子邮件地址,但我不记得多年来在野外看到过它们中的任何一个。

于 2009-11-28T04:54:56.177 回答
4

对于 SQL Server,您可以将计算列添加到表中,并将域提取到单独的字段中。如果您将该列持久保存到表中,您可以像使用任何其他字段一样使用它,甚至在其上放置一个索引,以加快速度,如果您通过域名查询很多:

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

因此,现在您的表格将有一个附加列“DomainName”,其中包含您电子邮件地址中“@”符号之后的任何内容。

于 2009-11-28T08:11:01.723 回答
2

假设您确实必须满足 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

正如唐尼指出的那样,字符串操作函数是非标准的......这就是为什么你必须保持数据冗余!

我已将帐户和域添加到第三个查询中,因为我记得并非所有 DBMS 都会对不在所选字段中的字段的查询进行排序。

于 2009-11-28T04:24:35.050 回答
2

这将适用于 Oracle:

select id,name,email,substr(email,instr(email,'@',1)+1) as domain
from table1
order by domain asc
于 2009-11-28T10:24:03.957 回答
2

对于 postgres,查询是:

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

该值252是允许的最长域(因为电子邮件的最大长度254包括本地部分、@. 和域。

有关详细信息,请参阅此内容:有效电子邮件地址的最大长度是多少?

于 2016-02-24T14:29:50.667 回答
1

您将不得不使用文本操作函数来解析域。然后按新列排序。

于 2009-11-28T04:23:11.560 回答
1

MySQL,right()instr()的智能组合

SQL Server,right()patindex()

甲骨文、instr()substr()

而且,正如其他人所说,如果您的记录数相当高,则将您的电子邮件字段包装在 where 子句中的函数中,这样 RDBMS 就无法使用您在该列上可能拥有的任何索引。因此,您可能需要考虑创建一个包含域的计算列。

于 2009-11-28T04:27:55.997 回答
1

如果您有百万条记录,我建议您仅使用域名创建新列。

于 2009-11-28T04:28:26.177 回答
1

我的建议是(对于 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;
然后只需添加一个 WHERE ...

于 2015-04-14T13:31:51.630 回答
1

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
于 2016-06-19T10:24:06.627 回答
0

更聪明地工作而不是更努力地工作:

SELECT REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING(emails.email, POSITION('@' IN emails.email)+1)),'.',2)) FROM emails
于 2010-10-11T12:25:50.393 回答