1

我正在尝试编写一种查找方法,用于根据与用户/系统相关的一些参数来确定要发送给用户的 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
4

4 回答 4

2

我认为这是一种有效的方法,易于扩展,意图非常明确,您可以通过执行以下操作来整理 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)
....
于 2009-03-16T05:51:43.533 回答
1

我不确定最好的方法是什么,但这里有一些替代方法:

一种想法是为每个规则存储一个模式,如下所示:

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。

另一个想法是使用 OUTER JOINS。

或者(利用刚刚出现的答案)通过编写进一步干燥事情:

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)
于 2009-03-16T05:52:56.450 回答
1

你正在做的事情是有意义的,并且有效。如果您遵循最佳实践——不要使用“SELECT *”——枚举您选择的列。

于 2009-03-16T05:55:19.627 回答
0

我想我会以不同的方式设计数据库,一个表 TA 是(MSGID、Key、CTID、Message),另一个是存储(MSGID、ID、IDTYPE)的 TB,其中 ID 代表 CampID/DistId/ DefaultId(以IDTYPE表示),其PK应依次为(ID、IDTYPE、MSGID)。您可以为 IDTYPE 分配一个表示优先级的数值,默认值为 0(匹配 ID 为 0)。所有列都不为 NULL。

如果我很好理解您的问题,您的输入由三个值 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 仅包含数字 ID,并且非常紧凑,并且连接将是即时的。

于 2009-03-16T09:07:17.870 回答