使用DOMAIN名称片段对具有一列电子邮件地址的表进行排序的最短和/或最有效的SQL语句是什么?
这基本上忽略了电子邮件地址中“@”之前的内容并且不区分大小写。让我们忽略这个国际化的域名。
目标: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
修改
我不是要求一个可以在所有3个或更多SQL引擎上运行的SQL语句。欢迎任何贡献。 :)
答案 0 :(得分:19)
试试这个
查询(适用于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
输出:
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
答案 1 :(得分: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;
答案 2 :(得分: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
表单的电子邮件地址 - 还有其他有效的电子邮件地址,但我记不起在野外看到它们中的任何一个。
答案 3 :(得分:4)
对于SQL Server,您可以向表中添加计算列,并将域提取到单独的字段中。如果您将该列保留在表中,您可以像使用任何其他字段一样使用它,甚至可以在其上添加索引,以加快速度,如果您通过域名进行大量查询:
ALTER TABLE Table1
ADD DomainName AS
SUBSTRING(email, CHARINDEX('@', email)+1, 500) PERSISTED
所以现在你的表会有一个额外的列“DomainName”,它包含你电子邮件地址中“@”后面的任何内容。
答案 4 :(得分: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
正如donnie指出的那样,字符串操作函数是非标准的...这就是为什么你必须保持数据冗余!
我已经在第三个查询中添加了帐户和域,因为我联系回忆起并非所有DBMS都会对不在所选字段中的字段进行查询排序。
答案 5 :(得分:2)
对于postgres,查询是:
SELECT * FROM table
ORDER BY SUBSTRING(email,(position('@' in email) + 1),252)
值252
是允许的最长域名(因为,电子邮件的最大长度为254
,包括本地部分,@
和域。
答案 6 :(得分:1)
您将不得不使用文本操作函数来解析域。然后按新列排序。
答案 7 :(得分:1)
SQL Server,right()和patindex()
而且,正如其他人所说的那样,如果你有一个不错的记录计数,那么将你的电子邮件字段包装在where where子句中的函数中就可以使得RDBMS不能使用你在该列上可能拥有的任何索引。因此,您可能需要考虑创建一个包含域的计算列。
答案 8 :(得分:1)
如果您有百万条记录,我建议您创建仅包含域名的新列。
答案 9 :(得分:1)
这适用于Oracle:
select id,name,email,substr(email,instr(email,'@',1)+1) as domain
from table1
order by domain asc
答案 10 :(得分: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;

答案 11 :(得分: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
答案 12 :(得分:0)
更聪明地工作而不是更难:
SELECT REVERSE(SUBSTRING_INDEX(REVERSE(SUBSTRING(emails.email, POSITION('@' IN emails.email)+1)),'.',2)) FROM emails