Pregunta

Estoy tratando de escribir un método de búsqueda para determinar un mensaje SMS para enviar a un usuario en función de algunos parámetros asociados con el usuario / sistema. Tendremos un mensaje predeterminado que se utilizará como último recurso, pero hay varias formas de anular el mensaje mediante varios parámetros. Esto es lo que tengo hasta ahora para la consulta de búsqueda: ¿hay alguna forma mejor de hacer esto? ¿Quizás una búsqueda no es el enfoque correcto para esto?

Aquí está la tabla de búsqueda:

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                   
}

Aquí hay un ejemplo de cómo se vería la tabla:

   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'

Aquí está la consulta que tengo:

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
¿Fue útil?

Solución

No estoy seguro de cuál es la mejor manera, pero aquí hay algunas alternativas:

Un pensamiento sería almacenar un patrón con cada regla, así:

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'

y luego use una prueba LIKE en lugar de todos los AND.

Otra idea sería utilizar OUTER JOINS.

O (reproduciendo la respuesta que acaba de llegar) para SECAR aún más las cosas escribiendo:

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)

Otros consejos

Creo que es un enfoque válido, fácil de extender, la intención es bastante clara, y puede ordenar el sql haciendo lo siguiente

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

Lo que estás haciendo tiene sentido y funciona. Si persigue las mejores prácticas, no use " SELECT * " - enumere qué columnas está seleccionando.

Creo que diseñaría la base de datos de una manera diferente, con una tabla TA que sería (MSGID, Clave, CTID, Mensaje) y otra TB que almacenaría (MSGID, ID, IDTYPE) donde ID representaría CampID / DistId / DefaultId (indicado por IDTYPE), cuyo PK debe ser (ID, IDTYPE, MSGID) en este orden. Puede asignar a IDTYPE un valor numérico que indique prioridad, con 0 para el valor predeterminado (y una ID coincidente de 0). Todas las columnas NO SON NULAS.

Si entiendo bien su problema, su entrada se compone de tres valores x, y y z (más un 0 implícito en mi caso), desea devolver el mensaje para el que tiene la mayor cantidad de coincidencias y, en caso de igualdad, ordenado 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

debería devolver el " mejor mensaje " como su primera fila, y todo lo que necesita agregar es un

top 1

luego únete a la otra tabla. Es probable que esto sea más rápido que una solución de una tabla, porque la tabla TB solo contiene ID numéricos y será bastante compacta, y la unión será instantánea.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top