Tabellenwertfunktionen sind das absolute Killer-Feature

28. September 2015

Wenn eine Abfrage bzw. ein View einfach nicht mehr genug ist

In manchen Fällen werden Datenbankabfragen so komplex, dass man

  • entweder selbst nicht mehr durchsteigt,
  • die Performance grauenhaft schlecht ist oder
  • das Problem mit einem einzelnen View schlicht nicht zu lösen ist.

Man möchte intuitiv eine temporäre Tabelle anlegen, dort die gewünschten Ergebnisse Stück für Stück eintragen und dann das Ganze ausgeben. Dieses Vorgehen hätte allerdings diverse Nachteile:

  • Eine solche Prozedur könnte man nicht innerhalb eines SELECT-Statements aufrufen, sondern müsste es prozedural starten, warten, bis es abgearbeitet worden ist, und die Ergebnisse dann irgendwie weiterverarbeiten. Nach Gebrauch müssten die temporären Daten dann wieder gelöscht werden.
  • Bei Verwendung in einer Multi-User-Umgebung müsste man einen recht großen Aufwand dafür treiben, dass ein gleichzeitiger Aufruf von unterschiedlichen Benutzern zu keiner Verfälschung des Ergebnisses führt.

In solchen Fällen helfen einem Tabellenwertfunktionen. Wie der Name schon sagt, sind dies Funktionen, die als Rückgabewert eine Tabelle liefern. Das ist an sich schon super. Richtig elegant wird dies aber erst durch den Umstand, dass man eine solche zurückgegebene Tabelle wiederum innerhalb einer Abfrage wie eine ganz normale Tabelle ansprechen und dementsprechend mit dem Inhalt anderer Tabellen verknüpfen kann.

Ein Beispiel zur Veranschaulichung

Schauen wir es uns der Reihe nach an: Grundlage des Beispiels sind wieder Tabellen aus dem Umfeld der amerikanischen Präsidenten aus dem Artikel über die Kreuztabellen. In diesem Fall haben wir es wieder mit der Tabelle mit den Präsidenten sowie der Tabelle ELECTION zu tun, in der die Wahlen vermerkt sind:

SQL Server Tabellenwertfunktionen

Wir konstruieren nun eine Tabellenwertfunktion, der wir den Namen eines Bundestaates übergeben und welche die Namen der Präsidenten liefert, die aus diesem Bundesstaat kommen. Diese Aufgabenstellung ist so einfach, dass man sie auch anders lösen könnte. Es geht aber hier um Prinzip: In der Funktion könnte man beliebig lange Berechnungen unterbringen, deren Ergebnis lediglich am Ende in einer Tabelle hinterlegt wird.

FUNCTION [dbo].[Winner aus Bundesstaat als Tabelle zurückgeben] 
(@Bundesstaat Varchar (20))
RETURNS @WINNER TABLE (NAME VARCHAR(20) NOT NULL, YEAR_ELECTED INT, VOTES INT) AS
BEGIN

  INSERT INTO @WINNER ( NAME, YEAR_ELECTED, VOTES )
  SELECT ELECTION.CANDIDATE, ELECTION.ELECTION_YEAR, ELECTION.VOTES
  FROM ELECTION 
    INNER JOIN President
      ON PRESIDENT.PRES_NAME = ELECTION.CANDIDATE
  WHERE ELECTION.WINNER_LOSER_INDIC='W' AND
    STATE_BORN = @Bundesstaat;

  RETURN 

END

Um das Ergebnis der obigen Funktion weiterverarbeiten zu können, muss deren Aufruf nun irgenwie in eine Abfrage oder ein Skript eingebettet werden können. Dieses geschieht auf verblüffend einfache Art und Weise, indem der Aufruf wie der Name einer Tabelle in ein beliebiges SELECT-Statement eingebettet wird. Das sieht dann zum Beispiel so aus:

SELECT * FROM [Winner aus Bundesstaat als Tabelle zurückgeben]('Ohio') AS GewinnerAusOhio

Die Tabelle GewinnerAusOhio in der obigen Anweisung könnte nun, wie oben schon angedeutet, ganz normal zum Beispiel über Joins mit anderen Tabellen verknüpft werden.