SQL:按电子邮件域名排序
Posted
技术标签:
【中文标题】SQL:按电子邮件域名排序【英文标题】:SQL: Sorting By Email Domain Name 【发布时间】:2010-12-21 03:46:56 【问题描述】:根据域名片段对包含电子邮件地址列的表进行排序的最短和/或有效的 SQL 语句是什么?
这基本上忽略了电子邮件地址中“@”之前的任何内容并且不区分大小写。让我们忽略这个的国际化域名。
针对:mysql、MSSQL、Oracle
来自TABLE1
的样本数据
通过电子邮件订购SELECT * FROM TABLE1 ORDER BY EMAIL ASC
按域排序SELECT * FROM TABLE1 ORDER BY ?????? ASC
编辑: 我不是要求一个可以在所有 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
(在大多数普通数据库中) .通过仅在 insert
和 update
上产生成本,您可以大大提高数据库的整体效率,因为这是您需要这样做的唯一时间点(即,它是唯一的数据变化的时间)。
为了实现这一点,请将电子邮件地址拆分为表格中的两个不同列,email_user
和 email_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 使用邮件域名更新邮件域名