Dünn besiedelte Lookup-Tabelle in SQL
Frage
Ich versuche zur Bestimmung einer SMS-Nachricht einer Lookup-Methode zu schreiben, um einen Benutzer auf wenigen Parametern mit dem Benutzer / System zugeordnet Basis zu senden. Wir werden eine Standardnachricht, die als letztes Mittel eingesetzt werden, aber es gibt mehr Möglichkeiten, um die Nachricht durch verschiedene Parameter außer Kraft zu setzen. Hier ist, was ich bisher für die Suche Abfrage habe - ist es bessere Möglichkeiten, dies zu tun? Vielleicht ein Nachschlag ist nicht der richtige Ansatz für das?
Hier ist die Lookup-Tabelle:
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
}
Hier ist ein Beispiel dafür, was die Tabelle aussehen würde:
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'
Hier ist die Abfrage ich habe:
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
Lösung
Ich bin mir nicht sicher, was der beste Weg ist, aber hier sind einige Alternativen:
Ein Gedanke wäre ein Muster zu speichern, mit jeder Regel, etwa so:
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'
und dann einen LIKE-Test anstelle allen ANDs.
Ein anderer Gedanke wäre die Verwendung von Outer-Joins.
oder (Ausspielen die Antwort, die gerade hereinkam) Dinge vertrocknen weiter durch Schreiben:
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)
Andere Tipps
Ich denke, das ist ein gültiger Ansatz, einfach zu erweitern, Absicht ziemlich klar ist, und Sie können die SQL ordentlich, indem Sie die folgenden
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)
....
Was Sie tun, macht Sinn, und arbeitet. Wenn Sie nach Best Practices sind - nicht „SELECT *“ verwenden -. Aufzuzählen, welche Spalten Sie die Auswahl
Ich glaube, ich würde die Datenbank in einer anderen Art und Weise entwerfen, mit einem Tisch TA das wäre (MSGID, Schlüssel, CTID, Message) und eine weitere TB, die gespeichert werden sollten (MSGID, ID, IDTYPE) wobei ID darstellen würde Campid / DISTID / DefaultId (durch IDTYPE angegeben), sollte die PK von denen (ID, IDTYPE, MSGID) in dieser Reihenfolge sein. Sie können einen numerischen Wert zuzuweisen, um IDTYPE die Priorität, mit 0 für den Standard anzeigt (und einer passenden ID von 0). Alle Spalten sind NOT NULL.
Wenn ich gut Ihr Problem zu verstehen, wird Ihre Eingabe von drei Werten x gemacht, y und z (plus eine implizite 0 in meinem Fall), den Sie die Nachricht zurück, für die die meisten Spiele haben, und für den Fall, die Gleichheit, um durch 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
sollte die „beste Nachricht“ als erste Zeile zurückgeben, und alles, was Sie brauchen, ist ein
top 1
dann mit der anderen Tabelle verbinden. Dies ist wahrscheinlich schneller sein als eine Ein-Tisch-Lösung, weil Tabelle TB nur numerisches IDs enthält und sehr kompakt sein, und die Verbindung wird sofort sein.