Domanda

Sto cercando di scrivere un metodo di ricerca per determinare un messaggio SMS da inviare a un utente in base ad alcuni parametri associati all'utente / al sistema. Avremo un messaggio predefinito che verrà utilizzato come ultima risorsa, ma ci sono diversi modi per sovrascrivere il messaggio con vari parametri. Ecco quello che ho finora per la query di ricerca - ci sono modi migliori per farlo? Forse una ricerca non è l'approccio giusto per questo?

Ecco la tabella di ricerca:

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                   
}

Ecco un esempio di come sarebbe la tabella:

   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'

Ecco la domanda che ho:

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
È stato utile?

Soluzione

Non sono sicuro di quale sia il modo migliore, ma ecco alcune alternative:

Un pensiero sarebbe quello di memorizzare uno schema con ogni regola, in questo modo:

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'

e quindi utilizza un test LIKE anziché tutti gli AND.

Un altro pensiero sarebbe quello di utilizzare OUTER JOINS.

O (suonando la risposta appena arrivata) per ASCIUGARE ulteriormente le cose scrivendo:

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)

Altri suggerimenti

Penso che sia un approccio valido, facile da estendere, l'intenzione è abbastanza chiara e puoi riordinare il sql procedendo come segue

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)
....

Quello che stai facendo ha senso e funziona. Se cerchi le migliori pratiche, non utilizzare " SELECT * " - elenca le colonne che stai selezionando.

Penso che progetterei il database in modo diverso, con una tabella TA che sarebbe (MSGID, Key, CTID, Message) e un'altra TB che memorizzerebbe (MSGID, ID, IDTYPE) dove ID rappresenterebbe CampID / DistId / DefaultId (indicato da IDTYPE), il cui PK dovrebbe essere (ID, IDTYPE, MSGID) in questo ordine. È possibile assegnare a IDTYPE un valore numerico che indica la priorità, con 0 per impostazione predefinita (e un ID corrispondente di 0). Tutte le colonne NON sono NULL.

Se capisco bene il tuo problema, il tuo input è composto da tre valori x, y e z (più uno 0 implicito nel mio caso), vuoi restituire il messaggio per il quale hai più corrispondenze e, nel caso di uguaglianza, ordinata da 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

dovrebbe restituire il "miglior messaggio" come prima riga e tutto ciò che devi aggiungere è un

top 1

quindi unisciti con l'altra tabella. È probabile che questo sia più veloce di una soluzione a una tabella, poiché la tabella TB contiene solo ID numerici e sarà piuttosto compatta e il join sarà istantaneo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top