Вопрос

Я пытаюсь написать метод поиска для определения SMS-сообщения для отправки пользователю на основе нескольких параметров, связанных с пользователем / системой. У нас будет сообщение по умолчанию, которое будет использоваться в качестве крайней меры, но существует несколько способов переопределить сообщение различными параметрами. Вот что у меня есть для поискового запроса - есть ли лучшие способы сделать это? Может быть, поиск не подходит для этого?

Вот таблица соответствия:

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                   
}

Вот пример того, как будет выглядеть таблица:

   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'

Вот мой запрос:

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
Это было полезно?

Решение

Я не уверен, что лучший способ, но вот несколько альтернатив:

Одной из мыслей было бы сохранить шаблон с каждым правилом, например, так:

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'

, а затем используйте тест LIKE вместо всех AND.

Еще одна мысль - использовать ВНЕШНИЕ СОЕДИНЕНИЯ.

Или (обыгрывая ответ, который только что пришел), чтобы высушить вещи, написав:

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)

Другие советы

Я думаю, что это правильный подход, его легко расширить, намерение достаточно ясное, и вы можете привести в порядок sql, выполнив следующее

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

То, что вы делаете, имеет смысл и работает. Если вы придерживаетесь лучших практик - не используйте & Quot; SELECT * & Quot; - перечислить, какие столбцы вы выбираете.

Я думаю, что я бы разработал базу данных другим способом, с одной таблицей TA, которая будет (MSGID, Key, CTID, Message), и еще одним TB, который будет хранить (MSGID, ID, IDTYPE), где ID будет представлять CampID. / DistId / DefaultId (указывается IDTYPE), PK которого должен быть (ID, IDTYPE, MSGID) в этом порядке. Вы можете присвоить IDTYPE числовое значение, обозначающее приоритет, с 0 по умолчанию (и совпадающим идентификатором 0). Все столбцы НЕ НУЛЬЫ.

Если я хорошо понимаю вашу проблему, ваш ввод состоит из трех значений x, y и z (плюс неявный 0 в моем случае), вы хотите вернуть сообщение, для которого у вас больше всего совпадений, и, в случае, если равенства, порядок по 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

должен возвращать " лучшее сообщение " в качестве первой строки, и все, что вам нужно добавить, это

top 1

затем присоединитесь к другой таблице. Вероятно, это будет быстрее, чем решение с одной таблицей, поскольку таблица TB содержит только числовые идентификаторы и будет довольно компактной, а объединение будет мгновенным.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top