SQL中填充稀疏的查找表

SQL中填充稀疏的查找表,sql,lookup,Sql,Lookup,我正在尝试编写一个查找方法,用于根据与用户/系统相关的几个参数确定要发送给用户的SMS消息。我们将使用默认消息作为最后手段,但是有多种方法可以通过各种参数覆盖消息。以下是我到目前为止对查找查询的了解——有没有更好的方法?也许查找不是解决这个问题的正确方法 以下是查找表: MessageLookup { ID bigint PK Key varchar CampaignTypeID bigin

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

我认为这是一种有效的方法,易于扩展,目的非常明确,您可以通过执行以下操作来整理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)
....

我认为这是一种有效的方法,易于扩展,目的非常明确,您可以通过执行以下操作来整理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)
....

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

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

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'
然后使用一个类似的测试,而不是所有的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)

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

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

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'
然后使用一个类似的测试,而不是所有的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)

你所做的是有意义的,并且有效的。
如果您在追求最佳实践--不要使用“选择*”--请列举您正在选择的列。

您所做的一切都是有意义的,并且是有效的。
如果您追求最佳实践--不要使用“SELECT*”--列举您正在选择的列。

我想我应该以不同的方式设计数据库,一个表TA是(MSGID、Key、CTID、Message),另一个表TB是存储(MSGID、ID、IDTYPE),其中ID表示CampID/DistId/DefaultId(由IDTYPE表示),其主键应按此顺序为(ID、IDTYPE、MSGID)。您可以为IDTYPE指定一个指示优先级的数值,默认值为0(匹配的ID为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
应该返回“best message”作为第一行,您只需要添加一个

top 1

然后加入另一个表。这可能比单表解决方案快,因为表TB只包含数字ID,而且非常紧凑,连接将是即时的。

我想我应该以不同的方式设计数据库,一个表TA是(MSGID、Key、CTID、Message),另一个表TB是存储(MSGID、ID、IDTYPE)其中ID表示CampID/DistId/DefaultId(由IDTYPE表示),其主键按此顺序应为(ID,IDTYPE,MSGID)。您可以为IDTYPE指定一个指示优先级的数值,默认值为0(匹配的ID为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
应该返回“best message”作为第一行,您只需要添加一个

top 1

然后加入另一个表。这可能比单表解决方案快,因为表TB只包含数字ID,而且非常紧凑,并且连接将是即时的。

规则列很有趣。它可能提供了将来扩展查找的方法(不知何故…)感谢您的回答规则栏很有趣。它可能会在将来提供扩展查找的方法(不知何故…)谢谢你的回答,我以前听说过。它主要是一种性能问题,还是一种保护自己不受未来变化影响的方法,还是其他什么?它是未来的证明(加上可读性——其他人更容易理解您的意图)。我见过一些灾难发生的原因,比如有人在重新创建的表上使用*之类的东西,列的顺序不同……如果您有数百个不感兴趣的列,这可能会影响性能。这也会让你不太清楚你感兴趣的专栏是什么。我假设您使用*是因为您实际上对所有列都感兴趣。在一般情况下,你可以通过明确列出你想要的东西来节省很多钱。我以前听说过。它主要是一种性能问题,还是一种保护自己不受未来变化影响的方法,还是其他什么?它是未来的证明(加上可读性——其他人更容易理解您的意图)。我见过一些灾难发生的原因,比如有人在重新创建的表上使用*之类的东西,列的顺序不同……如果您有数百个不感兴趣的列,这可能会影响性能。这也会让你不太清楚你感兴趣的专栏是什么。我假设您使用*是因为您实际上对所有列都感兴趣。在一般情况下,通过明确列出所需内容,您可以获得显著的节约。