2009-02-25 10 views
0

Je travaille sur une application web de réseau social, et j'ai eu une situation où j'ai besoin de renvoyer des e-mails de rappel aux utilisateurs qui n'ont pas activé leurs e-mails. Le problème est que lorsque j'ai enquêté sur la base de données j'ai trouvé que beaucoup de courriels sont dupliqués (il n'y avait apparemment aucune validation sur l'unicité de l'e-mail.) Ce que je dois faire est de récupérer ces champs pour que je puisse renvoyer les e-mails d'activation, et dans le cas des e-mails dupliqués, je dois retourner seulement l'un d'entre eux (ie si j'ai l'utilisateur john avec email [email protected] et l'utilisateur john1 avec email [email protected] aussi , je veux récupérer seulement sur ces johns peu importe john1 ou deux) donc j'ai pensé à suivre la requête SQL par (Grouper par Email). Le fait est que je ne peux pas sélectionner d'autres champs qui ne sont pas dans la clause group by la solution que j'ai ici est celle que je n'aime pas, j'ai créé une liste et chaque fois que j'ai besoin d'envoyer un email à un utilisateur je itère sur toute la liste pour m'assurer que cet email n'existe pas, si ce n'est pas le cas, je l'envoie, puis j'ajoute l'email à la liste, quelque chose comme: if (! EmailIsInList (email)) { SendActivationEmail (email); AddEmailToList (courrier électronique) } else {DoNotSend); }Un travail autour de la limitation de groupe par clause

En fait, j'ai résolu le problème de cette façon, mais je n'aime pas ma solution. Des idées?

+0

Pouvez-vous décrire la structure des tables? Tous les champs (nom d'utilisateur, code d'activation email, email, drapeau d'activation) se trouvent dans la même table ou dans des tables séparées (ex UserId, UserId, Email, IsActivated) et Email table (EmailId, UserId, Date, Message))? –

+0

Voici la structure des tables. Utilisateurs du tableau 1: UserID pk E-mail RegisterDate. Tableau 2 UserActivation: ID pk, ID utilisateur Références fk Utilisateurs (ID utilisateur), EmailModèle activé, Code de courrier électronique. Maintenant, j'ai besoin de l'ensemble de résultats pour être comme suit UserID - Email - EmailCode - UserName (sans e-mails redondants) – Galilyou

+0

Vous ne savez pas pourquoi c'est un problème. Trop de courriels obstruant votre système? Les utilisateurs se plaignent des courriels sur les comptes qu'ils ne veulent pas utiliser? Vous souhaitez que le compte d'utilisateur soit activé en fonction d'une réponse par e-mail. Qui se soucie si deux utilisateurs partagent un compte de messagerie? – JeffO

Répondre

0

Si nous supposons que la même adresse e-mail pourrait être à la fois activé contre usera et non activé contre UtilisateurB alors la requête suivante vous retourner un code d'utilisateur pour chaque adresse e-mail qui n'a jamais été activé

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 

Vous avez vraiment Je veux m'assurer que le champ email est indexé, et s'il a été indexé avec une clé composite unique de (email, userid) alors ce serait un scan indexé et devrait être assez rapide.

+0

s'il vous plaît lire mon commentaire sur la question, j'ai décrit la structure des tables là-bas! – Galilyou

1

données de test sur le revenu:

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 

Vous voyez, nous avons [email protected] déjà activé une fois, donc nous ne l'ont pas besoin dans le jeu de résultats.
Maintenant, la mise en œuvre avec RANG SUR:

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

il n'y a fondamentalement aucune différence à la solution fournie par Bliek dans mon lien :) mais fourni une solution sans nécessité de penser :) –

+0

bien, l'implémentation est assez différente - pas de CTE, pas de RowNumber. BTW, "crossplatform" solution: D –

+0

je voulais dire fondamentalement :) j'aime cette solution "crossplatform"! –

0

Je pense que vous faites une erreur logique majeure. L'adresse e-mail n'est pas et ne sera jamais unique. Juste parce que deux utilisateurs ont la même adresse email ne signifie pas qu'ils sont la même personne! Les gens partagent souvent des courriels, les couples peuvent avoir le même courriel, les petits bureaux ont parfois un seul courriel (c'est souvent le cas pour les cabinets de médecins). Les courriels sont également réutilisés si quelqu'un y renonce. Donc, John Smith qui s'inscrit en 2007 avec [email protected] n'est peut-être pas encore actif dans votre système et n'a donc pas pris la peine de changer son email quand il est allé à [email protected] En attendant, Judy Smith dans un état differnt enregistre [email protected] Vous ne pouvez pas supposer qu'une adresse e-mail soit unique.

+0

Ouais, j'ai compris, et cela a beaucoup de sens et si je devais redessiner la DB, je l'aurais dit de cette façon. mais j'ai hérité ce design de mon prédécesseur et j'ai vraiment besoin de gérer cette situation. – Galilyou

Questions connexes