围绕Group By Clause Limitation的工作

时间:2009-02-25 12:31:52

标签: asp.net sql sql-server aggregate

我正在开发一个社交网络网络应用程序,我遇到了需要向未激活其电子邮件的用户重新发送提醒电子邮件的情况。

问题是,当我调查数据库时,我发现许多电子邮件都是重复的(显然没有对电子邮件唯一性进行验证。所以我需要知道的是从数据库中检索这些字段的用户名,电子邮件激活码,电子邮件,以便我可以重新发送激活电子邮件,对于重复电子邮件的情况,我只需要返回其中一个(即如果我有用户john与电子邮件john@hotmail.com和用户john1与电子邮件john @ hotmail .com,我想只检索其中一个johns,无论john1还是两个)所以我想通过(Group By Email)跟踪SQL查询。

问题是我无法选择不在group by子句中的其他字段。我在这里的解决方案是我不喜欢的解决方案;我创建了一个List,每当我需要向用户发送电子邮件时,我会遍历整个列表以确保此电子邮件不存在,如果它不存在,我发送给它,然后将电子邮件添加到名单。
如下所示:

if(!EmailIsInList(email)){ 
  SendActivationEmail(email);
  AddEmailToList(email)
}
else { DoNotSend); }

其实我用这种方式解决了问题,仍然,我不喜欢我的解决方案。有什么想法吗?

3 个答案:

答案 0 :(得分:1)

收入测试数据:

DECLARE @User TABLE (UserId int, 
UserName varchar(100), Email varchar(40), IsActivated bit)
INSERT INTO @User
SELECT 1, 'John', 'john@hotmail.com', 0 UNION
SELECT 2, 'Ann', 'ann@hotmail.com', 0 UNION
SELECT 3, 'John2', 'john@hotmail.com', 1 UNION
SELECT 4, 'Bill', 'bill@hotmail.com', 0 UNION
SELECT 5, 'Bill', 'john@hotmail.com', 0

DECLARE @Email TABLE (EmailId int, 
UserId int, Date datetime, Message varchar(1000))
INSERT INTO @Email
SELECT 1, 1, GETDATE(), '' UNION
SELECT 2, 2, GETDATE(), '' UNION
SELECT 3, 3, GETDATE(), '' UNION
SELECT 4, 4, GETDATE(), '' UNION
SELECT 5, 5, GETDATE(), ''

SELECT * FROM @User
SELECT * FROM @Email

你知道,我们已经激活了john@hotmail.com一次,所以我们在结果集中不需要他 现在,使用RANK OVER实现:

SELECT M.UserID, M.UserName, M.Email, 
    M.IsActivated, M.EmailId, M.Date, M.Message 
FROM (
    SELECT RANK() OVER (PARTITION BY U.Email 
        ORDER BY U.IsActivated Desc, U.UserID ASC) AS N, 
        U.UserID, U.UserName, U.Email, U.IsActivated, 
        E.EmailId, E.Date, E.Message
    FROM @User U INNER JOIN @Email E ON U.UserID = E.UserID
)M WHERE M.N = 1 AND M.IsActivated = 0

答案 1 :(得分:0)

如果我们假设同一个电子邮件地址可以针对usera激活而不是针对userb激活,那么以下查询将为每个从未激活的电子邮件地址返回一个用户ID

SELECT  MAX(userid),
        email
FROM    users AS u1
WHERE   activated = 'False'
AND NOT EXISTS (
        SELECT 1
        FROM   users AS u2
        WHERE  u2.email = u1.email
        AND    u2.activated = 'True'
        )

GROUP BY email

您确实希望确保电子邮件字段已编入索引,如果使用唯一的复合键(email,userid)编制索引,那么这将是一个索引扫描,应该非常快。

答案 2 :(得分:0)

我认为你正在犯一个重大的逻辑错误。电子邮件地址不是也永远不会是唯一的。仅仅因为两个用户拥有相同的电子邮件地址并不意味着他们是同一个人!人们经常分享电子邮件,夫妻可能有同样的电子邮件,小型办公室有时只有一封电子邮件(这通常适用于医生的办公室。)如果有人放弃电子邮件,也会重复使用电子邮件。因此,2007年在jsmith@hotmail.com注册的约翰史密斯可能仍然没有在你的系统中活跃,所以当他去jsmith@gmail.com时没有费心去更改他的电子邮件。与此同时,Judy Smith在一个不同的州注册了jsmith@hotmail.com。您可以假设电子邮件地址willever是唯一的。