Малонаселенная таблица поиска в SQL
Вопрос
Я пытаюсь написать метод поиска для определения 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 содержит только числовые идентификаторы и будет довольно компактной, а объединение будет мгновенным.