質問
ユーザー/システムに関連付けられたいくつかのパラメーターに基づいて、ユーザーに送信する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'
そしてすべてのANDの代わりにLIKEテストを使用します。
もう1つの考えは、外部結合を使用することです。
または(入ったばかりの答えを再生します)次のように書いてさらにDRYします:
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;を使用しないでください。 -選択している列を列挙します。
別の方法でデータベースを設計すると思います。1つのテーブルTAは(MSGID、キー、CTID、メッセージ)で、もう1つのTBはIDがCampIDを表す場所(MSGID、ID、IDTYPE)になります/ DistId / DefaultId(IDTYPEで示されます)。PKはこの順序で(ID、IDTYPE、MSGID)になります。 IDTYPEには、優先順位を示す数値を割り当てることができます。デフォルトは0(および一致するIDは0)です。すべての列はNOT NULLです。
問題をよく理解している場合、入力はx、y、zの3つの値(この場合は暗黙的な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
<!> quot; best message <!> quot;を返す必要があります。最初の行として追加する必要があるのは
だけですtop 1
次に、他のテーブルと結合します。テーブルTBは数値IDのみを含み、非常にコンパクトであり、結合は即座に行われるため、これは1つのテーブルのソリューションよりも高速である可能性があります。