2009-02-25 2 views
0

Я работаю над веб-приложением в социальной сети, и у меня возникла ситуация, когда мне нужно повторно отправить электронные письма с напоминанием пользователям, которые не активировали свои электронные письма. Проблема заключается в том, что когда я исследовал БД, я обнаружил, что много писем дублируются (по-видимому, не было никакой проверки на уникальность электронной почты. Поэтому мне нужно знать, как извлечь эти поля из db: имя пользователя, код активации электронной почты, так что я могу повторно отправить электронные письма активации, и для случая дублированных писем мне нужно вернуть только один из них (т. е. если у меня есть пользователь john с электронной почтой [email protected] и пользователем john1 с электронной почтой [email protected] тоже , я хочу получить только из этих johns независимо от john1 или two), поэтому я подумал о том, чтобы скомпоновать SQL-запрос (Group By Email). Дело в том, что я не могу выбрать другие поля, которые не находятся в разделе group by решение, которое у меня есть, это тот, который мне не нравится, я создал список и каждый раз, когда мне нужно отправить электронное письмо пользователю, итерации по всему списку, чтобы убедиться, что это письмо не существует, если его там нет, я отправляю его, а затем добавляю письмо в список. Что-то вроде следующего: if (! EmailIsInList (электронная почта)) { SendActivationEmail (email); AddEmailToList (электронная почта) } else {DoNotSend); }Работа вокруг группы по ограничению количества сообщений

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

+0

Можете ли вы описать структуру таблиц? Все поля (имя пользователя, код активации электронной почты, адрес электронной почты, флаг активации) в той же таблице или они находятся в отдельных таблицах (ex User table (UserId, UserName, Email, IsActivated) и таблица E-mail (EmailId, UserId, Date, Message))? –

+0

Вот структура таблиц. Таблица 1 пользователи: ID пользователя pk Email РегистрацияЗабыли пароль? Таблица 2 UserActivation: ID pk, UserID fk ссылки Пользователи (UserID), EmailActivated бит, Код эл. Почты. Теперь мне нужно, чтобы результирующий набор выглядел следующим образом: UserID - Email - EmailCode - UserName (без лишних сообщений электронной почты) – Galilyou

+0

Не знаете, почему это проблема. Слишком много писем, засоряющих вашу систему? Пользователи жалуются на электронные письма на счетах, которые они не хотят использовать? Вы хотите, чтобы учетная запись пользователя активировалась на основе ответа электронной почты. Кого волнует, если два пользователя делят учетную запись электронной почты? – JeffO

ответ

0

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

+0

, пожалуйста, прочитайте мой комментарий к вопросу, я описал структуру таблиц там! – Galilyou

1

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

DECLARE @User TABLE (UserId int, 
UserName varchar(100), Email varchar(40), IsActivated bit) 
INSERT INTO @User 
SELECT 1, 'John', '[email protected]', 0 UNION 
SELECT 2, 'Ann', '[email protected]', 0 UNION 
SELECT 3, 'John2', '[email protected]', 1 UNION 
SELECT 4, 'Bill', '[email protected]', 0 UNION 
SELECT 5, 'Bill', '[email protected]', 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 

Вы видите, мы [email protected] уже активировали один раз, так что нам не нужно его в наборе результатов.
Теперь реализация с 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

в принципе нет никакой разницы с решением, предоставленным Bliek в моей ссылке :), но при условии отсутствия потребности в мысли-решении :) –

+0

ну, реализация совсем иная - нет CTE, нет RowNumber. BTW, «кроссплатформенное» решение: D –

+0

Я имел в виду в основном :) Мне нравится это «кроссплатформенное» решение! –

0

Я думаю, что вы делаете большую логическую ошибку. Адрес электронной почты не является и никогда не будет уникальным. Просто потому, что у двух пользователей одинаковый адрес электронной почты НЕ означает, что они одни и те же люди! Люди часто обмениваются электронными письмами, у пар может быть один и тот же адрес электронной почты, у небольших офисов иногда есть только одно электронное письмо (это часто верно для кабинетов врачей). Письма также используются повторно, если кто-то его отказывается. Поэтому Джон Смит, который регистрируется в 2007 году с [email protected], может не быть активным в вашей системе и, таким образом, не стал менять свою электронную почту, когда отправился на [email protected] Тем временем Джуди Смит в другом государстве регистрирует [email protected] Вы не можете считать адрес электронной почты willever уникальным.

+0

Да, я получил вашу точку зрения, и это имеет большой смысл, и если бы я должен был перепроектировать БД, я бы так выразился. но я унаследовал этот проект от своего предшественника, и мне действительно нужно справиться с этой ситуацией. – Galilyou

Смежные вопросы