Работа вокруг ограничения по группам - PullRequest
0 голосов
/ 25 февраля 2009

Я работаю над веб-приложением в социальной сети, и у меня возникла ситуация, когда мне нужно повторно отправлять электронные письма-напоминания пользователям, которые не активировали свои электронные письма.

Проблема в том, что, когда я исследовал БД, я обнаружил, что многие электронные письма дублируются (очевидно, не было никакой проверки уникальности электронной почты. Поэтому мне нужно знать, что нужно извлечь из БД эти поля: имя пользователя, код активации электронной почты) по электронной почте, чтобы я мог повторно отправить письма активации, а в случае дублированных писем мне нужно вернуть только одно из них (т.е. если у меня есть пользователь john с электронной почтой john@hotmail.com и пользователь john1 с электронной почтой john @ hotmail Кроме того, я хочу получить только один из этих johns (неважно john1 или два), поэтому я подумал о настройке SQL-запроса по (Group By Email).

Дело в том, что я не могу выбрать другие поля, которые не входят в предложение group by. у меня есть решение, которое мне не нравится; Я создал список, и каждый раз, когда мне нужно отправить электронное письмо пользователю, я перебираю весь список, чтобы убедиться, что это электронное письмо не существует, если его нет, я отправляю его, а затем добавляю электронное письмо в список.
Примерно так:

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

На самом деле я решил проблему таким образом, но мне не нравится мое решение. Есть идеи?

Ответы [ 3 ]

1 голос
/ 25 февраля 2009

Данные тестирования дохода:

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
0 голосов
/ 25 февраля 2009

Я думаю, что вы делаете большую логическую ошибку. Адрес электронной почты не является и никогда не будет уникальным. Тот факт, что два пользователя имеют один и тот же адрес электронной почты, НЕ означает, что они являются одним и тем же человеком! Люди часто делятся электронной почтой, пары могут иметь одну и ту же электронную почту, небольшие офисы иногда имеют только одну электронную почту (это часто верно для кабинетов врача). Электронные письма также используются повторно, если кто-то отказывается от них. Таким образом, Джон Смит, который зарегистрировался в 2007 году по адресу jsmith@hotmail.com, возможно, все еще не активен в вашей системе и, таким образом, не удосужился изменить свою электронную почту, когда перешел на jsmith@gmail.com. Тем временем Джуди Смит в другом штате регистрируется jsmith@hotmail.com. Вы не можете предполагать, что адрес электронной почты будет уникальным.

0 голосов
/ 25 февраля 2009

Если мы предположим, что один и тот же адрес электронной почты может быть активирован как для пользователя usera, так и не активирован для пользователя userb, следующий запрос вернет вам один идентификатор пользователя для каждого адреса электронной почты, который никогда не был активирован

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), тогда это будет индексированное сканирование, и оно должно быть довольно быстрым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...