{"id":55000626,"date":"2008-10-01T00:00:00","date_gmt":"2021-02-11T21:22:26","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=626"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Gespeicherte_Prozeduren","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/","title":{"rendered":"Gespeicherte Prozeduren"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg04.met.vgwort.de\/na\/06492b981ffc47d09164ee9959031380\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>&#8222;Oh &#8211; by the way: The same procedure as last year, Miss Sophie&#8220; &#8222;The same procedure as every year, James.&#8220; Auch der SQL Server bietet Procedures: Stored Procedures. Und wie auch Miss Sophie greift der SQL Server gerne auf altbew&auml;hrte Procedures zur&uuml;ck &#8211; nat&uuml;rlich weitaus &ouml;fter als nur einmal im Jahr und auch nicht immer nur auf ein und dieselbe Weise. Im Gegenteil: Sie k&ouml;nnen f&uuml;r die Verwaltung und Aufbereitung Ihrer Daten mehrere Stored Procedures in Ihrer Datenbank anlegen und diese immer wieder verwenden. Das sollten Sie auch ausgiebig tun, denn gerade Stored Procedures bieten das meiste Potenzial, wenn es um Geschwindigkeit, Datenkonsistenz und die Implementation von Gesch&auml;ftslogik geht.<\/b><\/p>\n<p>Eine Stored Procedure ist nichts anderes als eine Prozedur, in der, &auml;hnlich einer VBA-Funktion, mehrere Anweisungen &#8211; hier nat&uuml;rlich SQL-Anweisungen &#8211; gespeichert werden. Daher auch der Name <b>Stored Procedure <\/b>(zu deutsch: gespeicherte Prozedur). <\/p>\n<p>Warum aber sollten SQL-Anweisungen auf dem SQL Server gespeichert werden Immerhin k&ouml;nnen die SQL-Anweisungen doch im Frontend wunderbar nach den dort gegebenen Umst&auml;nden zur Laufzeit zusammengestellt und ausgef&uuml;hrt werden. Die Antwort auf diese Frage lautet: Geschwindigkeit.<\/p>\n<p><b>Geschwindigkeit<\/b><\/p>\n<p>Bevor der SQL Server eine SQL-Anweisung ausf&uuml;hrt, pr&uuml;ft er zun&auml;chst die Syntax der SQL-Anweisung. Zu dieser Syntaxpr&uuml;fung geh&ouml;rt nicht nur die Kontrolle der Syntax der einzelnen Befehle, sondern es wird auch die Existenz der dort angegebenen SQL Server-Objekte, wie Tabellen, Sichten und deren Spalten, gepr&uuml;ft. Diese Syntaxpr&uuml;fung erfolgt vor jeder Ausf&uuml;hrung der SQL-Anweisung. <\/p>\n<p>Nach der Syntaxkontrolle wird die SQL-Anweisung zun&auml;chst kompiliert, das hei&szlig;t, es wird ein Ausf&uuml;hrungsplan f&uuml;r die Ermittlung der Daten durch den Abfrageoptimierer erstellt. Dieser Ausf&uuml;hrungsplan ist mit einer Wegbeschreibung vergleichbar. Er enth&auml;lt die Reihenfolge, in der etwa die Tabellen der SQL-Anweisung gelesen oder welche Indizes benutzt werden. Anhand dieses Ausf&uuml;hrungsplans wird die SQL-Anweisung ausgef&uuml;hrt. <\/p>\n<p>Auch bei der Ausf&uuml;hrung einer gespeicherten Prozedur wird zun&auml;chst eine Syntaxkontrolle durchgef&uuml;hrt und ein Ausf&uuml;hrungsplan erstellt. Doch im Gegensatz zur SQL-Anweisung nicht bei jeder, sondern nur bei der ersten Ausf&uuml;hrung. Denn der Ausf&uuml;hrungsplan wird im sogenannten Prozedurcache &#8211; also im Arbeitsspeicher &#8211; abgelegt. Bei der n&auml;chsten Ausf&uuml;hrung entfallen Syntaxkontrolle und Kompilieren der gespeicherten Prozedur. Der SQL Server greift direkt auf den Ausf&uuml;hrungsplan im Arbeitsspeicher zu. Und das macht die Ausf&uuml;hrung von gespeicherten Prozeduren schnell &#8211; sehr schnell.<\/p>\n<p>Aber nicht nur die Geschwindigkeit ist ein Trumpf der gespeicherten Prozeduren. Mit gespeicherten Prozeduren k&ouml;nnen Sie auch die Datenkonsistenz und das Einhalten von Gesch&auml;ftsregeln gew&auml;hrleisten.<\/p>\n<p class=\"zwischen-berschrift-oberer-spaltenrand\">Gesch&auml;ftslogik und Datenkonsistenz<\/p>\n<p>Durch die M&ouml;glichkeit, mehrere SQL-Anweisungen &#8211; ob SELECT, UPDATE, INSERT oder DELETE &#8211; in einer gespeicherten Prozedur zu hinterlegen, sind diese pr&auml;destiniert f&uuml;r die Umsetzung der Gesch&auml;ftslogik auf dem SQL Server. <\/p>\n<p>Der Vorteil liegt auf der Hand &#8211; oder besser gesagt auf dem SQL Server: Egal mit welchem Frontend die Daten der Datenbank verwaltet oder ausgewertet werden, sofern die Verarbeitung &uuml;ber gespeicherte Prozeduren stattfindet, werden immer dieselben Algorithmen beziehungsweise Regeln f&uuml;r die Auswertungen oder Datenmanipulationen verwendet. An diesen Regeln gibt es kein Vorbei. <\/p>\n<p>Nat&uuml;rlich gibt es gewitzte Benutzer, die durchaus in der Lage sind, die Daten einer Tabelle &uuml;ber eine ODBC- oder OLEDB-Verbindung zu lesen oder gar zu &auml;ndern. Doch auch dies kann mit gespeicherten Prozeduren verhindert werden. Hier kommt das Rechtekonzept des SQL Servers ins Spiel: Sie nehmen den Benutzern jegliche Rechte an den Tabellen. Die Benutzer d&uuml;rfen die Daten einer Tabelle weder lesen, &auml;ndern oder l&ouml;schen noch neue Datens&auml;tze hinzuf&uuml;gen. Diese Aktionen sind nur &uuml;ber entsprechende gespeicherte Prozeduren m&ouml;glich, f&uuml;r deren Ausf&uuml;hrung die Benutzer die notwendigen Rechte haben. Eine Datenmanipulation direkt in den Tabellen &uuml;ber eine x-beliebige ODBC- oder OLEDB-Schnittstelle ist mit diesem Konzept nicht mehr m&ouml;glich. Vielmehr k&ouml;nnen die Daten nur &uuml;ber die in den gespeicherten Prozeduren hinterlegten Regeln und Algorithmen der Gesch&auml;ftslogik ver&auml;ndert und ausgewertet werden. K&ouml;nnen Sie sich eine bessere Methode zur Gew&auml;hrleistung der Datenkonsistenz vorstellen<\/p>\n<p>Nun sind Gesch&auml;ftsregeln nicht gerade ein Fels in der Brandung im &#8222;Daily Business&#8220;. Gesch&auml;ftsregeln werden st&auml;ndig modernisiert, verbessert und neuen Gegebenheiten angepasst. Das bedeutet st&auml;ndige Anpassungen von bestehender Programmlogik beziehungsweise von Programmcode. Sofern Sie die Regeln und Algorithmen zur Datenaufbereitung beziehungsweise Datenverarbeitung in gespeicherten Prozeduren gekapselt haben, m&uuml;ssen Sie nicht zig Frontends an die neuen Regeln anpassen, sondern lediglich die betroffenen gespeicherten Prozeduren. Das Frontend bleibt von solchen &auml;nderungen weitgehend unber&uuml;hrt. Lediglich bei &auml;nderungen in der Parameter&uuml;bergabe einer gespeicherten Prozedur muss diese im Frontend angepasst werden.<\/p>\n<p>Dasselbe gilt f&uuml;r eine nachtr&auml;gliche &auml;nderung des Datenbankdesigns &#8211; was bei einer Datenbankentwicklung nat&uuml;rlich nie vorkommt. Falls dieser seltene Fall doch mal eintreten sollte, m&uuml;ssen nur die gespeicherten Prozeduren angepasst werden, die die Daten der betroffenen Tabellen auswerten beziehungsweise verwalten. <\/p>\n<p>Sie sehen, mit gespeicherten Prozeduren haben Sie nicht nur Geschwindigkeitsvorteile, sondern auch eine gesunde Datenkonsistenz. Um jetzt noch in den Genuss von schnellen und stringenten gespeicherten Prozeduren zu kommen, m&uuml;ssen Sie nur eines tun: Sie m&uuml;ssen die gespeicherten Prozeduren schreiben. <\/p>\n<p><b>Gespeicherte Prozeduren<\/b><\/p>\n<p>Gespeicherte Prozeduren werden in T-SQL geschrieben. Diese Sprache ist die &#8222;Programmier&#8220;-Sprache des SQL Servers. Programmier-Sprache ist eigentlich etwas zu hoch gegriffen, denn T-SQL ist doch sehr spartanisch, was seine M&ouml;glichkeiten betrifft. F&uuml;r Datenauswertungen beziehungsweise -manipulationen jedoch ist T-SQL absolut ausreichend und &#8211; bei aller Diskussion &uuml;ber M&ouml;glichkeiten, .NET innerhalb von gespeicherten Prozeduren verwenden zu k&ouml;nnen &#8211; auch weiterhin die schnellste Variante, Daten auf dem SQL Server zu verarbeiten. Und es kommen mit jeder neuen SQL Server-Version neue T-SQL-Befehle dazu.<\/p>\n<p>T-SQL bietet das Notwendigste, um Daten strukturiert zu verarbeiten. <\/p>\n<ul>\n<li class=\"aufz-hlung\">Sie k&ouml;nnen Eingabe- und Ausgabeparameter mit und ohne Standardwerte definieren.<\/li>\n<li class=\"aufz-hlung\"> Sie k&ouml;nnen Variablen deklarieren und nutzen.<\/li>\n<li class=\"aufz-hlung\"> Sie k&ouml;nnen Systemwerte abfragen, wie die Anzahl der ge&auml;nderten Datens&auml;tze, Fehler usw.<\/li>\n<li class=\"aufz-hlung\"> Sie k&ouml;nnen <b>IF&#8230;ELSE<\/b>-Anweisungen durchf&uuml;hren.<\/li>\n<li class=\"aufz-hlung\"> Sie k&ouml;nnen Schleifen programmieren &#8211; was Sie bitte nur dann tun, wenn es nicht anders geht.<\/li>\n<li class=\"aufz-hlung\"> Sie k&ouml;nnen Zwischenergebnisse in tempor&auml;ren Tabellen beziehungsweise in <b>Table<\/b>-Variablen speichern.<\/li>\n<li class=\"aufz-hlung\"> Sie k&ouml;nnen gespeicherte Prozeduren innerhalb von gespeicherten Prozeduren aufrufen.<\/li>\n<li class=\"aufz-hlung\"> Sie k&ouml;nnen Sichten und benutzerdefinierte Funktionen verwenden.<\/li>\n<li class=\"aufz-hlung\"> Und last but not least ist es nat&uuml;rlich auch m&ouml;glich, mit T-SQL Prozeduren zu schreiben, deren Ausf&uuml;hrung eher langsam als schnell ist. <\/li>\n<\/ul>\n<p>Der letzte Punkt ist durchaus ernst zu nehmen. Wie bei jeder Programmiersprache sollte der Programmierer auch bei T-SQL wissen, was er tut. Auch hier ist es sehr einfach, einen schlechten und aufgebl&auml;hten Code zu schreiben, der lange Verarbeitungszeiten und hohen CPU-Verbrauch produziert.<\/p>\n<p>Doch genug der Theorie. Anhand eines Beispiels werden Sie nun sehen, wie eine gespeicherte Prozedur angelegt wird. In der Northwind-Datenbank soll eine gespeicherte Prozedur namens <b>spBestellungenKundeMitAnzPos<\/b> f&uuml;r den Besitzer <b>dbo<\/b> angelegt werden. <\/p>\n<p>Dazu m&uuml;ssen Sie zun&auml;chst das SQL Server Management Studio &ouml;ffnen und dort zur Northwind-Datenbank wechseln. Innerhalb der Datenbank erweitern Sie den Zweig <b>Programmierbarkeit <\/b>und &ouml;ffnen dort mit der rechten Maustaste auf gespeicherte Prozeduren das Kontextmen&uuml;, in dem Sie den Befehl <b>Neue gespeicherte Prozedur <\/b>w&auml;hlen (siehe Bild 1). Als Ergebnis erhalten Sie eine &#8222;Prozedurerstellungsabfrage&#8220; mit der Vorlage f&uuml;r eine neue gespeicherte Prozedur.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2008_04\/GespeicherteProzeduren-web-images\/pic001_opt.jpeg\" alt=\"pic001.TIF\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 1: Eine neue gespeicherte Prozedur<\/span><\/b><\/p>\n<p>Gespeicherte Prozeduren werden mit <b>CREATE PROCEDURE <\/b>angelegt. Innerhalb dieser Anweisung m&uuml;ssen der Name der Prozedur, die Parameter und selbstverst&auml;ndlich auch die Anweisungen der Prozedur enthalten sein. <\/p>\n<p>Der Name der gespeicherten Prozedur darf keine Leerzeichen oder eckigen Klammern enthalten, wohingegen Unterstriche erlaubt sind. Jedoch steckt in der Verwendung von Unterstrichen eine kleine Performancefalle. Ihre gespeicherten Prozeduren sollten nicht mit <b>sp_<\/b> beginnen. Dieses Pr&auml;fix ist f&uuml;r die systemeigenen Prozeduren des SQL Servers vorgesehen. Es hindert Sie allerdings nichts und niemand daran, dieses Pr&auml;fix zu nutzen. Sie erhalten auch keine Fehlermeldung. Aber der SQL Server interpretiert gespeicherte Prozeduren, die mit <b>sp_<\/b> beginnen, als Systemprozeduren und sucht diese zun&auml;chst in der <b>master<\/b>-Datenbank &#8211; und erst danach in der aktuellen Datenbank.<\/p>\n<p>Zum Namen geh&ouml;rt auch der Bezeichner des Schemas. &Uuml;ber das Schema eines Objekts werden unter anderem die Zugriffsrechte verwaltet. Es w&uuml;rde jedoch den Rahmen dieses Artikels sprengen, detailliert auf die Schemata einzugehen. Um es an dieser Stelle so kurz wie m&ouml;glich zu halten: Hier ist von dem Zusatz <b>dbo<\/b> die Rede. Geben Sie vorab immer das Schema <b>dbo <\/b>bei der Erstellung von SQL Server-Objekten an, um eine einheitliche Basis f&uuml;r die Weiterentwicklung und f&uuml;r eine sp&auml;tere Konfiguration eines Berechtigungskonzepts zu haben. <\/p>\n<p>Nach der Namensgebung folgt die Definition der Parameter. Ein Parameter wird hinter dem Namen der Prozedur in Klammern definiert. Mehrere Parameter werden dabei durch Komma getrennt. Eine Prozedur muss keine, kann aber bis zu 1.024 Parameter enthalten. Jeder einzelne Parameter ist mit Namen, Datentyp und Richtung und ggf. mit einem Standardwert zu definieren. <\/p>\n<p>Die Richtung zeigt den Weg des Parameters. Es gibt Input- wie auch Output-Parameter. OUTPUT-Parameter werden mit der Erweiterung OUTPUT gekennzeichnet und geben einen Wert aus der gespeicherten Prozedur an die aufrufende Instanz zur&uuml;ck.<\/p>\n<pre>CREATE PROCEDURE spInputOutput\r\n(\r\n@InputParameter int,\r\n@OutputParameter varchar(100) OUTPUT\r\n)\r\nAS\r\nBEGIN\r\n...<\/pre>\n<p>Die Datentypen der Parameter entsprechen den Datentypen, die auch bei Tabellen verwendet werden. Jeder Parameter muss mit einem @-Zeichen beginnen. Dies gilt auch f&uuml;r jede lokale Variable, die innerhalb der gespeicherten Prozedur genutzt wird.<\/p>\n<p>Mit den lokalen Variablen sind auch schon die ersten Komponenten des eigentlichen Programmcodes einer gespeicherten Prozedur angesprochen. Der Programmcode wird &uuml;ber die Anweisung <b>AS <\/b>nach der Parameterdefinition eingeleitet.<\/p>\n<p>Lokale Variablen werden in derselben Art wie die Parameter deklariert &#8211; mit der Ausnahme, dass bei der Deklaration nicht direkt ein Wert zugewiesen werden kann. Dies ist erst seit SQL Server 2008 m&ouml;glich. Eine Initialisierung k&ouml;nnen Sie entweder in einzelnen <b>SET<\/b>-Anweisungen oder aber &#8211; bei der Initialisierung von mehreren Variablen &#8211; in einer einzigen <b>SELECT<\/b>-Anweisung durchf&uuml;hren. Letzteres ist die effektivere Methode, da hier f&uuml;r die Initialisierung der einzelnen Variablen nur eine einzige Anweisung ausgef&uuml;hrt wird. Bei <b>SET <\/b>werden die Variablen einzeln initialisiert, was auch einzelne Anweisungen zur Folge hat.<\/p>\n<pre>CREATE PROCEDURE spInputOutput\r\n(\r\n@InputParameter int,\r\n@OutputParameter varchar(100) OUTPUT\r\n)\r\nAS\r\nBEGIN\r\nDECLARE @Var1 int\r\nDECLARE @Var2 datetime\r\nSET @Var1 = 0\r\nSET @Var2 = getdate()\r\n...<\/pre>\n<p>oder<\/p>\n<pre>CREATE PROCEDURE spInputOutput\r\n(\r\n@InputParameter int,\r\n@OutputParameter varchar(100) OUTPUT\r\n)\r\nAS\r\nBEGIN\r\nDECLARE @Var1 int, @Var2 datetime\r\nSELECT @Var1 = 0, @Var2 = getdate()\r\n...<\/pre>\n<p>Innerhalb des Programmcodes stehen alle M&ouml;glichkeiten von SQL zur Verf&uuml;gung. Dazu kommen noch Programmsteuerungsbefehle wie <b>BEGIN&#8230;END<\/b>, <b>IF&#8230;ELSE<\/b>, <b>WHILE<\/b>, <b>BREAK<\/b>, <b>CONTINUE<\/b>, <b>EXECUTE<\/b>, <b>GOTO<\/b>, <b>PRINT<\/b>, <b>RETURN<\/b>, <b>WAITFOR<\/b> u.v.m.<\/p>\n<p>Jeder zusammengeh&ouml;rige Block von Anweisungen wird mit einem <b>BEGIN <\/b>und <b>END <\/b>eingekreist. Besonders bei <b>IF&#8230;ELSE<\/b>-Anweisungen sind diese <b>BEGIN&#8230;END<\/b>-Bl&ouml;cke immens wichtig, um die Verarbeitung mehrerer Anweisungen etwa im <b>IF<\/b>-Part zu kennzeichnen. <\/p>\n<pre>...\r\nIF @Var1 &gt; 0 THEN\r\n    BEGIN\r\n    SELECT @Var1\r\n    RETURN 0\r\n    END\r\nElse\r\n    BEGIN\r\n    SELECT &euro;Fehler&euro;\r\n    RETURN 1\r\n    END\r\n    ...<\/pre>\n<p>Das Ergebnis der Prozedur wird abh&auml;ngig von ihrer Art und Aufgabe zur&uuml;ckgegeben. Gespeicherte Prozeduren k&ouml;nnen zur Datenmanipulation, aber auch zur Datenaufbereitung verwendet werden. Bei der Datenaufbereitung liefern die jeweiligen <b>SELECT<\/b>-Anweisungen innerhalb der gespeicherten Prozedur die Ergebnismengen an die aufrufende Instanz. <\/p>\n<p>In beiden F&auml;llen &#8211; ob Datenaufbereitung oder Datenmanipulation &#8211; wird von der gespeicherten Prozedur ein Return-Wert vom Datentyp <b>integer <\/b>an die aufrufende Instanz zur&uuml;ckgegeben. Dieser Wert kann als Kennzeichnung, ob die gespeicherte Prozedur erfolgreich ausgef&uuml;hrt wurde oder ein Fehler eingetreten ist, weiterverwendet werden. Die Systemprozeduren des SQL Servers liefern eine <b>0 <\/b>bei einer fehlerfreien Ausf&uuml;hrung und eine <b>1<\/b>, wenn die Anweisung mit einem Fehler beendet wurde. Diese Vorgehensweise ist nicht zwingend vorgeschrieben, aber empfehlenswert. Den Return-Wert &uuml;bergeben Sie mit der Anweisung <b>RETURN<\/b>.<\/p>\n<p>Die Anweisung <b>RETURN <\/b>ist immer die letzte Anweisung, die in einer gespeicherten Prozedur ausgef&uuml;hrt wird. Sie k&ouml;nnen diese Anweisung mehrfach an beliebigen Stellen in einer gespeicherten Prozedur angeben. Sobald aber die Anweisung das erste Mal ausgef&uuml;hrt wird, ist die gespeicherte Prozedur beendet. Der nachfolgende Code wird nicht mehr ausgef&uuml;hrt. <\/p>\n<p>Jede Anweisung beziehungsweise jeder zusammengeh&ouml;rende Anweisungsblock innerhalb einer gespeicherten Prozedur sollte mit einem Semikolon abgeschlossen werden. Das Semikolon ist f&uuml;r die SQL Server-Versionen bis einschlie&szlig;lich SQL Server 2005 nicht zwingend erforderlich. Ab SQL Server 2008 aber ist ein Semikolon ein syntaktisches Muss. Je fr&uuml;her Sie sich also an das Semikolon gew&ouml;hnen, desto weniger sind Sie ab der Version 2008 auf Fehlersuche.<\/p>\n<p>So weit ein grober &Uuml;berblick zur Erstellung einer gespeicherten Prozedur. In Listing 1 sehen Sie nun die gespeicherte Prozedur <b>dbo.spBestellungenKundeMitAnzPos<\/b>, die die Bestellungen eines Kunden abh&auml;ngig von der Anzahl der Bestellpositionen auflistet.<\/p>\n<p class=\"kastentabelleheader\">Listing 1: Gespeicherte Prozedur dbo.spBestellungenKundeMitAnzPos<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">CREATE PROCEDURE [dbo].[spBestellungenKundeMitAnzPos]<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &#8212; Kundennummer des Kunden<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> @Kundennummer nchar(5), <\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &#8212; optionale Anzahl der Positionen <\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> @AnzahlPositionen int = NULL AS<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">BEGIN<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">&#8212; Verhindert detaillierte Ausgaben der einzelnen Anweisungen<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">SET NOCOUNT ON;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">&#8212; Variable f&uuml;r Fehlermeldungen<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">DECLARE @strMessage As nvarchar(1000);<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">&#8212; Pr&uuml;fung ob negativer Wert f&uuml;r Anzahl &uuml;bergeben wurde<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">IF @AnzahlPositionen &lt; 0 <\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> BEGIN<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &#8212; Meldung vorbereiten<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> SET @strMessage = &euro;&#154;Die Anzahl &gt;&gt;&gt;&euro; + Cast(@AnzahlPositionen as varchar(5)) + &euro;&#154;&lt;&lt;&lt; ist falsch.&euro;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &#8212; Meldung ausgeben<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> RAISERROR (@strMessage, 16, 1)<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &#8212; Beenden und Verlassen der Gespeicherten Prozedure mit Returnwert 1<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> RETURN 1<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> END;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">&#8212; Pr&uuml;fung, ob der Kunde in Kundentabelle existiert<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">IF NOT EXISTS (SELECT * FROM dbo.Customers WHERE CustomerId = @Kundennummer)<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &#8212; Der Kunde existiert nicht in der Kundentabelle<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> BEGIN <\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &#8212; Meldung aufbereiten<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> SET @strMessage = &euro;&#154;Der Kunde &gt;&gt;&gt;&euro; + @Kundennummer + &euro;&#154;&lt;&lt;&lt; ist nicht vorhanden.&euro;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &#8212; Meldung ausgeben<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> RAISERROR (@strMessage, 16, 1)<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &#8212; Beenden und Verlassen der Gespeicherten Prozedure mit Returnwert 1<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> RETURN 1<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> END;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">IF @AnzahlPositionen Is Null<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &#8212; Es wurde keine Anzahl Positionen &uuml;bergeben<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> BEGIN<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &#8212; Ausgabe aller Bestellungen des Kunden<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> SELECT Count(*) As Anzahl, dbo.Orders.OrderId, dbo.Orders.CustomerId, dbo.Orders.OrderDate, <\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> dbo.Orders.ShippedDate, Sum(Quantity*UnitPrice) As Brutto FROM dbo.Orders INNER JOIN dbo.[Order Details] <\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> ON dbo.Orders.OrderId = dbo.[Order Details].OrderId WHERE dbo.Orders.CustomerId = @Kundennummer<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> GROUP BY dbo.Orders.OrderId, dbo.Orders.OrderDate, dbo.Orders.ShippedDate, dbo.Orders.CustomerId<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> ORDER BY Anzahl DESC<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> END;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">ELSE<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &#8212; Es wurde eine Anzahl Positionen &uuml;bergeben<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> BEGIN<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &#8212; Ausgabe der Bestellungen des Kunden mit gleich oder mehr Positionen als in Anzahl Positionen angegeben<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> SELECT Count(*) As Anzahl, dbo.Orders.OrderId, dbo.Orders.CustomerId, dbo.Orders.OrderDate, <\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> dbo.Orders.ShippedDate, Sum(Quantity*UnitPrice) As Brutto FROM dbo.Orders INNER JOIN dbo.[Order Details] <\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> ON dbo.Orders.OrderId = dbo.[Order Details].OrderId WHERE dbo.Orders.CustomerId = @Kundennummer<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> GROUP BY dbo.Orders.OrderId, dbo.Orders.OrderDate, dbo.Orders.ShippedDate, dbo.Orders.CustomerId<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> HAVING Count(*) &gt;= @AnzahlPositionen ORDER BY Anzahl DESC<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> END;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">END;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">RETURN 0<\/p>\n<p><!--30percent--><\/p>\n<p>Die gespeicherte Prozedur zeigt einige M&ouml;glichkeiten von T-SQL. Angefangen mit der Anweisung <b>SET NOCOUNT ON<\/b>, die vermeidet, dass nicht zu jeder SQL-Anweisung, die Daten ermittelt beziehungsweise modifiziert, eine Meldung mit <b>xx rows affected<\/b> an den Client zur&uuml;ckgegeben wird. Diese sogenannten <b>DONE_IN_PROC<\/b>-Meldungen sind in den seltensten F&auml;llen f&uuml;r eine Weiterverarbeitung interessant. <\/p>\n<p>Nach dieser eher technischen Anweisung geht es nun an die Programmlogik der gespeicherten Prozedur. Als Erstes werden die Eingaben der Parameter gepr&uuml;ft. Dabei muss der Wert des Parameters <\/p>\n<pre>    <b>@AnzahlPositionen <\/b>gr&ouml;&szlig;er 0 und die &uuml;bergebene Kundennummer in der Tabelle <b>dbo.Customers <\/b>vorhanden sein.<\/pre>\n<p>Schl&auml;gt eine der Pr&uuml;fungen fehl, wird eine entsprechende Meldung mit dem Wert des jeweiligen Parameters aufbereitet und in der Variablen <b>@strMessage <\/b>gespeichert. Der Parameter <b>@AnzahlPositionen <\/b>ist ein <b>Integer<\/b>-Wert und muss daher mit dem Befehl <b>CAST <\/b>in einen alphanumerischen Wert konvertiert werden, um ihn in der alphanumerischen Variablen <b>@strMessage <\/b>speichern zu k&ouml;nnen.<\/p>\n<p>Die aufbereitete Meldung wird per <b>RAISERROR <\/b>ausgegeben. Meldungen per <b>RAISERROR <\/b>werden bei der aufrufenden Instanz als Fehler interpretiert. Nach der Ausgabe der Fehlermeldung wird die gespeicherte Prozedur mit <b>RETURN <\/b>beendet. Der Return-Wert erh&auml;lt den Wert <b>1<\/b>, um der aufrufenden Instanz die Information mitzuteilen, dass die Prozedur nicht erfolgreich ausgef&uuml;hrt wurde.<\/p>\n<p>Sofern beide Pr&uuml;fungen ein positives Ergebnis liefern, wird die Verarbeitung fortgesetzt. Ma&szlig;gebend f&uuml;r die weitere Verarbeitung ist der Wert des Parameters <b>@AnzahlPositionen<\/b>, anhand dessen die Bestellungen eines Kunden ermittelt werden. Der Wert stellt dabei die Mindestanzahl der Positionen einer Bestellung dar. Enth&auml;lt der Parameter einen Wert, werden die Bestellungen des Kunden nach diesem Wert gefiltert; enth&auml;lt der Parameter keinen Wert, werden alle Bestellungen des Kunden ausgegeben. Die Ausf&uuml;hrung einer der beiden <b>SELECT<\/b>-Anweisungen ist gleichbedeutend mit der erfolgreichen Ausf&uuml;hrung der gesamten gespeicherten Prozedur &#8211; unabh&auml;ngig davon, ob die <b>SELECT<\/b>-Anweisung Daten liefert oder nicht. Aus diesem Grund wird die gespeicherte Prozedur mit dem Return-Wert <b>0<\/b> beendet.<\/p>\n<p>Diese kleine gespeicherte Prozedur zeigt nur einige wenige M&ouml;glichkeiten von T-SQL. Es gibt nat&uuml;rlich noch einiges mehr im Bereich der T-SQL-Programmierung, was aber den Rahmen dieses Artikels sprengen w&uuml;rde. Die gespeicherte Prozedur <b>dbo.spBestellungenKundeMitAnzPos<\/b> wird mit einem Klick auf <b>Ausf&uuml;hren <\/b>im SQL Server gespeichert &#8211; sofern der Code keinen syntaktischen Fehler enth&auml;lt. Sollten noch Fehler im Code sein, erhalten Sie im unteren Bereich des Codefensters eine Fehlermeldung, die mehr oder weniger aussagekr&auml;ftig auf den Syntaxfehler hinweist. Mit einem Doppelklick auf die Fehlermeldung k&ouml;nnen Sie direkt zur fehlerhaften Zeile springen und diese korrigieren.<\/p>\n<p>Wenn Sie nach erfolgreichem Speichern der Prozedur noch weitere &auml;nderungen am Code der Prozedur vornehmen, werden Sie bei einem erneuten Klick auf <b>Ausf&uuml;hren <\/b>die Meldung bekommen, dass die gespeicherte Prozedur nicht angelegt werden kann, da sie bereits vorhanden ist. Solange am Anfang Ihres Codes die Anweisung <b>CREATE <\/b>steht, wird der SQL Server versuchen, den Code im Abfragefenster als neue gespeicherte Prozedur anzulegen. Um nachtr&auml;gliche Code-&auml;nderungen speichern zu k&ouml;nnen, m&uuml;ssen Sie den Befehl von <b>CREATE <\/b>auf <b>ALTER <\/b>&auml;ndern. Dies ist, neben dem kompletten L&ouml;schen &uuml;ber <b>DROP PROCEDURE <\/b>und erneuten <b>CREATE PROCEDURE<\/b>, der einzige Weg, den Code einer bestehenden gespeicherten Prozedur zu &auml;ndern. <\/p>\n<p>Nachdem Sie nun die gespeicherte Prozedur mit <b>Ausf&uuml;hren <\/b>im SQL Server angelegt haben, m&ouml;chten Sie diese bestimmt auch ausf&uuml;hren. Dank des optionalen Parameters <b>@AnzahlPositionen <\/b>l&auml;sst sich die neue gespeicherte Prozedur in zwei Varianten aufrufen. Entweder mit der Anzahl der Bestellpositionen, die die Bestellungen mindestens enthalten m&uuml;ssen, oder mit allen Bestellungen des angegebenen Kunden. Die Anweisung<\/p>\n<pre>    EXEC dbo.spBestellungenKundeMitAnzPos &euro;&#154;ALFKI&euro;, 10<\/pre>\n<p>liefert alle Bestellungen des Kunden <b>ALFKI <\/b>mit zehn und mehr Bestellpositionen. Die folgende Anweisung hingegen listet s&auml;mtliche Bestellungen des Kunden <b>ALFKI <\/b>auf:<\/p>\n<pre>    EXEC dbo.spBestellungenKundeMitAnzPos &euro;&#154;ALFKI&euro;<\/pre>\n<p>Erg&auml;nzend zum Beispiel der Datenaufbereitung in Listing 1 zeigt Listing 2 noch eine kleine gespeicherte Prozedur, mit der die Daten einer Tabelle modifiziert werden. Die Anforderung besteht darin, dass ein Datensatz abh&auml;ngig davon, ob er bereits existiert, ge&auml;ndert oder angelegt werden soll. Auch wenn es auf den ersten Blick etwas dreist aussieht, aber auf diese Art und Weise wird die Aufgabe &#8222;Update oder Insert&#8220; am effektivsten gel&ouml;st. Anstatt erst mit einer eigenen SELECT-Anweisung zu pr&uuml;fen, ob der Datensatz bereits vorhanden ist, und anhand des Ergebnisses ein Update oder ein Insert auszuf&uuml;hren, wird hier grunds&auml;tzlich erst ein Update ausgef&uuml;hrt. <\/p>\n<p class=\"kastentabelleheader\">Listing 2: Gespeicherte Prozedur <\/p>\n<pre>dbo.spUpdateInsertRegion<\/pre>\n<p class=\"quellcode-funktionssammlung-1-5\">CREATE PROC [dbo].[spUpdateInsertRegion]<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">\n<p class=\"quellcode-funktionssammlung-1-5\"> @RegionId int,<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> @RegionDescription nchar(50)<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">)<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">AS<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">BEGIN<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> SET NOCOUNT ON;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> DECLARE @RowCount as int<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> DECLARE @Error as int<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> UPDATE dbo.Region<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> SET RegionDescription = @RegionDescription<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> WHERE RegionID = @RegionId;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> SELECT @RowCount = @@RowCount, @Error = @@Error;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> IF @RowCount = 0 AND @Error = 0<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> BEGIN<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> INSERT INTO dbo.Region VALUES (@RegionId, @RegionDescription)<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> SELECT @RowCount = @@RowCount, @Error = @@Error<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> END;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> IF @RowCount = 0 AND @Error = 0<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> RETURN 0;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> ELSE<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> RETURN 1;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">END<\/p>\n<p>Wurden dabei Daten ge&auml;ndert, wird das Insert nicht mehr ben&ouml;tigt. Wurden jedoch keine Daten ge&auml;ndert, hei&szlig;t das, dass der Datensatz nicht vorhanden ist und das Insert ausgef&uuml;hrt werden kann.<\/p>\n<p>Im besten Fall wird hier also nur eine Anweisung &#8211; n&auml;mlich das Update &#8211; und nicht wie bei der urspr&uuml;nglichen Methode zwei Anweisungen, das Select und das Update\/Insert, ausgef&uuml;hrt. <\/p>\n<p>Ob die Update-Anweisung bereits Daten gefunden und ver&auml;ndert hat, wird durch den Systemwert <b>@@Rowcount <\/b>ermittelt. Diese Systemvariable &#8211; zu erkennen durch die beiden @-Zeichen &#8211; beinhaltet immer die Anzahl der Datens&auml;tze, die bei der letzten Anweisung ermittelt beziehungsweise manipuliert wurden. Wurden also Datens&auml;tze ge&auml;ndert, wird die Systemvariable <b>@@Rowcount <\/b>einen Wert gr&ouml;&szlig;er <b>0 <\/b>enthalten.<\/p>\n<p><b>@@RowCount <\/b>enth&auml;lt den Wert <b>0<\/b>, wenn keine Datens&auml;tze ge&auml;ndert wurden, was wiederum verschiedene Gr&uuml;nde haben kann. Entweder wurden keine Datens&auml;tze gefunden oder aber es ist beim Update ein Fehler aufgetreten. <\/p>\n<p>Die Fehlernummer des Fehlers, der bei der zuletzt ausgef&uuml;hrten Anweisung innerhalb einer gespeicherten Prozedur aufgetreten ist, wird in der Systemvariablen <b>@@Error <\/b>gespeichert. Sind nun die Werte von <b>@@RowCount <\/b>und <b>@@Error <\/b>gleich <b>0<\/b>, wurden keine Datens&auml;tze gefunden und es ist auch kein Fehler eingetreten. Ergo gibt es den Datensatz nicht und das Insert kann ausgef&uuml;hrt werden.<\/p>\n<p>Da <b>@@RowCount <\/b>und <b>@@Error <\/b>bei jeder Anweisung in der gespeicherten Prozedur neu belegt werden, ist es erforderlich, diese Werte in eigenen Variablen zu speichern, sofern die Werte weiterverarbeitet werden sollen. Abh&auml;ngig von den Werten der <b>@@RowCount<\/b>&#8211; und <b>@@Error<\/b>-Variablen wird die Prozedur als erfolgreich oder nicht erfolgreich beendet. Durch den Return-Wert erf&auml;hrt die aufrufende Instanz, ob der Datensatz verarbeitet wurde. Um den Return-Wert auszuwerten, muss der Aufruf der gespeicherten Prozedur etwas erweitert werden:<\/p>\n<pre>    DECLARE @ReturnWert as int\r\n    EXEC @ReturnWert = dbo.UpdateInsertRegion 7, &euro;&#154;Hunsrueck&euro;\r\n    SELECT @ReturnWert As AnzahlDatens&auml;tze<\/pre>\n<p>Nun ist es f&uuml;r die Entwicklung von gespeicherten Prozeduren zwar sehr hilfreich, wenn diese im SQL Server Management Studio aufgerufen werden k&ouml;nnen, aber ein solcher manueller Aufruf bringt Sie in Ihrer Access-Applikation nicht weiter. Denn eigentlich sollen die gespeicherten Prozeduren Ihre Ergebnisse an Access &uuml;bermitteln und logischerweise auch von dort aufgerufen werden.<\/p>\n<p>Doch im Gegensatz zu Tabellen und Sichten ist das Einbinden von gespeicherten Prozeduren in Access nicht direkt m&ouml;glich, sofern Sie keine Access-Projekte (ADP) verwenden &#8211; und das ist wahrscheinlich der Fall. Eine gespeicherte Prozedur kann in Access nur indirekt &uuml;ber eine sogenannte Pass-Through-Abfrage aufgerufen werden. <\/p>\n<p><b>Pass-Through-Abfragen<\/b><\/p>\n<p>Access bietet verschiedene Abfragetypen, wie die Auswahl- und Kreuztabellenabfrage zur Ausgabe von Daten oder die Tabellenerstellungs-, Aktualisierungs-, L&ouml;sch- und Anf&uuml;geabfrage zur Manipulation von Daten. Dazu kommen noch drei weitere Abfragen, die unter dem Begriff &#8222;SQL spezifisch&#8220; zusammengefasst sind: UNION, Datendefinition und Pass-Through.<\/p>\n<p>F&uuml;r keine der drei letztgenannten Abfragen steht ein Abfragedesigner zur Verf&uuml;gung. Diese Abfragen m&uuml;ssen mit SQL-Text geschrieben werden. W&auml;hrend bei der UNION- und der Datendefinitionsabfrage die SQL-Syntax von Access &#8211; also Jet-SQL &#8211; ma&szlig;gebend ist, wird bei der Pass-Through-Abfrage die SQL-Syntax des jeweiligen Backends verwendet. Und das aus gutem Grund, denn bei einer Pass-Through-Abfrage greifen Sie direkt auf das Backend zu. Daher auch der Name dieser Abfrageart: Pass Through = Durchgriff. <\/p>\n<p>Beim direkten Zugriff auf das Backend ist weder die Jet-Engine noch sind manipulierende Funktionen der OBDC-Schnittstelle beteiligt. Kein Access-Abfrageoptimierer greift dort ein und &#8222;optimiert&#8220; die Abfrage, denn anhand des in der Pass-Through-Abfrage definierten Connection-Strings wird eine Verbindung zum jeweiligen Backend &#8211; in diesem Fall zum SQL Server und der entsprechenden Datenbank &#8211; aufgebaut. &Uuml;ber diese Verbindung wird die SQL-Anweisung direkt an Ort und Stelle ausgef&uuml;hrt. Und dort wird nun mal kein Jet-SQL, sondern T-SQL verstanden. <\/p>\n<p>F&uuml;r die Entwicklung einer Pass-Through-Abfrage, die auf den SQL Server zugreift, stehen Ihnen alle M&ouml;glichkeiten von T-SQL zur Verf&uuml;gung: die Verwendung von benutzerdefinierten Funktionen, von weiteren gespeicherten Prozeduren, Table-Variablen, tempor&auml;ren Tabellen und viele mehr. Mit all diesen M&ouml;glichkeiten m&uuml;ssen Sie innerhalb Access aber ohne Unterst&uuml;tzung klarkommen, denn Access bietet Ihnen keinen Abfragedesigner oder solch moderne Entwicklungsunterst&uuml;tzung wie Syntax-Highlighting oder Syntax-Pr&uuml;fung in Echtzeit. Daher sollten Sie Ihre SQL-Anweisungen zun&auml;chst mit dem SQL Server Management Studio entwickeln, dort testen und abschlie&szlig;end lediglich in die Pass-Through-Abfrage kopieren. <\/p>\n<p>Weitaus einfacher ist es, die SQL-Anweisungen als gespeicherte Prozedur auf dem SQL Server anzulegen und diese in der Pass-Through-Abfrage aufzurufen. Nat&uuml;rlich k&ouml;nnen Sie auch den Code der gespeicherten Prozedur direkt in die Pass-Through-Abfrage eingeben, aber dann verschenken Sie einiges an Performance. Denken Sie an den bereits beschriebenen Prozedurcache. SQL-Anweisungen werden dort nicht immer zwischengespeichert und wiederverwendet, wohl aber gespeicherte Prozeduren. <\/p>\n<p>Insofern sollten Sie Pass-Through-Abfragen immer in Verbindung mit einer gespeicherten Prozedur nutzen. Diese Kombination plus die Option, Parameter an gespeicherte Prozeduren zu &uuml;bergeben, bieten eine Menge M&ouml;glichkeiten.<\/p>\n<p>Um dies zu verdeutlichen, stellen Sie sich ein Einzelformular in Access vor, mit dem Sie in den Kundendaten bl&auml;ttern k&ouml;nnen. &Uuml;ber eine Kombobox k&ouml;nnen Sie einen Kunden ausw&auml;hlen und gezielt zum zugeh&ouml;rigen Datensatz navigieren. F&uuml;r die Umsetzung einer solchen Anforderung gibt es in Access verschiedene M&ouml;glichkeiten. Die einfachste Methode besteht darin, die Kundentabelle als Datenherkunft f&uuml;r das Formular anzugeben und &uuml;ber den Wert der Kombobox die Datens&auml;tze zu filtern. Eine etwas aufwendigere Methode besteht darin, dass anhand des ausgew&auml;hlten Werts eine <b>SELECT<\/b>-Anweisung zusammengesetzt und diese als Datenherkunft verwendet wird. <\/p>\n<p>Keine dieser Varianten nutzt den Geschwindigkeitsvorteil von gespeicherten Prozeduren. Genau das Gegenteil ist der Fall, denn bei der ersten Variante wird zus&auml;tzlich noch unn&ouml;tiger Netzwerk-Traffic produziert. Die Umsetzung dieser Anforderung mittels einer gespeicherten Prozedur ist recht einfach: Sie erstellen auf dem SQL Server eine Prozedur, die den Datensatz zu einem bestimmten Kunden anhand eines &uuml;bergebenen Parameters ermittelt. Die gespeicherte Prozedur rufen Sie &uuml;ber eine Pass-Through-Abfrage auf, die wiederum als Datenherkunft f&uuml;r das Formular verwendet wird. Der in der Kombobox ausgew&auml;hlte Wert wird als Parameter an die gespeicherte Prozedur &uuml;bergeben. Die ermittelt anhand des Wertes den Datensatz zum ausgew&auml;hlten Kunden und gibt diesen &#8211; und nur diesen &#8211; an Access zur Ausgabe zur&uuml;ck.<\/p>\n<p>Das klingt zu sch&ouml;n, um wahr zu sein Ist es auch! Sie k&ouml;nnen zwar an gespeicherte Prozeduren Parameter weiterleiten, aber nicht an eine Pass-Through-Abfrage. Zumindest nicht direkt. Per VBA ist es wenigstens indirekt m&ouml;glich, Parameter an eine Pass-Through-Abfrage zu &#8222;&uuml;bergeben&#8220;. <\/p>\n<p>Das ist eine mehr als schmeichelhafte Umschreibung f&uuml;r den notwendigen Schritt, den Sie f&uuml;r eine solche &#8222;Parameter&uuml;bergabe&#8220; vornehmen m&uuml;ssen. Denn eigentlich &uuml;bertragen Sie keine Parameter, sondern Sie &auml;ndern den Quellcode der Pass-Through-Abfrage vor der Ausf&uuml;hrung dahingehend, dass Sie die bereits darin angegebenen Parameterwerte mit den neuen Werten ersetzen. Im Klartext hei&szlig;t das, dass etwa der Quellcode <\/p>\n<pre>    EXEC dbo.SelectKunde &euro;&#154;ALFKI&euro;<\/pre>\n<p>in diesen ge&auml;ndert wird:<\/p>\n<pre>    EXEC dbo.SelectKunde &euro;&#154;ERNH&euro;<\/pre>\n<p>Im Grunde genommen &uuml;bergeben Sie keinen Parameter, sondern Sie erstellen zur Laufzeit eine neue Pass-Through-Abfrage &#8211; nur unter derselben Bezeichnung. Doch das ist nicht relevant. Vielmehr ist relevant, dass die darin enthaltene gespeicherte Prozedur f&uuml;r den SQL Server &#8211; und insbesondere f&uuml;r den Prozedurcache &#8211; nicht neu ist. <\/p>\n<p>Diese Art der Parameter&uuml;bergabe k&ouml;nnen Sie bei jeder Kombination von Pass-Through-Abfragen und gespeicherten Prozeduren verwenden. Egal, ob Sie diese Kombination zur Datenausgabe nutzen oder zur Datenmanipulation wie &auml;ndern, L&ouml;schen und Hinzuf&uuml;gen von Daten. <\/p>\n<p>Apropos Datenmanipulation: Gerade bei Datenmanipulationen zeigt sich eine weitere St&auml;rke dieser Kombination. Die &auml;nderung von mehreren Datens&auml;tzen &#8211; wie beispielsweise die &auml;nderung von &#8222;Germany&#8220; in &#8222;Deutschland&#8220; in der Spalte <b>Country <\/b>der Tabelle <b>dbo.Customers <\/b>&#8211; ist mit einer gespeicherten Prozedur &uuml;ber eine Pass-Through-Abfrage viel schlanker und wesentlich schneller erledigt als &uuml;ber eine Access-Aktualisierungsabfrage.<\/p>\n<p>Bei einer Access-Aktualisierungsabfrage fordert Access zun&auml;chst alle betroffenen Datens&auml;tze vom SQL Server an. Dieser filtert die Daten nach den angegebenen Kriterien und liefert sie an Access. F&uuml;r jeden Datensatz der &uuml;bertragenen Datenmenge erstellt Access nun zun&auml;chst eine <b>SELECT<\/b>-Anweisung mit einer <b>WHERE<\/b>-Bedingung auf den Prim&auml;rschl&uuml;ssel des jeweiligen Datensatzes und f&uuml;hrt diese aus. Liefert diese <b>SELECT<\/b>-Anweisung ein Ergebnis, wird eine <b>UPDATE<\/b>-Anweisung mit einer <b>WHERE<\/b>-Bedingung auf den Prim&auml;rschl&uuml;ssel von Access erstellt und ausgef&uuml;hrt. Wohlgemerkt &#8211; diese beiden Abfragen werden pro Datensatz der bereits vom SQL Server gefilterten und von Access bereitgestellten Datens&auml;tze erzeugt und ausgef&uuml;hrt.<\/p>\n<p>Eine Pass-Through-Abfrage mit der folgenden SQL-Anweisung hingegen wird an den SQL Server &uuml;bertragen; der f&uuml;hrt die Anweisung aus und alle betroffenen Datens&auml;tze sind auf dem aktuellen Stand:<\/p>\n<p>UPDATE dbo.Customers SET Country = &euro;&#154;Deutschland&euro; WHERE Country = &euro;&#154;Germany&euro; <\/p>\n<p>Pass-Through-Abfragen eignen sich also zur Datenmanipulation wie auch zur Aufbereitung von Daten. Sofern eine Pass-Through-Abfrage Daten liefert, k&ouml;nnen Sie diese wie andere Access-Abfragen mit Tabellen und Abfragen verkn&uuml;pfen oder als Datenherkunft f&uuml;r Formulare, Berichte und Controls wie Kombo- und Listboxen nutzen. Allerdings mit einer deutlichen Einschr&auml;nkung: Die Daten einer Pass-Through-Abfrage sind schreibgesch&uuml;tzt und k&ouml;nnen nicht ge&auml;ndert werden. Insofern eignen sich Pass-Through-Abfragen f&uuml;r schreibgesch&uuml;tzte Auswertungen in Formularen und nat&uuml;rlich besonders in Berichten. <\/p>\n<p>Aber auch f&uuml;r Daten&auml;nderungen k&ouml;nnen die Daten &uuml;ber eine Pass-Through-Abfrage ermittelt werden. Denken Sie an das Beispiel mit der Kundenausgabe eines bestimmten Kunden. Sie k&ouml;nnen den durch eine Pass-Through-Abfrage ermittelten Datensatz in eine lokale Tabelle schreiben und diese als Datenherkunft f&uuml;r das Formular verwenden, mit dem Sie den Datensatz &auml;ndern. Nach der &auml;nderung lesen Sie den Datensatz aus der lokalen Tabelle und f&uuml;hren die &auml;nderung &uuml;ber eine in einer Pass-Through-Abfrage enthaltene gespeicherte Prozedur auf dem SQL Server aus. <\/p>\n<p>Die in Access gespeicherten Pass-Through-Abfragen erkennen Sie im Access-Datenbankfenster an einem kleinen Globus. Sofern die Pass-Through-Abfrage nur der Datenmanipulation dient und keine Daten liefert, wird neben dem Globus ein Ausrufezeichen angezeigt.<\/p>\n<p>Das war die Theorie &#8211; nun folgt der praktische Teil: Die bereits erstellte gespeicherte Prozedur <b>dbo.spBestellungenKundeMitAnzPos<\/b> soll in eine Pass-Through-Abfrage integriert und dann ausgef&uuml;hrt werden.<\/p>\n<p>Starten Sie Access, wechseln Sie dort zum Abfragefenster und klicken Sie auf <b>Neu <\/b>um eine neue Abfrage zu erstellen. Im Men&uuml; <b>Abfrage <\/b>w&auml;hlen Sie im Untermen&uuml; <b>SQL spezifisch <\/b>den Eintrag <b>Pass-Through <\/b>aus (siehe Bild 3). Der Abfrageeditor &auml;ndert sich zur reinen SQL-Eingabe. Dort geben Sie folgenden Ausdruck ein:<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2008_04\/GespeicherteProzeduren-web-images\/pic002_opt.jpeg\" alt=\"pic002.TIF\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 2: Das Vorlageskript zu gespeicherten Prozeduren<\/span><\/b><\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2008_04\/GespeicherteProzeduren-web-images\/pic003_opt.jpeg\" alt=\"pic003.TIF\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 3: Eine neue Pass-Through-Abfrage<\/span><\/b><\/p>\n<pre>    EXEC dbo.spBestellungenKundeMitAnzPos &euro;&#154;ALFKI&euro;, 2<\/pre>\n<p>Mit <b>EXEC <\/b>haben Sie bereits den ersten Befehl eingegeben, der in der Syntax von Jet-SQL nicht vorkommt. F&uuml;r die Ausf&uuml;hrung dieser Anweisung auf dem SQL Server fehlt noch die entsprechende ODBC-Verbindung, in der der SQL Server und die dort befindliche Datenbank sowie die Anmeldung definiert ist.<\/p>\n<p>Dazu w&auml;hlen Sie im Men&uuml; <b>Ansicht <\/b>den Befehl <b>Eigenschaften<\/b>, um den gleichnamigen Dialog zu &ouml;ffnen. Dort klicken Sie in der Option ODBC-Verbindung auf die Schaltfl&auml;che mit den drei Punkten, um die ODBC-Verbindung zu Ihrer Northwind-Datenbank auf Ihrem SQL Server auszuw&auml;hlen beziehungsweise anzulegen. Das kann eine DSN (auf dem Rechner gespeicherte ODBC-Datenquelle) sein oder auch ein kompletter Connect-String, der den ODBC-Datenquellenadministrator &uuml;berfl&uuml;ssig macht &#8211; eine DNSless Connection, in der Sie neben den Serverdaten auch den zu verwendenden Treibernamen samt optionaler Konfigurationsparameter angeben m&uuml;ssen.<\/p>\n<p>Eine Eigenschaft der Pass-Through-Abfrage und ihre Auswirkung muss an dieser Stelle unbedingt noch erw&auml;hnt werden: Mit der Option <b>Liefert Datens&auml;tze <\/b>legen Sie fest, ob die Pass-Through-Abfrage Datens&auml;tze an den Client zur&uuml;ckgibt oder ob sie Datens&auml;tze manipuliert. <\/p>\n<p>Sofern Sie die Option <b>Liefert Datens&auml;tze <\/b>auf <b>Nein <\/b>setzen, wird die Pass-Through-Abfrage keine Datens&auml;tze liefern. Auch dann nicht, wenn die darin aufgerufene gespeicherte Prozedur eigentlich Daten liefert. Durch die Einstellung erwartet Access keine Daten und zeigt sie folglich auch nicht an.<\/p>\n<p>Daf&uuml;r erhalten Sie bei jeder Pass-Through-Abfrage mit der Konfiguration <b>Liefert Datens&auml;tze <\/b>gleich <b>Nein <\/b>vor der eigentlichen Ausf&uuml;hrung die Warnmeldung, dass mit der Ausf&uuml;hrung Daten ge&auml;ndert werden k&ouml;nnten. Auch wenn die in der Pass-Through-Abfrage aufgerufene gespeicherte Prozedur keine Anweisungen zur Daten&auml;nderung enth&auml;lt.<\/p>\n<p>Nat&uuml;rlich macht die Einstellung <b>Liefert Datens&auml;tze <\/b>gleich <b>Nein <\/b>nur Sinn, wenn die Pass-Through-Abfrage eine gespeicherte Prozedur enth&auml;lt, die Daten manipuliert. So wie die Beispiel-Prozedur <b>dbo.spUpdateInsertRegion<\/b>, bei der keine Datens&auml;tze angezeigt, sondern lediglich ge&auml;ndert werden. Insofern kann f&uuml;r eine solche Pass-Through-Abfrage die Option auf <b>Nein<\/b> gesetzt werden. Sollte bei der Datenmanipulation ein Fehler auftreten, der innerhalb der gespeicherten Prozedur nicht behandelt wird, erhalten Sie auch in Access eine entsprechende Fehlermeldung. <\/p>\n<p>Doch zur&uuml;ck zur Pass-Through-Abfrage mit dem Aufruf der gespeicherten Prozedur <b>dbo.spBestellungenKundeMitAnzPos<\/b>. <\/p>\n<p>Nachdem Sie die OBDC-Verbindung konfiguriert und die Option <b>Liefert Datens&auml;tze <\/b>auf <b>Ja <\/b>belassen haben, k&ouml;nnen Sie die Abfrage mit einem Klick auf <b>Ausf&uuml;hren <\/b>starten. Das Ergebnis wird Ihnen wie bei einer &uuml;blichen Access-Auswahlabfrage im Datenblatt angezeigt (siehe Bild 4).<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2008_04\/GespeicherteProzeduren-web-images\/pic004_opt.jpeg\" alt=\"pic004.TIF\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 4: Ein erfolgreicher Durchgriff<\/span><\/b><\/p>\n<p>Wenn Sie die Pass-Through-Abfrage nun speichern, k&ouml;nnen Sie durch einen Doppelklick auf die Abfrage immer alle Bestellungen des Kunden ALFKI mit mehr als zwei Bestellpositionen sehen. Aber bestimmt interessieren Sie auch die Bestellungen anderer Kunden.<\/p>\n<p>Um diese zu sehen, m&uuml;ssen Sie lediglich die Parameterwerte der gespeicherten Prozedur &auml;ndern. Wenn Sie also beispielsweise die Bestellungen des Kunden <b>ERNSH<\/b> mit mehr als f&uuml;nf Bestellpositionen sehen m&ouml;chten, m&uuml;ssen Sie die im Code der Pass-Through-Abfrage enthaltenen Parameter vor der Ausf&uuml;hrung mit VBA &auml;ndern. <\/p>\n<p>In Listing 3 sehen Sie eine solche &#8222;Parameter&uuml;bergabe&#8220; und in Listing 4 den dazu geh&ouml;renden Aufruf.<\/p>\n<p class=\"kastentabelleheader\">Listing 3: &auml;ndern der Parameter in einer Pass-Through-Abfrage<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">Public Sub subBestellungenKundeMitAnzPos(strKunde As String, _<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> Optional intAnzahl As Integer)<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> Dim ptQRY As DAO.QueryDef<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> Set ptQRY = _<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> CurrentDb.QueryDefs(&#8222;pt_spBestellungenKundeMitAnzPos&#8220;)<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> ptQRY.Connect = &#8222;ODBC;DSN=Northwind;DATABASE=Northwind;&euro; _<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &amp; &euro;Trusted_Connection=Yes&#8220;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &euro;Abfrage liefert Datens&auml;tze<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> ptQRY.ReturnsRecords = True<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &euro;&auml;ndern der Abfrage<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> If IsNull(intAnzahl) Then<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &euro;Es wurde keine Anzahl &uuml;bergeben<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> ptQRY.SQL = &#8222;EXEC dbo.spBestellungenKundeMitAnzPos &euro;&#8220; _<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &amp; strKunde &amp; &#8222;&euro;&#8220;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> Else<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &euro;Es wurde eine Anzahl &uuml;bergeben<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> ptQRY.SQL = &#8222;EXEC dbo.spBestellungenKundeMitAnzPos &euro;&#8220; _<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> &amp; strKunde &amp; &#8222;&euro;, &#8220; &amp; intAnzahl<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> End If<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">End Sub<\/p>\n<p class=\"kastentabelleheader\">Listing 4: Aufruf einer Pass-Through-Abfrage<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">Public Function sTestMit_ERNSTH() <\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> subBestellungenKundeMitAnzPos &#8222;ERNSH&#8220;, 5<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\"> DoCmd.OpenQuery &#8222;pt_spBestellungenKundeMitAnzPos&#8220;<\/p>\n<p class=\"quellcode-funktionssammlung-1-5\">End Function<\/p>\n<p>Auf diese Art und Weise k&ouml;nnen Sie jegliche Parameter von gespeicherten Prozeduren in Pass-Through-Abfragen &auml;ndern und somit die Datenherkunft von Formularen oder Berichten konkret auf die notwendigen Datens&auml;tze eingrenzen. Gerade f&uuml;r umfangreiche Berichte oder Formulare, in denen keine Daten ge&auml;ndert werden m&uuml;ssen, ist dies der optimale Weg. <\/p>\n<p><b>Fazit<\/b><\/p>\n<p>Gespeicherte Prozeduren sind die effizienteste Art, mit der Daten auf dem SQL Server verarbeitet werden k&ouml;nnen. Durch die Wiederverwendung bereits ausgef&uuml;hrter Prozeduren direkt aus dem Prozedurcache haben diese SQL Server-Objekte einen immensen Geschwindigkeitsvorteil.<\/p>\n<p>Die Kapselung jedweder Daten&auml;nderungen beziehungsweise Datenaufbereitungen in gespeicherten Prozeduren gew&auml;hrleistet nicht nur die Einhaltung von Gesch&auml;ftsregeln, sondern auch die Datenkonsistenz.<\/p>\n<p>Etwas umst&auml;ndlich, aber durchaus lohnend, ist der Aufruf einer gespeicherten Prozedur in Access. Dies ist nur &uuml;ber Pass-Through-Abfragen oder ADO-Recordsets m&ouml;glich, die aber durch die Verlagerung der Ausf&uuml;hrung von Access zum SQL Server und der damit verbundenen besseren Performance nicht untersch&auml;tzt werden sollte.<\/p>\n<p>Der SQL Server bietet neben der gespeicherten Prozedur noch weitere Objekte an, mit denen Daten aufbereitet und manipuliert werden k&ouml;nnen: benutzerdefinierte Funktionen und Trigger.<\/p>\n<p>Diese beiden Typen und ihre Verwendung in Access sind Inhalt des n&auml;chsten Artikels dieser Reihe.<\/p>\n<table>\n<tbody>\n<tr>\n<td>\n<p class=\"kastentabelleheader\">Debuggen von gespeicherten Prozeduren<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p>Bei der F&uuml;lle von M&ouml;glichkeiten in T-SQL und in gespeicherten Prozeduren kommt nat&uuml;rlich automatisch die Frage &#8222;Kann man gespeicherte Prozeduren auch debuggen&#8220;. Ja &#8211; man kann. Aber nicht mit den Tools, die mit dem SQL Server geliefert werden &#8211; weder mit dem SQL Server Management Studio (SSMS) noch mit dem Business Intelligence Development Studio (BIDS). Das Debuggen von gespeicherten Prozeduren wird nur in Visual Studio 2005 unterst&uuml;tzt. Erst mit dem SQL Server 2008 ist das Debuggen im SSMS m&ouml;glich.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2008_04\/GespeicherteProzeduren-web-images\/pic002_opt.jpeg\" alt=\"pic002.TIF\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 2: Das Vorlageskript zu gespeicherten Prozeduren<\/span><\/b><\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>spBestellungenKundeMitAnzPos.sql<\/p>\n<p>spUpdateInsertRegion.sql<\/p>\n<p>SPs.mdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/8468B7B2-B072-4B37-A167-1B0E913DF6B2\/aiu_626.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8222;Oh &#8211; by the way: The same procedure as last year, Miss Sophie&#8220; &#8222;The same procedure as every year, James.&#8220; Auch der SQL Server bietet Procedures: Stored Procedures. Und wie auch Miss Sophie greift der SQL Server gerne auf altbew&auml;hrte Procedures zur&uuml;ck &#8211; nat&uuml;rlich weitaus &ouml;fter als nur einmal im Jahr und auch nicht immer nur auf ein und dieselbe Weise. Im Gegenteil: Sie k&ouml;nnen f&uuml;r die Verwaltung und Aufbereitung Ihrer Daten mehrere Stored Procedures in Ihrer Datenbank anlegen und diese immer wieder verwenden. Das sollten Sie auch ausgiebig tun, denn gerade Stored Procedures bieten das meiste Potenzial, wenn es um Geschwindigkeit, Datenkonsistenz und die Implementation von Gesch&auml;ftslogik geht.<\/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":[662008,66052008,44000022],"tags":[],"class_list":["post-55000626","post","type-post","status-publish","format-standard","hentry","category-662008","category-66052008","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>Gespeicherte Prozeduren - 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\/Gespeicherte_Prozeduren\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Gespeicherte Prozeduren\" \/>\n<meta property=\"og:description\" content=\"&quot;Oh - by the way: The same procedure as last year, Miss Sophie&quot; &quot;The same procedure as every year, James.&quot; Auch der SQL Server bietet Procedures: Stored Procedures. Und wie auch Miss Sophie greift der SQL Server gerne auf altbew&auml;hrte Procedures zur&uuml;ck - nat&uuml;rlich weitaus &ouml;fter als nur einmal im Jahr und auch nicht immer nur auf ein und dieselbe Weise. Im Gegenteil: Sie k&ouml;nnen f&uuml;r die Verwaltung und Aufbereitung Ihrer Daten mehrere Stored Procedures in Ihrer Datenbank anlegen und diese immer wieder verwenden. Das sollten Sie auch ausgiebig tun, denn gerade Stored Procedures bieten das meiste Potenzial, wenn es um Geschwindigkeit, Datenkonsistenz und die Implementation von Gesch&auml;ftslogik geht.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2021-02-11T21:22:26+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg04.met.vgwort.de\/na\/06492b981ffc47d09164ee9959031380\" \/>\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=\"31\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Gespeicherte_Prozeduren\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Gespeicherte_Prozeduren\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Gespeicherte Prozeduren\",\"datePublished\":\"2021-02-11T21:22:26+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Gespeicherte_Prozeduren\\\/\"},\"wordCount\":6105,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Gespeicherte_Prozeduren\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg04.met.vgwort.de\\\/na\\\/06492b981ffc47d09164ee9959031380\",\"articleSection\":[\"2008\",\"5\\\/2008\",\"SQL Server und Co.\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Gespeicherte_Prozeduren\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Gespeicherte_Prozeduren\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Gespeicherte_Prozeduren\\\/\",\"name\":\"Gespeicherte Prozeduren - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Gespeicherte_Prozeduren\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Gespeicherte_Prozeduren\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg04.met.vgwort.de\\\/na\\\/06492b981ffc47d09164ee9959031380\",\"datePublished\":\"2021-02-11T21:22:26+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Gespeicherte_Prozeduren\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Gespeicherte_Prozeduren\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Gespeicherte_Prozeduren\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg04.met.vgwort.de\\\/na\\\/06492b981ffc47d09164ee9959031380\",\"contentUrl\":\"http:\\\/\\\/vg04.met.vgwort.de\\\/na\\\/06492b981ffc47d09164ee9959031380\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Gespeicherte_Prozeduren\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Gespeicherte Prozeduren\"}]},{\"@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":"Gespeicherte Prozeduren - 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\/Gespeicherte_Prozeduren\/","og_locale":"de_DE","og_type":"article","og_title":"Gespeicherte Prozeduren","og_description":"\"Oh - by the way: The same procedure as last year, Miss Sophie\" \"The same procedure as every year, James.\" Auch der SQL Server bietet Procedures: Stored Procedures. Und wie auch Miss Sophie greift der SQL Server gerne auf altbew&auml;hrte Procedures zur&uuml;ck - nat&uuml;rlich weitaus &ouml;fter als nur einmal im Jahr und auch nicht immer nur auf ein und dieselbe Weise. Im Gegenteil: Sie k&ouml;nnen f&uuml;r die Verwaltung und Aufbereitung Ihrer Daten mehrere Stored Procedures in Ihrer Datenbank anlegen und diese immer wieder verwenden. Das sollten Sie auch ausgiebig tun, denn gerade Stored Procedures bieten das meiste Potenzial, wenn es um Geschwindigkeit, Datenkonsistenz und die Implementation von Gesch&auml;ftslogik geht.","og_url":"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/","og_site_name":"Access im Unternehmen","article_published_time":"2021-02-11T21:22:26+00:00","og_image":[{"url":"http:\/\/vg04.met.vgwort.de\/na\/06492b981ffc47d09164ee9959031380","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"31\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Gespeicherte Prozeduren","datePublished":"2021-02-11T21:22:26+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/"},"wordCount":6105,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/#primaryimage"},"thumbnailUrl":"http:\/\/vg04.met.vgwort.de\/na\/06492b981ffc47d09164ee9959031380","articleSection":["2008","5\/2008","SQL Server und Co."],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/","url":"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/","name":"Gespeicherte Prozeduren - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/#primaryimage"},"thumbnailUrl":"http:\/\/vg04.met.vgwort.de\/na\/06492b981ffc47d09164ee9959031380","datePublished":"2021-02-11T21:22:26+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/#primaryimage","url":"http:\/\/vg04.met.vgwort.de\/na\/06492b981ffc47d09164ee9959031380","contentUrl":"http:\/\/vg04.met.vgwort.de\/na\/06492b981ffc47d09164ee9959031380"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Gespeicherte_Prozeduren\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Gespeicherte Prozeduren"}]},{"@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\/55000626","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=55000626"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000626\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55000626"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55000626"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55000626"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}