{"id":55000648,"date":"2009-02-01T00:00:00","date_gmt":"2020-05-22T22:20:54","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=648"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Benutzerdefinierte_Funktionen_im_MS_SQL_Server","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/","title":{"rendered":"Benutzerdefinierte Funktionen im MS SQL Server"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg01.met.vgwort.de\/na\/bfe0a340b3e148418b0b71cc56d30322\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>&#8222;Die Drei von der Tankstelle&#8220;, &#8222;Drei Engel f&uuml;r Charlie&#8220; und &#8222;Die drei Fragezeichen&#8220; haben eines gemeinsam: Es sind immer Drei. Drei, von denen jeder seine besonderen F&auml;higkeiten hat, und Drei, die sich perfekt erg&auml;nzen. So ist es auch beim SQL Server. Neben den gespeicherten Prozeduren und Triggern bietet der SQL Server mit den benutzerdefinierten Funktionen eine dritte Komponente, mit der Programmlogik gespeichert und wiederverwendet werden kann. Und weil aller guten Dinge nun mal drei sind, gibt es die benutzerdefinierten Funktionen auch gleich in drei verschiedenen Typen.<\/b><\/p>\n<p>Diese drei verschiedenen Typen hei&szlig;en Inlinefunktionen, Tabellenfunktionen und Skalarfunktionen. <\/p>\n<p>Skalarfunktionen sind weitestgehend mit VBA-Funktionen in Access vergleichbar. Anhand einer optionalen Parameter&uuml;bergabe wird ein Wert ermittelt und zur&uuml;ckgegeben. Die Inline- und Tabellenfunktionen gehen dort noch einen Schritt weiter, denn sie liefern nicht nur einen Wert, sondern komplette Ergebnismengen.<\/p>\n<p>Die &auml;hnlichkeit zu VBA-Funktionen liegt aber nicht nur in der Ermittlung der Daten, sondern auch in ihrer Anwendung. Gerade die Verwendung eigener geschriebener Funktionen in <b>SELECT<\/b>-Anweisungen, Access-Abfragen, G&uuml;ltigkeitsregeln und Modulen ist einer der Vorteile von Access. Dieser Vorteil gilt auch f&uuml;r benutzerdefinierte Funktionen, denn diese sind in der SQL Server-Entwicklung universell einsetzbar. Sie k&ouml;nnen in <b>SELECT<\/b>-Anweisungen, in Sichten, in gespeicherten Prozeduren, in Triggern und in anderen benutzerdefinierten Funktionen wie auch in Standardwerten und Einschr&auml;nkungen verwendet werden und stehen somit f&uuml;r die Realisierung verschiedenster Anforderungen zur Verf&uuml;gung.<\/p>\n<p><b>Einsatzm&ouml;glichkeiten<\/b><\/p>\n<p>Der Grund f&uuml;r den Einsatz von benutzerdefinierten Funktionen ist derselbe wie bei gespeicherten Prozeduren: Die Kapselung von Programmlogik und somit die Kapselung von Gesch&auml;ftsregeln und von Regeln zur Datenkonsistenz. <\/p>\n<p>Zwar k&ouml;nnen Sie mit benutzerdefinierten Funktionen keine Daten manipulieren, aber im Vergleich zu gespeicherten Prozeduren sind benutzerdefinierte Funktionen flexibler einsetzbar. Im Gegensatz zu gespeicherten Prozeduren k&ouml;nnen diese n&auml;mlich auch in Sichten, <b>SELECT<\/b>-Anweisungen oder in anderen benutzerdefinierten Funktionen verwendet werden. Insofern ist der Einsatz benutzerdefinierter Funktionen in manchen F&auml;llen sinnvoller als der Einsatz gespeicherter Prozeduren.<\/p>\n<p>F&uuml;r die beispielsweise oft ben&ouml;tigte Ermittlung der Produktbezeichnung anhand einer Produktnummer k&ouml;nnen Sie eine Skalarfunktion erstellen, die immer genau den einen Wert &#8211; die Produktbezeichnung &#8211; anhand der &uuml;bergebenen Produktnummer liefert.<\/p>\n<p>Eine andere Skalarfunktion k&ouml;nnte die in der Northwind-Datenbank immer wieder notwendige Summe einer Bestellposition anhand der Spalten <b>Einzelpreis<\/b>, <b>Menge <\/b>und <b>Discount <\/b>berechnen.<\/p>\n<p>Die Werte solcher Skalarfunktionen k&ouml;nnen Sie als Spalte in einer <b>SELECT<\/b>-Anweisung, als Filterkriterium in einer <b>WHERE<\/b>-Bedingung oder in einer <b>INSERT<\/b>&#8211; oder <b>UPDATE<\/b>-Anweisung verwenden.<\/p>\n<p>In <b>SELECT<\/b>-Anweisungen und bei Datenmanipulationen stehen auch die Tabellen- und Inlinefunktionen zur Verf&uuml;gung. Allerdings liefern diese Typen nicht einzelne Werte, sondern Ergebnismengen und sind somit ein guter Ersatz f&uuml;r Sichten oder Tabellen. <\/p>\n<p>Tabellen- und Inlinefunktionen bieten gerade Sichten gegen&uuml;ber einen gro&szlig;en Vorteil: Sie unterst&uuml;tzen Parameter. <\/p>\n<p>Eine Sicht liefert immer alle Daten der in der Sicht angegebenen SQL-Anweisung. Die Datenermittlung ist starr und kann nicht durch Parameter beeinflusst werden. In Tabellen- und Inlinefunktionen hingegen sind Parameter erlaubt.<\/p>\n<p>Dadurch k&ouml;nnen die Daten bereits bei der Ermittlung anhand der &uuml;bergebenen Parameterwerte gefiltert werden. <\/p>\n<p>Es ist schon ein Unterschied, ob in einer Tabellenverkn&uuml;pfung von Bestellkopf und Bestellpositionen alle Bestellpositionen verkn&uuml;pft werden oder dabei nur die Bestellpositionen ber&uuml;cksichtigt werden, die dem Wert eines &uuml;bergebenen Parameters entsprechen.<\/p>\n<p>Sie sehen, die Einsatzm&ouml;glichkeiten sind so vielf&auml;ltig wie die von VBA-Funktionen in Access. Die Verwendung benutzerdefinierter Funktionen ist f&uuml;r Sie insofern eigentlich nichts Neues. Bis auf die Entwicklung dieser Funktionen, denn die schreiben Sie nat&uuml;rlich nicht in VBA, sondern in T-SQL. Dabei sind Art und Umfang der Entwicklungsm&ouml;glichkeit abh&auml;ngig vom jeweiligen Typ. <\/p>\n<p>Inline- und Tabellenfunktionen unterscheiden sich in der Werter&uuml;ckgabe gegen&uuml;ber den Skalarfunktionen und die Skalar- und Tabellenfunktionen unterscheiden sich anhand der M&ouml;glichkeiten zur Ermittlung des Werts beziehungsweise der Werte von den Inlinefunktionen.<\/p>\n<p><b>Inlinefunktionen<\/b><\/p>\n<p>Inlinefunktionen liefern eine Ergebnismenge und k&ouml;nnen insofern wie Tabellen und Sichten &#8211; und somit fast &uuml;berall &#8211; verwendet werden. Aber nur fast, denn bei der Ermittlung von Standardwerten oder der Einhaltung von G&uuml;ltigkeitsregeln wird dieser Funktionstyp nicht unterst&uuml;tzt.<\/p>\n<p>Der gro&szlig;e Vorteil einer Inlinefunktion liegt darin, dass bei der Ermittlung der Daten &uuml;bergebene Parameterwerte als Filterkriterien verwendet werden k&ouml;nnen. Damit ist eigentlich auch bereits die Definition einer Inlinefunktion beschrieben. Sie besteht aus einer einzigen <b>SELECT<\/b>-Anweisung, die anhand eines Parameterwerts gefiltert werden kann. Mehr au&szlig;er dieser gibt es dort nicht. Von der Programmierung her ist die Inlinefunktion daher die einfachste Variante.<\/p>\n<p>Eine neue Inlinefunktion k&ouml;nnen Sie mit dem SQL Server Management Studio anlegen. Sie finden die benutzerdefinierten Funktionen unter <b>Programmierbarkeit<\/b> innerhalb der jeweiligen Datenbank. Dort sehen Sie unter <b>Gespeicherte Prozeduren<\/b> auch den Knoten <b>Funktionen<\/b>, der Ihnen nach einem Klick auf den Knoten weitere Verzweigungen anzeigt. <\/p>\n<p>Inlinefunktionen liefern eine Ergebnismenge &uuml;ber eine virtuelle Tabelle und geh&ouml;ren somit zur Gruppe der Tabellenwertfunktionen. <\/p>\n<p>Durch einen Klick mit der rechten Maustaste auf den Knoten <b>Tabellenwertfunktionen <\/b>k&ouml;nnen Sie den Befehl <b>Neue Inline-Tabellenwertfunktion <\/b>(siehe Bild 1) ausw&auml;hlen. Sie erhalten auch hier &#8211; wie bei den gespeicherten Prozeduren und Triggern &#8211; ein neues Abfragefenster mit einem Vorlageskript.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_01\/UDF-web-images\/pic01_opt.jpeg\" alt=\"pic01.TIF\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 1: Eine neue Inlinefunktion<\/span><\/b><\/p>\n<p>Die Definition einer neuen Funktion beginnt mit dem Befehl <b>CREATE FUNCTION<\/b>, gefolgt vom Funktionsnamen, der immer das entsprechende Schema enthalten muss. Wie bereits bei den gespeicherten Prozeduren beschrieben, werden &uuml;ber das Schema eines Objekts unter anderem die Zugriffsrechte verwaltet. Sofern Sie kein detailliertes Berechtigungskonzept einsetzen, ist das Schema in der Regel <b>dbo<\/b>. Sie sollten f&uuml;r eine einheitliche Basis f&uuml;r die Weiterentwicklung und eine sp&auml;tere Konfiguration eines Berechtigungskonzepts immer <b>dbo<\/b> angeben.<\/p>\n<p>Eine genauere Erkl&auml;rung der Berechtigungsvergabe anhand der Schemata w&uuml;rde allerdings den Rahmen dieses Artikels sprengen.<\/p>\n<p>Der oder die Parameter, die in der <b>SELECT<\/b>-Anweisung der Inlinefunktion verwendet werden, geben Sie durch Komma getrennt in Klammern hinter dem Namen der Funktion an. Dabei verwenden Sie das <b>@-<\/b>Zeichen zur Kennzeichnung jedes einzelnen Parameters sowie den Datentyp. <\/p>\n<p>Nach den Parametern definieren Sie mit <b>RETURNS TABLE<\/b>, welchen Datentyp das Ergebnis der Funktion aufweist. Eine Inlinefunktion liefert eine Ergebnismenge anhand einer virtuellen Tabelle &uuml;ber den Datentyp <b>TABLE<\/b>. Die Struktur dieser virtuellen Tabelle ergibt sich aus der <b>SELECT<\/b>-Anweisung. Nach <b>RETURNS TABLE <\/b>leiten Sie mit <b>AS <\/b>den eigentlichen Programmcode ein, der in Klammern angegeben werden muss. Der Programmcode besteht wie bereits erw&auml;hnt nur aus einer einzelnen <b>SELECT<\/b>-Anweisung. Eine weitere Spezifikation zur Kennzeichnung der Tabellenfunktion als Inlinefunktion ist nicht notwendig. <\/p>\n<p>Als Beispiel sehen Sie in Listing 1 die Inlinefunktion <b>dbo.ifArtikelEinerKategorie<\/b>, die alle aktiven oder inaktiven Artikel einer bestimmten Kategorie als Ergebnismenge liefert. <\/p>\n<p class=\"kastentabelleheader\">Listing 1: Beispiel f&uuml;r eine Inlinefunktion<\/p>\n<pre>CREATE FUNCTION dbo.ifArtikelEinerKategorie \r\n( \r\n @CategoryId int,\r\n @Discontinued bit\r\n)\r\nRETURNS TABLE \r\nAS\r\nRETURN \r\n(\r\n SELECT \r\n dbo.Products.ProductId, dbo.Products.ProductName, \r\n dbo.Products.SupplierID, dbo.Suppliers.CompanyName, \r\n dbo.Products.CategoryID, dbo.Categories.CategoryName, \r\n dbo.Products.QuantityPerUnit, dbo.Products.UnitPrice, \r\n dbo.Products.UnitsInStock, dbo.Products.UnitsOnOrder, \r\n dbo.Products.ReorderLevel, dbo.Products.Discontinued\r\n FROM \r\n dbo.Products \r\n INNER JOIN dbo.Categories \r\n ON dbo.Products.CategoryID = dbo.Categories.CategoryID \r\n INNER JOIN dbo.Suppliers \r\n ON Products.SupplierID = Suppliers.SupplierID\r\n WHERE\r\n dbo.Products.CategoryId = @CategoryId\r\n AND\r\n dbo.Products.Discontinued = @Discontinued\r\n)<\/pre>\n<p>Die Erkl&auml;rung dieser Inlinefunktion ist recht einfach. Die <b>SELECT<\/b>-Anweisung ermittelt alle Artikeldaten zuz&uuml;glich der Bezeichnung der Kategorie, zu der die Artikel geh&ouml;ren, sowie den Firmennamen des Lieferanten. Diese Ergebnismenge wird bei der Ermittlung auf eine Kategorie gefiltert, die &uuml;ber den Parameter <b>@CategoryId <\/b>an die <b>SELECT<\/b>-Anweisung &uuml;bergeben wird. Zus&auml;tzlich wird &uuml;ber den Parameter <b>@Discontinued <\/b>bestimmt, ob die Ergebnismenge nur die aktiven Artikel (Wert <b>0<\/b>) oder nur die inaktiven Artikel (Wert <b>1<\/b>) enth&auml;lt.<\/p>\n<p>Bei der <b>SELECT<\/b>-Anweisung m&uuml;ssen Sie darauf achten, dass alle Spalten einen Namen bekommen. Dies gilt insbesondere bei der Verwendung von Konstanten oder berechneten Spalten. Hier muss zwingend ein Alias vergeben werden. Diese Inlinefunktion k&ouml;nnen Sie nun wie eine &#8222;parametrisierte Sicht&#8220; verwenden. Folgender Aufruf liefert alle aktiven Artikel der Kategorie <b>1<\/b>:<\/p>\n<pre>SELECT * FROM dbo.ifArtikelEinerKategorie (1, 0)<\/pre>\n<p>Sie k&ouml;nnen die Inlinefunktion auch in einer Tabellenverkn&uuml;pfung verwenden. Die folgende Abfrage etwa liefert alle Bestellpositionen, die inaktive Artikel der Kategorie 1 beinhalten:<\/p>\n<pre>SELECT * FROM dbo.[Order Details] OD\r\nINNER JOIN dbo.ifArtikelEinerKategorie(1, 1) AEK\r\nON OD.ProductId = AEK.ProductId<\/pre>\n<p>F&uuml;r einfache <b>SELECT<\/b>-Anweisungen ist die Inlinefunktion die erste Wahl, da sie schnell programmiert und flexibel einsetzbar ist. Flexibel einsetzbar sind auch die Tabellenfunktionen &#8211; und sie sind auch flexibel in der Ermittlung der Ergebnismenge.<\/p>\n<p><b>Tabellenfunktionen<\/b><\/p>\n<p>Im Unterschied zu einer Inlinefunktion k&ouml;nnen in einer Tabellenfunktion mehrere SQL-Anweisungen zur Ermittlung der Ergebnismenge gespeichert werden. <\/p>\n<p>Dies sagt bereits der Kontextmen&uuml;befehl des Knotens <b>Tabellenwertfunktionen<\/b> aus: Neue Tabellenwertfunktion mit mehreren Anweisungen (siehe Bild 1). Auch dieser Befehl liefert Ihnen eine Skriptvorlage in einem neuen Abfragefenster. Diese unterscheidet sich in einigen Punkten von der der Inlinefunktion.<\/p>\n<p>Bei einer Tabellenfunktion wird die Struktur der virtuellen Tabelle nicht anhand einer <b>SELECT<\/b>-Anweisung bestimmt, sondern muss durch eine <b>TABLE<\/b>-Variable explizit definiert werden. Insofern gibt es hier kein <b>RETURNS TABLE<\/b>, sondern ein <b>RETURNS <\/b>gefolgt von der Definition der <b>TABLE<\/b>-Variablen.<\/p>\n<p>Die einzelnen SQL-Anweisungen zur Ermittlung der Ergebnismenge werden in einer Tabellenfunktion im <b>BEGIN&#8230;END<\/b>-Block zusammengefasst. Mit diesen SQL-Anweisungen ermitteln Sie nach und nach die Daten und f&uuml;llen mit diesen die <b>TABLE<\/b>-Variable. Dabei stehen Ihnen alle M&ouml;glichkeiten der T-SQL-Programmierung zur Verf&uuml;gung, bis auf wenige Ausnahmen:<\/p>\n<ul>\n<li class=\"aufz-hlung\">Ausgabe von Meldungen: Benutzerdefinierte Funktionen liefern immer Werte oder Ergebnismengen. Meldungen, die zum Beispiel auf einen Fehler hinweisen und durch <b>RAISERROR <\/b>oder <b>PRINT <\/b>ausgel&ouml;st werden, werden nicht unterst&uuml;tzt.<\/li>\n<li class=\"aufz-hlung\">Datenmanipulationen au&szlig;erhalb der Funktion: Innerhalb der Tabellenfunktion k&ouml;nnen Sie die Daten der dort enthaltenen Objekte &#8211; sprich tempor&auml;ren Tabellen oder Table-Variablen &#8211; manipulieren; die Daten anderer Tabellen jedoch nicht.<\/li>\n<li class=\"aufz-hlung\">Verwendung von gespeicherten Prozeduren: Gespeicherte Prozeduren k&ouml;nnen in benutzerdefinierten Funktionen nicht aufgerufen werden. Der Befehl <b>EXECUTE <\/b>wird nicht unterst&uuml;tzt. Dies w&uuml;rde auch der gerade erw&auml;hnten Einschr&auml;nkung widersprechen, dass in benutzerdefinierten Funktionen keine Daten von Tabellen manipuliert werden k&ouml;nnen. W&auml;ren in benutzerdefinierten Funktionen gespeicherte Prozeduren erlaubt, w&auml;ren &uuml;ber diese die Datenmanipulationen m&ouml;glich.<\/li>\n<\/ul>\n<p><!--30percent--><\/p>\n<p>Die Programmlogik wird wie bei gespeicherten Prozeduren durch den Befehl <b>RETURN <\/b>beendet und dadurch die ermittelte Ergebnismenge an die aufrufende Instanz geliefert.<\/p>\n<p>In Listing 2 sehen Sie die Tabellenfunktion <b>dbo.tfMitarbeiterHierarchie<\/b>, die die Hierarchie der Mitarbeiter im Unternehmen auflistet. Als Erg&auml;nzung wird pro Mitarbeiter das Alter hinzugef&uuml;gt.<\/p>\n<p class=\"kastentabelleheader\">Listing 2: Beispiel f&uuml;r eine Tabellenfunktion<\/p>\n<pre>CREATE FUNCTION dbo.tfMitarbeiterHierarchie ()\r\nRETURNS @Mitarbeiter TABLE \r\n(\r\n HierarchieEbene int, ManagerId int, \r\n MitarbeiterId int, Titel nvarchar(30), \r\n Mitarbeiter nvarchar(30), [Alter] int\r\n)\r\nAS\r\nBEGIN\r\n -- Hierarchie per CTE ermitteln\r\n WITH cteHierarchie (Ebene, MgrId, EmpId, Titel, Mitarbeiter) AS \r\n (\r\n SELECT 1, E.ReportsTo, E.EmployeeId, E.Title, \r\n E.LastName + &euro;&#154;, &euro;&#154; + E.FirstName \r\n FROM dbo.Employees As E\r\n WHERE ReportsTo Is Null\r\n UNION ALL\r\n SELECT Ebene+1, E.ReportsTo, E.EmployeeId, E.Title, \r\n E.LastName + &euro;&#154;, &euro;&#154; + E.FirstName\r\n FROM dbo.Employees As E INNER JOIN cteHierarchie \r\n ON cteHierarchie.EmpId = E.ReportsTo\r\n )\r\n INSERT INTO @Mitarbeiter (HierarchieEbene, ManagerId, \r\n MitarbeiterId, Titel, Mitarbeiter)\r\n SELECT * FROM cteHierarchie ORDER BY Ebene, MgrId; \r\n -- Alter erg&auml;nzen\r\n UPDATE @Mitarbeiter\r\n SET [Alter] = \r\n CASE \r\n WHEN DateAdd(Year, Datediff(Year, BirthDate, \r\n getdate()), BirthDate) &gt; getdate() \r\n THEN Datediff(Year, BirthDate, getdate()) - 1\r\n ELSE DateDiff(Year, BirthDate, getdate())\r\n END \r\n FROM @Mitarbeiter As Mitarbeiter \r\n INNER JOIN dbo.Employees \r\n ON Mitarbeiter.MitarbeiterId = dbo.Employees.EmployeeId \r\n RETURN \r\nEND<\/pre>\n<p>Der Quellcode dieser Tabellenfunktion sieht auf den ersten Blick kompliziert aus, aber auf den zweiten Blick ist zu erkennen, dass hier lediglich Daten ermittelt und in die R&uuml;ckgabe-Tabelle geschrieben werden, um danach noch per Update erg&auml;nzt zu werden. Doch der Reihe nach:<\/p>\n<p>Am Anfang, noch vor dem einleitenden <b>AS<\/b>, steht die Definition der <b>TABLE<\/b>-Variablen, &uuml;ber die die Ergebnismenge zur&uuml;ckgeliefert wird. Die Definition einer <b>TABLE<\/b>-Variablen ist identisch mit der des T-SQL-Befehls <b>CREATE TABLE<\/b>. Innerhalb des <b>BEGIN&#8230;END<\/b>-Blocks wird die <b>TABLE<\/b>-Variable mit Daten gef&uuml;llt. Dabei wird die Hierarchie der Mitarbeiter &uuml;ber eine rekursive <b>CTE <\/b>ermittelt und per <b>INSERT<\/b>-Anweisung in die <b>TABLE<\/b>-Variable geschrieben. <b>CTE <\/b>&#8211; die Common Table Expression &#8211; gibt es seit SQL Server 2005. <\/p>\n<p>Anschlie&szlig;end m&uuml;ssen die Datens&auml;tze in der <b>TABLE<\/b>-Variablen noch um das Alter des jeweiligen Mitarbeiters erg&auml;nzt werden. Die Berechnung des Alters erfolgt pro Mitarbeiter in einer <b>UPDATE<\/b>-Anweisung. Mittels <b>RETURN <\/b>wird die benutzerdefinierte Funktion beendet und die Ergebnismenge an die aufrufende Instanz &uuml;bermittelt.<\/p>\n<p>Die in diesem Beispiel erstellte Tabellenfunktion ben&ouml;tigt keine Parameter. Beim Aufrufen der Funktion m&uuml;ssen trotzdem die Klammern mit angegeben werden, da sonst die Funktion nicht erkannt wird.<\/p>\n<p>Die folgende Abfrage liefert die Hierarchie der Mitarbeiter inklusive des Alters des jeweiligen Mitarbeiters:<\/p>\n<pre>SELECT * FROM tfMitarbeiterHierarchie()<\/pre>\n<p>Sie sehen, in einer Tabellenfunktion kann einiges an Logik zur Ermittlung der Ergebnismenge implementiert werden. Dies gilt auch f&uuml;r die Ermittlung von nur einem Wert &#8211; und daf&uuml;r gibt es die Skalarfunktionen.<\/p>\n<p><b>Skalarfunktion<\/b><\/p>\n<p>Skalar Was ist nochmal ein Skalar Nun, wozu gibt es Wikipedia: &#8222;Eine skalare Variable ist im Kontext von Programmiersprachen eine Variable, die einen einzelnen Wert speichert.&#8220; Also eine doch durchaus treffende Bezeichnung f&uuml;r eine benutzerdefinierte Funktion, die als Ergebnis nur einen einzelnen Wert liefert.<\/p>\n<p>Die Ermittlung eines solchen Werts kann ein einzelnes <b>SELECT<\/b>-Statement, eine Konstante oder auch mehrere Zeilen Code wie bei der Tabellenfunktion sein. Art und Umfang zur Ermittlung dieses einzelnen Wertes ist Ihnen &uuml;berlassen. Bei der Programmierung haben Sie dieselben M&ouml;glichkeiten, aber auch dieselben Einschr&auml;nkungen, wie bei den Tabellenfunktionen.<\/p>\n<p>Skalarfunktionen werden gerne als &#8222;gekapselte Konstanten&#8220; verwendet, da hier lediglich eine Konstante zur&uuml;ckgegeben wird. Sollte sich diese Konstante mal &auml;ndern, muss sie nur an einer Stelle &#8211; in der Skalarfunktion &#8211; ge&auml;ndert werden.<\/p>\n<p>Die Einsatzm&ouml;glichkeiten von Skalarfunktionen sind sehr vielf&auml;ltig. Sie k&ouml;nnen als Spalten in einer <b>SELECT<\/b>-Anweisung, in <b>WHERE<\/b>-Bedingungen oder auch als Initialisierung von Variablen in T-SQL verwendet werden, wie auch in gespeicherten Prozeduren, Sichten, Triggern und in anderen benutzerdefinierten Funktionen.<\/p>\n<p>Auch in Einschr&auml;nkungen und Standardwerten einer Tabelle k&ouml;nnen Skalarfunktionen genutzt werden. Bevor Sie also einen Trigger f&uuml;r etwas ausgefallenere Standardwerte beziehungsweise Einschr&auml;nkungen verwenden, sollten Sie zun&auml;chst den Einsatz einer Skalarfunktion pr&uuml;fen.<\/p>\n<p>Um eine neue Skalarfunktion zu erstellen, m&uuml;ssen Sie im Knoten <b>Funktionen<\/b> aus dem Kontextmen&uuml; des Knotens <b>Skalarwertfunktionen<\/b> den Eintrag <b>Neue Skalarwertfunktion<\/b> anklicken. Sie erhalten auch hier wieder eine neue Abfrage mit einem Vorlageskript.<\/p>\n<p>Die Struktur &auml;hnelt der einer Tabellenfunktion. Auch hier definieren Sie mit der Anweisung <b>RETURNS <\/b>den Datentyp des R&uuml;ckgabewerts. Nur, dass es sich hier nicht um eine Definition einer virtuellen Tabelle, sondern um einen Datentyp f&uuml;r einen einzelnen Wert handelt. Dabei k&ouml;nnen Sie alle Datentypen nutzen, die der SQL Server im Bereich einer Tabellendefinition zur Verf&uuml;gung stellt, mit Ausnahme der Datentypen <b>text<\/b>, <b>ntext<\/b>, <b>image <\/b>oder <b>timestamp<\/b>. Es gibt noch einen weiteren Datentyp, den Sie nicht verwenden k&ouml;nnen. Dieser steht aber auch nicht als Datentyp f&uuml;r Tabellen zur Verf&uuml;gung, sondern nur innerhalb der T-SQL-Programmierung: der Datentyp <b>TABLE<\/b>. So leicht ist der SQL Server nun auch wieder nicht auszutricksen.<\/p>\n<p>In einer Skalarfunktion entwickeln Sie die Logik wie auch bei der Tabellenfunktion innerhalb eines <b>BEGIN&#8230;END<\/b>-Blocks. Den ermittelten Wert &uuml;bergeben Sie dann am Ende mit dem Befehl <b>RETURN<\/b>. Bei einer Skalarfunktion muss die Variable, die den ermittelten Wert enth&auml;lt, zwingend hinter der Anweisung <b>RETURN <\/b>angegeben werden.<\/p>\n<p>Im folgenden Beispiel wird eine bereits eingangs erw&auml;hnte Anforderung umgesetzt: In einer Skalarfunktion soll die Produktbezeichnung anhand der &uuml;bergebenen Produkt-ID ermittelt werden. Die Umsetzung dieser Anforderung sehen Sie in Listing 3.<\/p>\n<p class=\"kastentabelleheader\">Listing 3: Eine Skalarfunktion zur Ermittlung von Produktbezeichnungen<\/p>\n<pre>CREATE FUNCTION dbo.sfProduktBezeichnung\r\n(\r\n@ProductId int\r\n)\r\nRETURNS nvarchar(40)\r\nAS\r\nBEGIN\r\nDECLARE @ProductName nvarchar(40)\r\nSELECT @ProductName = ProductName\r\nFROM Products WHERE ProductId = @ProductId\r\nRETURN @ProductName\r\nEND<\/pre>\n<p>Mit dieser Skalarfunktion k&ouml;nnen Sie nun in <b>SELECT<\/b>-Anweisungen anhand der Produkt-ID die Bezeichnung ohne aufwendige Tabellenverkn&uuml;pfungen ausgeben. In Bild 2 sehen Sie eine solche Anweisung einschlie&szlig;lich des Ergebnisses. <\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_01\/UDF-web-images\/pic02_opt.jpeg\" alt=\"pic02.TIF\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 2: Eine Skalarfunktion im Einsatz<\/span><\/b><\/p>\n<p>Dort sehen Sie auch, dass die Skalarfunktion mit dem Zusatz <b>dbo<\/b> aufgerufen wurde. Im Gegensatz zu Tabellen- und Inlinefunktionen m&uuml;ssen Sie bei einer Skalarfunktion immer das Schema mit angeben, sonst wird die Funktion vom SQL Server nicht erkannt.<\/p>\n<p>Auch das zweite eingangs erw&auml;hnte Beispiel &#8211; die Berechnung der Positionssumme &#8211; ist mit einer Skalarfunktion schnell realisiert. Listing 4 zeigt eine solche Skalarfunktion. <\/p>\n<p class=\"kastentabelleheader\">Listing 4: Berechnung der Positionssumme<\/p>\n<pre>CREATE FUNCTION dbo.sfBerechnePositionSumme\r\n(\r\n@OrderId int,\r\n@ProductId int\r\n)\r\nRETURNS decimal(18,2)\r\nAS\r\nBEGIN\r\nDECLARE @PosSum as float\r\nSELECT @PosSum =\r\nSum((UnitPrice*Quantity)*\r\n((1-Discount)\/100)*100)\r\nFROM dbo.[Order Details]\r\nWHERE OrderId = @OrderId\r\nAND ProductId = @ProductId\r\nRETURN @PosSum\r\nEND<\/pre>\n<p>Wenn Sie nun die Abfrage in Bild 2 mit dieser Funktion erweitern, erhalten Sie pro Bestellposition direkt die Summe. Sollte sich an der Berechnung in Zukunft etwas &auml;ndern &#8211; beispielsweise durch eine Rabattstaffel abh&auml;ngig von der Menge &#8211; m&uuml;ssen Sie nur die Berechnung der Skalarfunktion erweitern. Abbildung 3 zeigt die erweiterte <b>SELECT<\/b>-Anweisung inklusive Ergebnis.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_01\/UDF-web-images\/pic03_opt.jpeg\" alt=\"pic03.TIF\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 3: Die erweiterte Skalarfunktion<\/span><\/b><\/p>\n<p>Anhand dieser beiden doch recht bescheidenen Beispiele erkennen Sie bereits das Potenzial von Skalarfunktionen.<\/p>\n<p>Es gibt noch eine klassische Skalarfunktion, die bei fast jedem Projekt zum Einsatz kommen sollte, in dem benutzerdefinierte Funktionen eingesetzt werden: das Ermitteln des aktuellen Datums.<\/p>\n<p>Der SQL Server liefert anhand der Systemfunktion <b>getdate() <\/b>den aktuellen Zeitpunkt im Format <b>Datum und Uhrzeit<\/b>. Bei SQL-Anweisungen, die nur Daten bis zum heutigen Tag ber&uuml;cksichtigen sollen, kann die Funktion <b>getdate() <\/b>aber nicht ohne Weiteres genutzt werden. Immerhin ist es ein Unterschied, ob die Daten bis zum <b>06.11.2008<\/b> oder bis zum <b>06.11.2008 23:00:00<\/b> verglichen werden. Um es genau zu nehmen, ist das ein Unterschied von 23 Stunden. Bei einer Umsatzauswertung w&auml;re dies schlichtweg falsch, da der Umsatz des fast kompletten Tags in der Auswertung enthalten w&auml;re. Wenn schon also ein Zeitpunkt des heutigen Tages, dann bitte den j&uuml;ngsten, also <b>06.11.2008 00:00:00<\/b>.<\/p>\n<p>Was also liegt n&auml;her, als in einer Skalarfunktion den Wert der SQL Server-Funktion <b>getdate() <\/b>zu ermitteln und diesen Wert so aufzubereiten, dass er die Uhrzeit <b>00:00:00<\/b> enth&auml;lt. Dies ist mit folgender <b>SELECT<\/b>-Anweisung realisierbar:<\/p>\n<pre>SELECT Cast(Convert(varchar(10), getdate(), 112) As datetime)<\/pre>\n<p>Eine gute Idee, aber nicht umsonst hie&szlig; es eben &#8222;zum Einsatz kommen sollte&#8220;. Die Umsetzung scheitert an einer Einschr&auml;nkung der Skalarfunktionen, denn diese k&ouml;nnen nur &#8222;deterministische Funktionen&#8220; verarbeiten.<\/p>\n<p>Eine deterministische Funktion liefert immer dasselbe Ergebnis, wenn sie mit bestimmten Parameterwerten aufgerufen wird. So liefert die Beispielfunktion <b>dbo.sfProduktBezeichnung<\/b> immer die Produktbezeichnung zur Produkt-ID <b>1<\/b>, wenn <b>1<\/b> als Parameter &uuml;bergeben wird. <\/p>\n<p>Eine nicht deterministische Funktion liefert bei jeder Ausf&uuml;hrung unterschiedliche Werte, auch wenn die Parameterwerte bei den Ausf&uuml;hrungen immer dieselben sind.<\/p>\n<p>Genau das ist bei <b>getdate() <\/b>der Fall: Es wird pro Aufruf immer der aktuelle Zeitpunkt zur&uuml;ckgegeben. Und der aktuelle Zeitpunkt hat genau jetzt schon einen anderen Wert. Und jetzt. Und jetzt. Jetzt wieder &#8230;<\/p>\n<p>Um die Anforderung &#8211; die Aufbereitung des aktuellen Datums zum Zeitpunkt <b>00:00 Uhr <\/b>&#8211; trotzdem mit einer Skalarfunktion zu realisieren, muss der Wert von <b>getdate() <\/b>vor dem Aufruf der Skalarfunktion ermittelt und als Parameterwert an die Skalarfunktion &uuml;bergeben werden.<\/p>\n<p>Listing 5 zeigt Ihnen nun das korrekte Ermitteln des aktuellen Datums zum Zeitpunkt 00:00 Uhr. <\/p>\n<p class=\"kastentabelleheader\">Listing 5: Das aktuelle Datum zum Zeitpunkt 0:00<\/p>\n<pre>CREATE FUNCTION dbo.sfAktuellerTag\r\n(\r\n@parGetdate datetime\r\n)\r\nRETURNS datetime\r\nAS\r\nBEGIN\r\nDECLARE @Tag datetime\r\nSET @Tag = cast(convert(varchar(10),\r\n@parGetdate, 112) as datetime)\r\nRETURN @Tag\r\nEND<\/pre>\n<p>Der folgende Aufruf dieser Skalarfunktion liefert Ihnen beispielsweise am <b>06.11.2008 <\/b>um <b>23:15 Uhr <\/b>den Wert <b>06.11.2008 00:00:00<\/b>:<\/p>\n<pre>SELECT dbo.sfAktuellerTag(getdate())<\/pre>\n<p>Diese Funktion k&ouml;nnen Sie nun in <b>WHERE<\/b>-Bedingungen verwenden, um Werte bis zum heutigen Tag zu ermitteln. Mehr noch, durch die Parameter&uuml;bergabe k&ouml;nnen Sie ein x-beliebiges Datum &uuml;bergeben. Dieses Datum wird immer mit der Uhrzeit <b>00:00 Uhr <\/b>ausgegeben.<\/p>\n<p>Haben Sie sich schon gefragt, warum die Funktion <b>getdate() <\/b>in der Beispielfunktion <b>dbo.tfMitarbeiterHierarchie<\/b> ohne Probleme funktioniert<\/p>\n<p>Die Antwort ist ganz einfach: Tabellen- und Inlinefunktionen haben keine Probleme mit nicht deterministischen Funktionen. Daf&uuml;r aber k&ouml;nnen Sie die Tabellen- und Inlinefunktionen nicht direkt in <b>WHERE<\/b>-Bedingungen oder als Spalte verwenden.<\/p>\n<p>Trotz einiger kleinerer Einschr&auml;nkungen sind die Skalar-, Inline- oder Tabellenfunktionen doch eine gro&szlig;e St&uuml;tze bei der SQL Server-Programmierung. Au&szlig;erdem haben sie durchaus auch Einfluss auf die Ausf&uuml;hrungszeiten Ihrer SQL-Abfragen. Wobei dieser Einfluss nicht immer ein positiver sein muss.<\/p>\n<p><b>Performance<\/b><\/p>\n<p>Die gute Nachricht zum Anfang: benutzerdefinierte Funktionen werden vom SQL Server wie gespeicherte Prozeduren oder Trigger behandelt, das hei&szlig;t, dass auch bei der Ausf&uuml;hrung einer benutzerdefinierten Funktion der bereits erstellte Ausf&uuml;hrungsplan wiederverwendet wird.<\/p>\n<p>Benutzerdefinierte Funktionen nutzen also dieselben Performancevorteile wie gespeicherte Prozeduren und Trigger. <\/p>\n<p>Die gute Nachricht kann auch gleichzeitig eine schlechte sein. Der Ausf&uuml;hrungsplan f&uuml;r die benutzerdefinierte Funktion wird ohne R&uuml;cksicht darauf erstellt, wo und in welchem Kontext sie verwendet wird. <\/p>\n<p>Der Abfrageoptimierer erstellt somit f&uuml;r eine gespeicherte Prozedur, in der eine benutzerdefinierte Funktion verwendet wird, keinen gemeinsamen Ausf&uuml;hrungsplan, sondern einen f&uuml;r die benutzerdefinierte Funktion und einen f&uuml;r die gespeicherte Prozedur. Dadurch werden eventuell einige Optimierungsm&ouml;glichkeiten nicht ber&uuml;cksichtigt.<\/p>\n<p>W&auml;re der Quellcode der benutzerdefinierten Funktion in der gespeicherten Prozedur enthalten, w&uuml;rde der Abfrageoptimierer nur einen und wohl auch einen komplett anderen Ausf&uuml;hrungsplan erstellen.<\/p>\n<p>Bei der Verwendung von benutzerdefinierten Funktionen sollte noch ein weiterer Aspekt beachtet werden. Skalarfunktionen, die als Spalte oder in <b>WHERE<\/b>-Bedingungen verwendet werden, werden pro Datensatz ausgef&uuml;hrt.<\/p>\n<p>Dies gilt auch dann, wenn der Skalarfunktion immer derselbe Parameterwert &uuml;bergeben wird und sie demzufolge immer dasselbe Ergebnis liefert. Dies mag sich bei geringer Datenmenge noch nicht bemerkbar machen, bei zunehmender Datenmenge jedoch wird die Ausf&uuml;hrung der SQL-Anweisung immer langsamer.<\/p>\n<p>Sie sollten also vor Verwendung einer benutzerdefinierten Funktion darauf achten, welche Verarbeitungen in der Funktion vollzogen werden, und diese gegebenenfalls auf eine andere Art und Weise nutzen. <\/p>\n<p>Bei folgender Anweisung wird die Ermittlung des aktuellen Datums pro Datensatz der Tabelle <b>dbo.Order Details<\/b> ausgef&uuml;hrt. <\/p>\n<pre>SELECT * FROM dbo.Orders\r\nWHERE OrderDate &lt;= dbo.sfAktuellerTag(getdate())<\/pre>\n<p>Dies ist eigentlich unn&ouml;tig, denn die Skalarfunktion liefert in diesem Fall immer denselben Wert. Das aktuelle Datum kann genauso gut vorab ermittelt und in einer Variablen gespeichert werden, die wiederum in der <b>SELECT<\/b>-Anweisung verwendet wird.<\/p>\n<pre>DECLARE @AktuellerTag datetime\r\nSET @AktuellerTag = dbo.sfAktuellerTag(getdate())\r\nSELECT * FROM dbo.Orders WHERE OrderDate &lt;= @AktuellerTag<\/pre>\n<p>Besonders vorsichtig sollten Sie sein, wenn Sie benutzerdefinierte Funktionen auf der Seite der Spalten innerhalb einer <b>WHERE<\/b>-Bedingung verwenden. <\/p>\n<p>Mit folgender Anweisung werden die Bestellungen anhand einer Artikelbezeichnung &uuml;ber die Skalarfunktion <b>dbo.sfProduktBezeichnung<\/b> ermittelt:<\/p>\n<pre>SELECT * FROM dbo.[Order Details]\r\nWHERE dbo.sfProduktBezeichnung(dbo.[Order Details].ProductId) = &euro;&#154;Chai&euro;<\/pre>\n<p>Die benutzerdefinierte Funktion wird pro Datensatz der Tabelle <b>dbo.Order Details<\/b> ausgef&uuml;hrt. Auch hier ist es wie bei dem vorangegangenen Beispiel sinnvoller, den Wert vor der Abfrage zu ermitteln und in einer Variablen zu speichern, die dann in der Abfrage verwendet wird.<\/p>\n<p>Dabei wird auf den Einsatz der Skalarfunktion verzichtet und der Quellcode dieser benutzerdefinierten Funktion zur Ermittlung des Werts verwendet:<\/p>\n<pre>DECLARE @ProduktId int\r\nSELECT @ProduktId = ProductId FROM dbo.Products WHERE ProductName = &euro;&#154;Chai&euro;\r\nSELECT * FROM dbo.[Order Details] WHERE ProductId = @ProduktId<\/pre>\n<p>Besonders drastisch werden die Performanceeinbu&szlig;en, wenn Sie auf beiden Seiten, also auf der Seite der Spalten wie auf der Seite der Filterbedingung Skalarfunktionen verwenden. Beide Funktionen werden pro Datensatz ausgef&uuml;hrt, was zu drastischen Performanceeinbu&szlig;en f&uuml;hren kann.<\/p>\n<p>Die Beispiele zeigen, dass es in manchen F&auml;llen sinnvoll ist, benutzerdefinierte Funktionen nicht direkt in <b>SELECT<\/b>-Anweisungen zu verwenden oder komplett auf ihren Einsatz zu verzichten. <\/p>\n<p>Nat&uuml;rlich hei&szlig;t das jetzt nicht, dass Sie keine benutzerdefinierten Funktionen einsetzen sollen, jedoch sollten Sie sich bei ihrem Einsatz dar&uuml;ber im Klaren sein, welche Datenmengen ermittelt und welche Verarbeitungen durch die Funktionen ausgef&uuml;hrt werden.<\/p>\n<p>So weit zu den benutzerdefinierten Funktionen mit ihren positiven und negativen Auswirkungen bei der SQL Server-Programmierung. Doch wie sieht es aus mit Access Wie k&ouml;nnen die benutzerdefinierten Funktionen in Access verwendet werden Immerhin bieten sich die Tabellen- und Inlinefunktionen als &#8222;parametrisierbare&#8220; Sichten f&uuml;r einen Einsatz in Access geradezu an.<\/p>\n<p><b>Benutzerdefinierte Funktionen und Access<\/b><\/p>\n<p>Die M&ouml;glichkeiten, wie benutzerdefinierte Funktionen in Access verwendet werden k&ouml;nnen, h&auml;ngen vom Format der Access-Datenbank ab. <\/p>\n<p>Bei einer ADP verwenden Sie die Objekte der SQL Server-Datenbank nicht in Access, sondern &uuml;ber Access, das hei&szlig;t, Sie sprechen die SQL Server-Objekte direkt an. Aus diesem Grund k&ouml;nnen Sie die benutzerdefinierten Funktionen wie die gespeicherten Prozeduren und Sichten in den Access-Objekten &#8211; Formulare, Berichte, Controls &#8211; unmittelbar verwenden. In Bild 4 sehen Sie die Beispielfunktion <b>dbo.ifArtikelEinerKategorie<\/b> als Datenherkunft f&uuml;r ein Formular.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_01\/UDF-web-images\/pic03_opt.jpeg\" alt=\"pic03.TIF\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 3: Die erweiterte Skalarfunktion<\/span><\/b><\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_01\/UDF-web-images\/pic04_opt.jpeg\" alt=\"pic04.TIF\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 4: Eine Inlinefunktion als Datenherkunft<\/span><\/b><\/p>\n<p>In einer MDB dagegen ist dies nicht so einfach m&ouml;glich, da die Jet-Engine die benutzerdefinierten Funktionen nicht als Tabellen einbinden kann. <\/p>\n<p>Auch der Weg &uuml;ber die Pass-Through-Abfrage ist nicht wirklich zufriedenstellend. Dort k&ouml;nnen Sie die Tabellen- und Inlinefunktionen nur als Tabellen beziehungsweise Sichten und die Skalarfunktionen nur als Spalten oder in <b>WHERE<\/b>-Bedingungen verwenden. Aber eben nicht direkt, sondern immer nur in Verbindung mit einer SQL-Anweisung.<\/p>\n<p>Nat&uuml;rlich ist das Speichern von SQL-Anweisungen in einer Pass-Through-Abfrage eine Variante, aber denken Sie an die Empfehlung zu Pass-Through-Abfragen aus dem Beitrag <b>Gespeicherte Prozeduren<\/b> (s. Shortlink 626):<\/p>\n<p>In Pass-Through-Abfragen sollten Sie aus Gr&uuml;nden der Performance keine SQL-Anweisungen, sondern gespeicherte Prozeduren verwenden. <\/p>\n<p>Insofern packen Sie Ihre SQL-Anweisungen, die die benutzerdefinierten Funktionen verwenden, in gespeicherte Prozeduren und rufen diese per Pass-Through-Abfragen auf. <\/p>\n<p><b>Fazit<\/b><\/p>\n<p>Benutzerdefinierte Funktionen erg&auml;nzen die M&ouml;glichkeiten der SQL Server-Programmierung optimal. Sie sind flexibel einsetzbar: in einfachen SQL-Anweisungen und Sichten &uuml;ber gespeicherte Prozeduren und Trigger bis hin zu Einschr&auml;nkungen und Standardwerten. Au&szlig;erdem bieten die drei Typen unterschiedliche M&ouml;glichkeiten, Programmlogik zu kapseln und wiederzuverwenden. <\/p>\n<p>Ob als &#8222;parametrisierte&#8220; Sicht per Tabellen-, Inline- oder als Skalarfunktion, in <b>WHERE<\/b>-Bedingungen beziehungsweise als Spalte in <b>SELECT<\/b>-Anweisungen oder zur Ermittlung von Standardwerten oder Pr&uuml;fung von Einschr&auml;nkungen:Es gibt kaum einen Bereich, f&uuml;r den Sie benutzerdefinierte Funktionen nicht verwenden k&ouml;nnen &#8211; also: Probieren Sie es aus!<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>tfMitarbeiterHierarchie.sql<\/p>\n<p>ifArtikelEinerKategorie.sql<\/p>\n<p>sfAktuellerTag.sql<\/p>\n<p>sfBerechnePositionSumme.sql<\/p>\n<p>sfProduktBezeichnung.sql<\/p>\n<p>Suedsturm_Backup4.sql<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/{C4A4F009-A1E1-4123-97BB-C1278AC951DE}\/aiu_648.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8222;Die drei von der Tankstelle&#8220;, &#8222;Drei Engel f&uuml;r Charlie&#8220; und &#8222;Die drei Fragezeichen&#8220; haben eines gemeinsam: Es sind immer drei. Drei, von denen jeder seine besonderen F&auml;higkeiten hat und drei, die sich perfekt erg&auml;nzen. So ist es auch beim SQL Server. Neben den gespeicherten Prozeduren und Triggern bietet der SQL Server mit den Benutzerdefinierten Funktionen eine dritte Komponente an, mit der Programmlogik gespeichert und wiederverwendet werden kann. Und weil aller guten Dinge nun mal drei sind, gibt es die Benutzerdefinierten Funktionen auch gleich in drei verschiedene Typen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[66012009,662009,44000022],"tags":[],"class_list":["post-55000648","post","type-post","status-publish","format-standard","hentry","category-66012009","category-662009","category-SQL_Server_und_Co"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Benutzerdefinierte Funktionen im MS SQL Server - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Benutzerdefinierte Funktionen im MS SQL Server\" \/>\n<meta property=\"og:description\" content=\"&quot;Die drei von der Tankstelle&quot;, &quot;Drei Engel f&uuml;r Charlie&quot; und &quot;Die drei Fragezeichen&quot; haben eines gemeinsam: Es sind immer drei. Drei, von denen jeder seine besonderen F&auml;higkeiten hat und drei, die sich perfekt erg&auml;nzen. So ist es auch beim SQL Server. Neben den gespeicherten Prozeduren und Triggern bietet der SQL Server mit den Benutzerdefinierten Funktionen eine dritte Komponente an, mit der Programmlogik gespeichert und wiederverwendet werden kann. Und weil aller guten Dinge nun mal drei sind, gibt es die Benutzerdefinierten Funktionen auch gleich in drei verschiedene Typen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-22T22:20:54+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg01.met.vgwort.de\/na\/bfe0a340b3e148418b0b71cc56d30322\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"22\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Benutzerdefinierte Funktionen im MS SQL Server\",\"datePublished\":\"2020-05-22T22:20:54+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\\\/\"},\"wordCount\":4035,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/bfe0a340b3e148418b0b71cc56d30322\",\"articleSection\":[\"1\\\/2009\",\"2009\",\"SQL Server und Co.\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\\\/\",\"name\":\"Benutzerdefinierte Funktionen im MS SQL Server - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/bfe0a340b3e148418b0b71cc56d30322\",\"datePublished\":\"2020-05-22T22:20:54+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/bfe0a340b3e148418b0b71cc56d30322\",\"contentUrl\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/bfe0a340b3e148418b0b71cc56d30322\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Benutzerdefinierte Funktionen im MS SQL Server\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Benutzerdefinierte Funktionen im MS SQL Server - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/","og_locale":"de_DE","og_type":"article","og_title":"Benutzerdefinierte Funktionen im MS SQL Server","og_description":"\"Die drei von der Tankstelle\", \"Drei Engel f&uuml;r Charlie\" und \"Die drei Fragezeichen\" haben eines gemeinsam: Es sind immer drei. Drei, von denen jeder seine besonderen F&auml;higkeiten hat und drei, die sich perfekt erg&auml;nzen. So ist es auch beim SQL Server. Neben den gespeicherten Prozeduren und Triggern bietet der SQL Server mit den Benutzerdefinierten Funktionen eine dritte Komponente an, mit der Programmlogik gespeichert und wiederverwendet werden kann. Und weil aller guten Dinge nun mal drei sind, gibt es die Benutzerdefinierten Funktionen auch gleich in drei verschiedene Typen.","og_url":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-22T22:20:54+00:00","og_image":[{"url":"http:\/\/vg01.met.vgwort.de\/na\/bfe0a340b3e148418b0b71cc56d30322","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"22\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Benutzerdefinierte Funktionen im MS SQL Server","datePublished":"2020-05-22T22:20:54+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/"},"wordCount":4035,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/#primaryimage"},"thumbnailUrl":"http:\/\/vg01.met.vgwort.de\/na\/bfe0a340b3e148418b0b71cc56d30322","articleSection":["1\/2009","2009","SQL Server und Co."],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/","url":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/","name":"Benutzerdefinierte Funktionen im MS SQL Server - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/#primaryimage"},"thumbnailUrl":"http:\/\/vg01.met.vgwort.de\/na\/bfe0a340b3e148418b0b71cc56d30322","datePublished":"2020-05-22T22:20:54+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/#primaryimage","url":"http:\/\/vg01.met.vgwort.de\/na\/bfe0a340b3e148418b0b71cc56d30322","contentUrl":"http:\/\/vg01.met.vgwort.de\/na\/bfe0a340b3e148418b0b71cc56d30322"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Benutzerdefinierte_Funktionen_im_MS_SQL_Server\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Benutzerdefinierte Funktionen im MS SQL Server"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000648","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55000648"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000648\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55000648"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55000648"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55000648"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}