Sie würden keine Anwendung mit Funktionen schreiben, die 200 Zeilen lang sind. Sie würden diese langen Funktionen in kleinere Funktionen mit jeweils einer klar definierten Verantwortung zerlegen.
Warum schreiben Sie Ihre SQL so?
Zerlegen Sie Ihre Abfragen genauso wie Sie Ihre Funktionen zerlegen. Dies macht sie kürzer, einfacher, leichter zu verstehen, leichter zu testen und leichter umzugestalten. Und es ermöglicht Ihnen, "Shims" zwischen ihnen und "Wrapper" um sie herum hinzuzufügen, genau wie Sie es im Prozedurcode tun.
Wie machst Du das? Indem jede Abfrage in eine Ansicht umgewandelt wird. Dann komponieren Sie komplexere Abfragen aus diesen einfacheren Ansichten, genauso wie Sie komplexere Funktionen aus primitiveren Funktionen komponieren.
Und das Tolle ist, dass Sie bei den meisten Kompositionen von Ansichten mit Ihrem RDBMS genau die gleiche Leistung erzielen. (Für einige wird das nicht der Fall sein. Na und? Vorzeitige Optimierung ist die Wurzel allen Übels. Zuerst richtig codieren, dann bei Bedarf optimieren.)
Hier ist ein Beispiel für die Verwendung mehrerer Ansichten zum Zerlegen einer komplizierten Abfrage.
Da in jedem Beispiel nur eine Transformation hinzugefügt wird, kann jede unabhängig getestet werden, um Fehler zu finden, und die Tests sind einfach.
Hier ist die Basistabelle im Beispiel:
create table month_value(
eid int not null, month int, year int, value int );
Diese Tabelle ist fehlerhaft, da sie zwei Spalten, Monat und Jahr, verwendet, um ein Datum, einen absoluten Monat, darzustellen. Hier ist unsere Spezifikation für die neue, berechnete Spalte:
Wir machen das als lineare Transformation, so dass es das gleiche wie (Jahr, Monat) sortiert und dass für jedes (Jahr, Monat) Tupel ein und nur ein Wert vorhanden ist und alle Werte aufeinander folgen:
create view cm_absolute_month as
select *, year * 12 + month as absolute_month from month_value;
Was wir jetzt testen müssen, ist unserer Spezifikation inhärent, nämlich dass es für jedes Tupel (Jahr, Monat) ein und nur ein (absolutes_Monat) gibt und dass (absolutes_Monat) aufeinanderfolgend sind. Lassen Sie uns einige Tests schreiben.
Unser Test wird eine SQL- select
Abfrage mit der folgenden Struktur sein: ein Testname und eine zusammen verkettete case-Anweisung. Der Testname ist nur eine beliebige Zeichenfolge. Die case-Anweisung ist nur eine case when
Testanweisung then 'passed' else 'failed' end
.
Die Testanweisungen sind nur SQL-Auswahlen (Unterabfragen), die wahr sein müssen, damit der Test bestanden wird.
Hier ist unser erster Test:
--a select statement that catenates the test name and the case statement
select concat(
-- the test name
'For every (year, month) there is one and only one (absolute_month): ',
-- the case statement
case when
-- one or more subqueries
-- in this case, an expected value and an actual value
-- that must be equal for the test to pass
( select count(distinct year, month) from month_value)
--expected value,
= ( select count(distinct absolute_month) from cm_absolute_month)
-- actual value
-- the then and else branches of the case statement
then 'passed' else 'failed' end
-- close the concat function and terminate the query
);
-- test result.
Das Ausführen dieser Abfrage führt zu folgendem Ergebnis: For every (year, month) there is one and only one (absolute_month): passed
Solange in month_value genügend Testdaten vorhanden sind, funktioniert dieser Test.
Wir können auch einen Test für ausreichende Testdaten hinzufügen:
select concat( 'Sufficient and sufficiently varied month_value test data: ',
case when
( select count(distinct year, month) from month_value) > 10
and ( select count(distinct year) from month_value) > 3
and ... more tests
then 'passed' else 'failed' end );
Testen wir nun, ob es aufeinanderfolgend ist:
select concat( '(absolute_month)s are consecutive: ',
case when ( select count(*) from cm_absolute_month a join cm_absolute_month b
on ( (a.month + 1 = b.month and a.year = b.year)
or (a.month = 12 and b.month = 1 and a.year + 1 = b.year) )
where a.absolute_month + 1 <> b.absolute_month ) = 0
then 'passed' else 'failed' end );
Lassen Sie uns nun unsere Tests, bei denen es sich nur um Abfragen handelt, in eine Datei einfügen und das Skript für die Datenbank ausführen. Wenn wir unsere Ansichtsdefinitionen in einem Skript (oder in Skripten, ich empfehle eine Datei pro zugehörigen Ansichten) speichern, die für die Datenbank ausgeführt werden sollen, können wir unsere Tests für jede Ansicht demselben Skript hinzufügen , sodass der Vorgang von (re -) Beim Erstellen unserer Ansicht werden auch die Tests der Ansicht ausgeführt. Auf diese Weise erhalten wir beide Regressionstests, wenn wir Ansichten neu erstellen, und wenn die Ansichtserstellung gegen die Produktion ausgeführt wird, wird die Ansicht auch in der Produktion getestet.
Erstellen Sie eine Testsystemdatenbank, die Sie beliebig oft neu laden können. Laden Sie Ihre Daten oder erstellen Sie Ihre Daten und speichern Sie sie. Erstellen Sie eine einfache Möglichkeit, es neu zu laden. Schließen Sie Ihr Entwicklungssystem an diese Datenbank an und validieren Sie Ihren Code, bevor Sie zur Produktion gehen. Treten Sie sich jedes Mal, wenn Sie es schaffen, ein Problem in Produktion zu bringen. Erstellen Sie eine Testsuite, um bekannte Probleme zu überprüfen und Ihre Testsuite im Laufe der Zeit zu erweitern.
quelle
Möglicherweise möchten Sie DbUnit überprüfen , damit Sie versuchen können , Komponententests für Ihre Programme mit einem festen Datensatz zu schreiben. Auf diese Weise sollten Sie in der Lage sein, Abfragen mit mehr oder weniger vorhersehbaren Ergebnissen zu schreiben.
Das andere, was Sie möglicherweise tun möchten, ist, Ihren SQL Server-Ausführungsstapel zu profilieren und herauszufinden, ob alle Abfragen tatsächlich die richtigen sind, z. B. wenn Sie nur eine Abfrage verwenden, die sowohl korrekte als auch falsche Ergebnisse zurückgibt, dann ist die Abfrage eindeutig verwendet wird in Frage, aber was ist, wenn Ihre Anwendung unterschiedliche Anfragen an verschiedenen Stellen im Code sendet?
Jeder Versuch, Ihre Abfrage zu korrigieren, wäre dann vergeblich. Die unerwünschten Abfragen könnten ohnehin immer noch die falschen Ergebnisse auslösen.
quelle
Re: tpdi
Beachten Sie, dass hiermit nur überprüft wird, ob die Werte für aufeinanderfolgende Monate aufeinanderfolgend sind und nicht, dass aufeinanderfolgende Daten vorhanden sind (was wahrscheinlich ursprünglich beabsichtigt war). Dies ist immer dann der Fall, wenn keine Ihrer Quelldaten aufeinanderfolgend ist (z. B. wenn Sie nur geradzahlige Monate haben), auch wenn Ihre AM-Berechnung völlig falsch ist.
Fehlt mir auch etwas oder stößt die zweite Hälfte dieser ON-Klausel auf den falschen Monatswert? (dh prüft, ob 12/2011 nach 1/2010 kommt)
Was noch schlimmer ist, wenn ich mich richtig erinnere, lässt SQL Server mindestens weniger als 10 Ansichtsebenen zu, bevor das Optimierungsprogramm seine virtuellen Hände in die Luft wirft und bei jeder Anforderung vollständige Tabellenscans durchführt. Übertreiben Sie diesen Ansatz also nicht.
Denken Sie daran, Ihre Testfälle zu testen!
Andernfalls scheint es im Allgemeinen so zu sein , einen sehr breiten Datensatz zu erstellen, der die meisten oder alle möglichen Formen von Eingaben umfasst, SqlUnit oder DbUnit oder eine andere * Einheit zu verwenden, um die Überprüfung der erwarteten Ergebnisse anhand dieser Daten zu automatisieren und sie nach Bedarf zu überprüfen, zu pflegen und zu aktualisieren der Weg, den man gehen sollte.
quelle