Aktualisieren einer WHERE-Klausel, um zu überprüfen, ob sich ein Wert NICHT in einer separaten Tabelle befindet

8

Ich habe eine Abfrage, die eine WHEREKlausel verwendet, und ich verwende zufällig genau dieselbe WHEREKlausel in vielen Abfragen in dieser Tabelle (et al.).

Die Abfrage lautet:

SELECT
    DATENAME(DW, [AtDateTime]) AS [Day of Week]
    ,COUNT(*) AS [Number of Searches]
    ,CAST(CAST(COUNT(*) AS DECIMAL(10, 2)) 
         / COUNT(DISTINCT CONVERT(DATE, [AtDateTime])) AS DECIMAL(10, 2)) 
       AS [Average Searches per Day]
    ,SUM(CASE WHEN [NumFound] = 0 THEN 1 ELSE 0 END) 
       AS [Number of Searches with no Results]
    ,CAST(CAST(SUM(CASE WHEN [NumFound] = 0 THEN 1 ELSE 0 END) 
         AS DECIMAL(10, 2)) / COUNT(*) AS DECIMAL(10, 4)) 
       AS [Percent of Searches with no Results]
FROM [DB].[dbo].[SearchHistory] 
WHERE 
    [CustomerNumber] <> '1234' AND [CustomerNumber] <> '5678'
GROUP BY DATENAME(DW, [AtDateTime]), DATEPART(DW, [AtDateTime])
ORDER BY DATEPART(DW, [AtDateTime])

Der Teil, den ich ändern möchte, ist die WHEREKlausel, mit der ich stattdessen eine Tabelle verwenden kann, sodass ich nicht alle meine Abfragen aktualisieren muss, wenn ich eine Kundennummer hinzufügen muss, die ignoriert werden soll. (Und es gibt einige Abfragen, die dieselbe WHEREKlausel haben.)

Der Kommissar
quelle
Wenn die Kundenausschlüsse derzeit spezifisch für die Abfrageausführung sind, warum sollte das Verschieben in eine gemeinsam genutzte Tabelle / Arbeitstabelle keine falsche Freigabe einführen? In einer normalen Anwendung sind Kunden normalerweise willkürlich und somit spezifisch für eine einzelne Abfrageausführung. Ich würde vorschlagen, dass bei dieser Frage entweder wichtige Fakten zur Allgemeinheit weggelassen werden, die für das ordnungsgemäße Funktionieren der Lösung erforderlich sind, oder das Problem des Teilens übersehen wird.
Thomas W
@ThomasW - was ist das für ein "falsches Teilen", von dem du sprichst? Haben Sie eine Referenz dafür? Ich habe noch nie davon gehört.
Max Vernon
1
@ThomasW Voraussetzung dafür ist, dass bestimmte Kunden, die wir haben (die wir häufig zum Testen verwenden), aus bestimmten Berichten ausgeschlossen werden müssen, da sie die Ergebnisse verzerren.
Der Kommissar
1
@ MaxVernon - vielleicht wäre ein besser erkannter Begriff "falscher Geltungsbereich". Was beschrieben wurde, bestand darin, eine Eingabe von einem völlig unabhängigen Parameter in eine benutzerübergreifende, aufrufübergreifende gemeinsam genutzte DB-Tabelle zu ändern. Diese Änderung überschreitet zwei Bereichsgrenzen. In Anbetracht des zusätzlichen Kontextes scheint der beschriebene Bereich in Ordnung zu sein, aber wenn dies nicht der Fall wäre, würde sich dies als "fehlerhaftes Teilen" manifestieren.
Thomas W
1
Der beschriebene Ansatz erinnerte auch an eine ganze Reihe von Legacy-Work-Table-Implementierungen (~ 1000 Tabellen) in einer Hauptanwendung, für die ich verantwortlich bin. In diesem Zusammenhang habe ich die mögliche "Arbeitstisch" -Natur als Frage aufgeworfen :) Danke.
Thomas W

Antworten:

5

Erstellen Sie eine Tabelle, in der die auszuschließenden Kundennummern enthalten sind, und schließen Sie diese Zeilen dann mit a NOT EXISTSin der WHEREKlausel aus.

