2009-03-16 6 views
1

J'essaie d'écrire une méthode de recherche pour déterminer un message SMS à envoyer à un utilisateur basé sur quelques paramètres associés à l'utilisateur/système. Nous aurons un message par défaut qui sera utilisé en dernier recours, mais il existe plusieurs façons de remplacer le message par divers paramètres. Voici ce que j'ai jusqu'à présent pour la requête de recherche - y at-il de meilleurs moyens de le faire? Peut-être qu'une recherche n'est pas la bonne approche pour cela?Table de recherche peu peuplée dans SQL

Voici la table de recherche:

MessageLookup 
{ 
ID bigint PK       
Key varchar       
CampaignTypeID bigint FK,    
ServiceProviderID bigint FK nullable, -- optional override parameter 
DistributorID bigint FK nullable,  -- optional override parameter 
CampaignID bigint FK nullable,  -- optional override parameter 
Message varchar     
} 

Voici un exemple de ce que la table ressemblerait à ceci:

ID Key CTID SPID DistID CampID Message 
    1 Help 1 NULL NULL NULL 'This is the default message' 
    2 Help 1 375 NULL NULL 'This is the SP375 message' 
    3 Help 1 377 NULL NULL 'This is the SP377 message' 
    4 Help 1 NULL 13  NULL 'This is the Dist13 message' 
    5 Help 1 375 13  NULL 'This is the SP375/Dist13 message' 
    6 Help 1 NULL 13  500 'This is the Dist13/Camp500 message' 
    7 Help 1 375 13  500 'This is the SP375/Dist13/Camp500 msg' 
    8 Help 1 NULL NULL 500 'This is the Camp500 help message' 

Voici la requête que j'ai:

select 
    --top 1 
    * 
from MessageLookup ml 
where ml.[Key] = @Key 
and ml.CampaignTypeID = @CampaignTypeID 
and 
(
    ml.ServiceProviderID = @ServiceProviderID or 
    ml.ServiceProviderID is null 
) 
and 
(
    ml.DistributorID = @DistributorID or 
    ml.DistributorID is null 
) 
and 
(
    ml.CampaignID = @CampaignID or 
    ml.CampaignID is null 
) 
order by 
    CampaignID desc, -- highest precedence lookup param 
    DistributorID desc, 
    ServiceProviderID desc -- lowest precedence lookup param 

Répondre

1

Je ne suis pas sûr de ce que la meilleure façon est, mais voici quelques alternatives:

Une pensée serait de stocker un modèle à chaque règle, comme suit:

ID Key CTID Rule  Message 
1 Help 1 '[%:%:%]' 'This is the default message' 
2 Help 1 '[375:%:%]' 'This is the SP375 message' 
3 Help 1 '[377:%:%]' 'This is the SP377 message' 
4 Help 1 '[%:13:%]' 'This is the Dist13 message' 
5 Help 1 '[375:13:%]' 'This is the SP375/Dist13 message' 

puis utilisez un test LIKE au lieu de tous les AND.

Une autre idée serait d'utiliser OUTER JOINS.

Ou (jouer la réponse qui vient à) DRY les choses plus en écrivant:

where ml.[Key] = @Key 
    and ml.CampaignTypeID = @CampaignTypeID 
    and IsNull(ml.ServiceProviderID = @ServiceProviderID,true) 
    and IsNull(ml.DistributorID  = @DistributorID, true) 
    and IsNull(ml.CampaignID  = @CampaignID,  true) 
+0

La colonne Règle est intéressante. Il pourrait fournir des moyens d'étendre la recherche dans le futur (en quelque sorte ...) Merci pour la réponse –

2

Je pense que c'est une approche valide, facile à étendre, l'intention est assez claire, et vous pouvez ranger le sql en faisant ce qui suit

select 
    --top 1 
    * 
from MessageLookup ml 
where ml.[Key] = @Key 
and ml.CampaignTypeID = @CampaignTypeID 
and ml.ServiceProviderID = IsNull(@ServiceProviderID, ml.ServiceProviderID) 
and ml.DistributorID = IsNull(@DistributorID, ml.DistributorID) 
and ml.CampaignID = IsNull(@CampaignID, ml.CampaignID) 
.... 
1

Ce que vous faites est logique, et travaille. Si vous êtes après les meilleures pratiques - ne pas utiliser "SELECT *" - énumérer les colonnes que vous sélectionnez.

+0

J'ai déjà entendu ça. S'agit-il principalement d'un problème de performance ou d'un moyen de vous protéger des changements futurs ou de quelque chose d'autre? –

+0

Il est à l'épreuve du temps (plus la lisibilité - il est beaucoup plus facile pour quelqu'un d'autre de comprendre votre intention). J'ai vu certaines catastrophes se produire à cause de choses comme un * étant utilisé sur une table que quelqu'un a recréé, avec des colonnes dans un ordre différent ... – SquareCog

+0

Cela peut être un problème de performance si vous avez des centaines de colonnes qui ne vous intéressent pas Cela peut également rendre moins clair les colonnes qui vous intéressent. –

0

Je pense que je concevrais la base de données d'une manière différente, avec une table TA qui serait (MSGID, Key, CTID, Message) et une autre TB qui stockerait (MSGID, ID, IDTYPE) où ID représenterait CampID/DistId/DefaultId (indiqué par IDTYPE), dont le PK doit être (ID, IDTYPE, MSGID) dans cet ordre. Vous pouvez attribuer à IDTYPE une valeur numérique indiquant la priorité, avec 0 pour la valeur par défaut (et un ID correspondant à 0). Toutes les colonnes ne sont pas NULL. Si je comprends bien votre problème, votre entrée est faite de trois valeurs x, y et z (plus un 0 implicite dans mon cas), vous voulez retourner le message pour lequel vous avez le plus de correspondances, et, dans cas d'égalité, ordre par IDTYPE.

select MSGID, count(*) as nbr_candidates, max(IDTYPE) as priority 
from TB 
where (ID = x and IDTYPE = ...) 
    or (ID = y and IDTYPE = ...) 
    or (ID = z and IDTYPE = ...) 
    or (ID = 0 and IDTYPE = 0) 
group by MSGID 
order by 2 desc, 3 desc 

doit retourner le « meilleur message » comme première ligne, et tout ce que vous devez ajouter est un

top 1 

puis se joignent à l'autre table. Ceci est susceptible d'être plus rapide qu'une solution à table unique, car la table TB ne contient que des identifiants numériques et sera très compacte, et la jointure sera instantanée.