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- selectAbfrage 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 whenTestanweisung 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.