CREATE TABLE dbo.ExcludedCustomers
(
    CustomerNumber VARCHAR(255) NOT NULL
        CONSTRAINT PK_ExcludedCustomers
        PRIMARY KEY CLUSTERED
);

INSERT INTO dbo.ExcludedCustomers (CustomerNumber)
VALUES ('1234')
    , ('5678');


SELECT
    <....>
FROM [DB].[dbo].[SearchHistory] 
WHERE 
    NOT EXISTS (
        SELECT 1
        FROM dbo.ExcludedCustomers ec
        WHERE ec.CustomerNumber = SearchHistory.CustomerNumber
    )
    <...>;
Max Vernon
quelle
7
CREATE TABLE dbo.CustomerExclusions
(
  CustomerNumber VARCHAR(32) PRIMARY KEY -- Is CustomerNumber *really* a string?
);

INSERT dbo.CustomerExclusions(CustomerNumber) VALUES('1234'),('5678');

Jetzt wird Ihre WHEREKlausel über alle Abfragen hinweg:

WHERE NOT EXISTS 
(
  SELECT 1 FROM dbo.CustomerExclusions AS c
  WHERE c.CustomerNumber = SearchHistory.CustomerNumber
)
Aaron Bertrand
quelle
Ja, leider. Kundennummern müssen eine Zeichenfolge sein, um die Kompatibilität mit dem AS / 400 zu gewährleisten. (Zumindest für den Moment arbeiten wir an einer Lösung dafür.)
Der Kommissar
3
@EBrown Äh, ugh.
Aaron Bertrand
-3

Es gibt wichtige Fragen / mögliche Probleme mit Ihrem vorgeschlagenen Ansatz. Natürlich können Sie über eine Arbeitstabelle zum Ausschluss von Kundennummern einfach genug ausschließen:

WHERE NOT EXISTS (
  SELECT 1 FROM [dbo].Work_ExcludeCustomer
  WHERE CustomerNumber = SearchHistory.CustomerNumber
)

Was nun "Abfrageparameter" waren - vollständig dynamisch und unabhängig, pro Abfrage und pro Benutzer - wird nun zu einem "gemeinsam genutzten persistenten Status in der Datenbank".

Einige Fragen und relevante Punkte:

  1. Sollten die Kundenausschlussinformationen separat sein, pro Benutzer oder pro Sitzung? Sie können einen 'SessionID'-Parameter hinzufügen, um diese zu unterscheiden, aber im Wesentlichen erstellen Sie ein altes "Arbeitstabellen" -Muster neu.

  2. Vielleicht könnte eine NOT IN (...) Klausel vorzuziehen sein? das kann dynamisch bis zur Grenze von 2100 Parametern parametriert werden.

  3. Besuchen Sie möglicherweise Ihren Code / Ihre Infrastruktur erneut, um Abfragen und Bindungsparameter zu erstellen, wenn Sie sich derzeit auf feste Parameternummern verlassen. Durch diese Verbesserung wird die Modularität und Verwendung von IN- oder NOT IN-Klauseln (?,?,? ..) mit variabler Anzahl von Parametern ermöglicht.

Vorgeschlagener Ansatz:

WHERE [CustomerNumber] NOT IN (?, ?, ?)

Mit Bindungen '1234', '5678', '6789' usw. an die NOT IN () -Parameter und nachfolgenden logischen Abfrageparametern, die dynamisch an die entsprechende Nummerierung gebunden sind.

Thomas W.
quelle
1
Die Verwendung von NOT IN (...) und / oder das dynamische Erstellen von Abfragetext ist ein Anti-Pattern und führt zu einer geringeren Leistung als die von Aaron und mir empfohlenen satzbasierten Ansätze.
Max Vernon
Lesen Sie diesen Beitrag , um die Unterschiede zu lesen .
Max Vernon
@MaxVernon - Das Ersetzen dynamischer Parameter durch "gemeinsam genutzte" Daten oder Arbeitstabellen kann zu einer falschen Freigabe führen, was weitaus eher ein Anti-Pattern ist. Da niemand anderes ausdrücklich in Betracht gezogen oder festgestellt hat, dass dies kein Problem ist, ist es absolut berechtigt, dieses Anliegen zur Sprache zu bringen. es sollte auch nicht trivial herabgestimmt werden.
Thomas W