SQL:按电子邮件域名排序

Posted

技术标签:

【中文标题】SQL:按电子邮件域名排序【英文标题】:SQL: Sorting By Email Domain Name 【发布时间】:2010-12-21 03:46:56 【问题描述】:

根据域名片段对包含电子邮件地址列的表进行排序的最短和/或有效的 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 语句。欢迎任何贡献。 :)

【问题讨论】:

请贴出你目前写的代码。人们通常不喜欢只为你写代码。 字符串操作函数是相当非标准化的。如果您能找到一个适用于所有 3 个查询的查询,我会感到惊讶。 @Mitch:如您所见,我添加了几个 os SQL 语句,非常简单,我没有一个用于我要问的语句。 :P 域名(和电子邮件)应该小写 - 因为域名(和互联网)不区分大小写,所以在捕获它们时将文本驱动为小写是没有风险的。但是域名从右到左解析 - 在@符号之前遇到的第二个句点表示子域,并且子域的数量没有限制。例如,foo@worldof.bar.net - worldof 是子域,bar 是域,net 是根。这是否会改变您期望的列表排序方式? 鉴于示例数据,电子邮件必须被分割成子字符串。但数据也是确定性的——它总是会返回相同的数据。这意味着您可以考虑使用物化视图(SQL Server 中的索引视图)将您需要的字符串与电子邮件地址分开,同时使用索引。不幸的是,在您列出的数据库中 - MySQL 尚不支持物化视图,Oracle 和 SQL Server 支持。 【参考方案1】:

试试这个

查询(对于 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

【讨论】:

等了几天才得到更多答案,似乎这是最完整的一个。在可扩展性和性能方面,我确实很欣赏其他替代方法和想法。确实是Wye开口。谢谢大家! 这个 Postgres 查询:select * from mytbl order by SUBSTRING(email,(position('@',email)+1),1) 对于 Sql Server,它看起来只会按域的第一个字母排序,所以我会调整如下:select * from mytbl order by SUBSTRING(email,(CHARINDEX('@',email)+1),LEN(email)-CHARINDEX('@', email)) pygorex1 已经回答了是的,我找不到它你应该添加一个链接或他的文字 + 他的名字不要让它变得复杂......【参考方案2】:

对于 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;

【讨论】:

SUBSTRING_INDEX 只是 MySQL。您需要 Google 搜索 Oracle 和 SQL Server 中的子字符串/字符串修改功能。不幸的是,这个 AFAIK 没有标准的 ANSI SQL 代码。 我就是这么想的。我想知道 o.k.w 是否意味着这 3 个 DBMS 是硬性要求? @lexu,pygorex1:不是硬性要求。我只是认为放 3 个受欢迎的可能会对其他人有所帮助。 pygorex1,+1 为您的答案:P 感谢您的 +1。这是一个不错的技巧 - 但请记住,您将在其自己的索引列中从单独的域中获得更快的性能。【参考方案3】:

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

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

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

然后您按email_domain 排序,如果您想要完整的电子邮件地址,请使用email_name|'@'|email_domain

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

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

而且,如果您根本不喜欢从 3NF 恢复,email_name/email_domain 解决方案将解决这个问题。

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

【讨论】:

【参考方案4】:

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

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

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

【讨论】:

【参考方案5】:

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

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

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

【讨论】:

【参考方案6】:

这将适用于 Oracle:

select id,name,email,substr(email,instr(email,'@',1)+1) as domain
from table1
order by domain asc

【讨论】:

【参考方案7】:

对于 postgres,查询是:

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

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

更多详情请参见:What is the maximum length of a valid email address?

【讨论】:

【参考方案8】:

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

【讨论】:

【参考方案9】:

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

SQL Server、right() 和 patindex()

甲骨文、instr() 和 substr()

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

【讨论】:

【参考方案10】:

如果你有百万条记录,我建议你只用域名创建新列。

【讨论】:

【参考方案11】:

我的建议是(对于 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 ...

【讨论】:

【参考方案12】:

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

【讨论】:

【参考方案13】:

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

SELECT REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING(emails.email, POSITION('@' IN emails.email)+1)),'.',2)) FROM emails

【讨论】:

调用 reverse 两次并不聪明。聪明(并且显而易见)是为本地部分和域名设置单独的列,以便数据库可以使用索引。

以上是关于SQL:按电子邮件域名排序的主要内容,如果未能解决你的问题,请参考以下文章

oracle sql cursor 使用邮件域名更新邮件域名

用于显示电子邮件列中域名总数的 SQL

删除电子邮件主题中的 [External] 标签,之后无法按主题排序

JavaScript 按发件人排序Gmail邮件

按主题对Gmail邮件排序

SQL - 按电子邮件和最新日期分组