SQL中稀疏填充的查找表

时间:2009-03-16 05:41:43

标签: sql lookup

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

答案 0 :(得分: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)
....

答案 1 :(得分: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)

答案 2 :(得分:1)

你在做什么是有道理的,也是有效的。 如果您遵循最佳实践 - 请勿使用“SELECT *” - 枚举您选择的列。

答案 3 :(得分:0)

我想我会以不同的方式设计数据库,一个表TA将是(MSGID,Key,CTID,Message),另一个TB将存储(MSGID,ID,IDTYPE),其中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并且非常紧凑,并且连接将是即时的。