Pergunta

Eu estou tentando escrever um método de pesquisa para determinar uma mensagem SMS para enviar para um usuário com base em alguns parâmetros associados com o usuário / sistema. Teremos uma mensagem padrão que será usado como um último recurso, mas existem várias maneiras de substituir a mensagem por vários parâmetros. Aqui está o que eu tenho até agora para a consulta de pesquisa - existem melhores maneiras de fazer isso? Talvez uma pesquisa não é a abordagem correta para isso?

Aqui está a tabela de referência:

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                   
}

Aqui está um exemplo do que a mesa seria parecido com:

   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'

Aqui está a consulta que tenho:

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
Foi útil?

Solução

Eu não tenho certeza que a melhor maneira é, mas aqui estão algumas alternativas:

Um pensamento seria para armazenar um padrão com cada regra, assim:

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, em seguida, usar um teste como em vez de todas as ANDs.

Outro pensamento seria usar junções externas.

Or (jogando fora a resposta que acabou de chegar) para secar as coisas mais escrevendo:

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)

Outras dicas

Eu acho que é uma abordagem válida, fácil de estender, a intenção é muito clara, e você pode arrumar o sql fazendo o seguinte

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

O que você está fazendo faz sentido, e obras. Se você é depois de melhores práticas - não usar "SELECT *" -. Enumerar as colunas que você está selecionando

Eu acho que eu iria projetar o banco de dados de uma forma diferente, com uma mesa TA que seria (MSGID, Key, CTID, Mensagem) e outra TB que iria armazenar (MSGID, ID, idtype), onde ID representaria CampID / DistId / DefaultId (indicado por idtype), a PK dos quais deve ser (ID, idtype, MSGID), por esta ordem. Você pode atribuir a idtype um valor numérico que indica a prioridade, com 0 para o padrão (e uma ID correspondente de 0). Todas as colunas não são NULL.

Se eu entendi bem o seu problema, sua entrada é feita de três valores x, yez (mais um implícito 0 no meu caso), você quer retornar a mensagem para o qual tem o maior número de partidas, e, no caso da igualdade, ordem por 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

deve retornar o "melhor mensagem" como sua primeira linha, e tudo que você precisa fazer é adicionar um

top 1

, em seguida, juntar-se com a outra mesa. Este é provável que seja mais rápido do que uma solução one-mesa, porque a tabela TB contém apenas IDs numéricos e será bastante compacto, e a junção será instantânea.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top