{"id":444,"date":"2007-02-25T22:35:57","date_gmt":"2007-02-25T21:35:57","guid":{"rendered":"http:\/\/www.glorf.it\/blog\/2007\/02\/25\/sql-talk\/temporaere-tabellen-heute-hier-morgen-fort"},"modified":"2007-02-25T22:35:57","modified_gmt":"2007-02-25T21:35:57","slug":"temporaere-tabellen-heute-hier-morgen-fort","status":"publish","type":"post","link":"http:\/\/www.glorf.it\/blog\/2007\/02\/25\/sql-talk\/temporaere-tabellen-heute-hier-morgen-fort","title":{"rendered":"tempor&#228;re Tabellen &#8211; heute hier, morgen fort"},"content":{"rendered":"<p>Am Microsoft SQL Server gibt es drei offizielle Arten von tempor&#228;ren Tabellen, aber tats&#228;chlich sind es sogar f&#252;nf. Je nach Art der Verwendung findet sich leicht etwas passendes.<\/p>\n<p><strong>sitzungsbezogene tempor&#228;re Tabellen<\/strong><\/p>\n<p>Die lokale Tabelle wird direkt in einer Session angelegt. Beispiel:<\/p>\n<p><code lang=\"sql\">create table #localtable(<br \/>\n\tid integer identity(1,1) not null primary key,<br \/>\n\tf nvarchar(100) collate Latin1_General_CI_AS not null<br \/>\n);<\/code><\/p>\n<ul>\n<li>Die Tabelle existiert in der gesamten Verbindung (&quot;Session&quot;) und damit in allen Prozeduren, die innerhalb aufgerufen werden.<br \/>\nErst nach dem Ende der Verbindung wird die Tabelle automatisch entfernt. Es sei denn sie wird vorher explizit mit einem DROP-Befehl entfernt.<\/li>\n<li>Andere Verbindungen k&#246;nnen nicht auf die Tabelle zugreifen. Sie existiert nur &quot;lokal&quot; in dieser Session.<\/li>\n<li>Wird in einer Stored-Procedure (SP) eine gleichnamige Tabelle angelegt, dann wird dort eine eigene, unabh&#228;ngige, tempor&#228;re Tabelle mit gleichem Namen angelegt. In diesem Fall kann man nur auf die &quot;innere&quot; zugreifen. (siehe n&#228;chster Typ)<\/li>\n<li>Es ist m&#246;glich einen Index auf die Tabele zu legen und\/oder nachtr&#228;glich weitere Constraints anzulegen.<\/li>\n<\/ul>\n<p><strong>lokale tempor&#228;re Tabellen<\/strong><\/p>\n<p>Die lokale Tabelle wird in einer Stored-Procedure (oder einem anderen G&#252;ltigkeitsbereich) angelegt. Die Syntax ist genau wie beim obigen Beispiel.<\/p>\n<ul>\n<li>Die Tabelle existiert aber nur in dieser Stored-Procedure (nennen wir sie mal SP1) und allen Prozeduren, die innerhalb von SP1 aufgerufen werden.<br \/>\nNach dem Ende der Prozedur wird die Tabelle automatisch entfernt. Es sei denn sie wird vorher explizit entfernt.<\/li>\n<li>Andere Prozeduren oder Verbindungen k&#246;nnen nicht auf die Tabelle zugreifen. Sie existiert nur &quot;lokal&quot; in dieser Instanz der SP.<\/li>\n<li>Wird die Prozedur in anderen Sitzungen erneut aufgerufen, werden dort jeweils eigene, unabh&#228;ngige tempor&#228;re Tabellen angelegt.<\/li>\n<li>Es ist m&#246;glich einen Index auf die Tabele zu legen und\/oder nachtr&#228;glich weitere Constraints anzulegen.<\/li>\n<\/ul>\n<p><strong>globale tempor&#228;re Tabellen<\/strong><\/p>\n<p>Bei der globalen Tabelle ist es egal in welchem G&#252;ltigkeitsbereich sie angelegt, wird. Sie kann in allen Stored-Procedures und Funktions zugegriffen werden. F&#252;r die Syntax anbei noch ein Beispiel:<\/p>\n<p><code lang=\"sql\">create table ##globaltable(<br \/>\n\tid integer identity(1,1) not null primary key,<br \/>\n\tf nvarchar(100) collate Latin1_General_CI_AS not null<br \/>\n);<\/code><\/p>\n<ul>\n<li>Die Tabelle ist von jeder Verbindung aus zugreifbar, kann also von allen Stored-Procedures, Funktionen verwendet werden.<\/li>\n<li>Wird von einer anderen Verbindung (egal mit welchem Benutzer) versucht eine gleichnamibe Tabelle anzulegen, kommt die Fehlermeldung, dass es die Tabelle schon gibt.<\/li>\n<li>Nach dem Ende der urspr&#252;nglichen Verbindung wird die Tabelle automatisch entfernt, sofern keine andere Verbindung eine Sperre auf einen Datensatz, eine Seite oder die ganze Tabelle h&#228;lt. Nat&#252;rlich kann sie auch vorher explizit entfernt werden.<\/li>\n<li>Sobald die anderen Verbindungen auf die so eben entfernte Tabelle zuzugreifen, kommt die Meldung, dass sie nicht existiert.<\/li>\n<li>Es ist m&#246;glich einen Index auf die Tabele zu legen und\/oder nachtr&#228;glich weitere Constraints anzulegen.<\/li>\n<\/ul>\n<p>In der Praxis finde ich diese Art der Tabellen sehr unpraktisch und w&#252;rde von deren Verwendung abraten. Was hat man davon, wenn die Existenz der Tabelle so stark mit der anlegenden Verbindung zusammenh&#228;ngt, dann w&#228;re doch die sitzungsbezogene tempor&#228;re Tabelle deutlich verst&#228;ndlicher.<\/p>\n<p><strong>(normale) Tabelle in TempDB<\/strong><\/p>\n<p>Bei der normalen Tabelle in der TempDB muss man das Recht haben Tabellen anzulegen, also z.B. SysAdmin oder DdlAdmin in der TempDB sein. F&#252;r die Syntax wieder ein Beispiel:<\/p>\n<p><code lang=\"sql\">create table tempdb.dbo.mytable(<br \/>\n\tid integer identity(1,1) not null primary key,<br \/>\n\tf nvarchar(100) collate Latin1_General_CI_AS not null<br \/>\n);<\/code><\/p>\n<ul>\n<li>Die Tabelle ist von jeder Verbindung aus zugreifbar, kann also von allen Stored-Procedures, Funktionen verwendet werden.<\/li>\n<li>Die Tabelle wird erst beim n&#228;chsten Start des SQL-Servers entfernt, sofern sie nicht vorher explizit entfernt wurde.<\/li>\n<li>Es ist m&#246;glich einen Index auf die Tabele zu legen und\/oder nachtr&#228;glich weitere Constraints anzulegen.<\/li>\n<\/ul>\n<p><em>Rechte in der Praxis<\/em><\/p>\n<p>1. M&#246;glichkeit: Man kann die Benutzer, die diese Tabellen anlegen d&#252;rfen als User in der TempDB anlegen. Dass muss man allerdings nach jedem Server-Start machen, weil da die TempDB gel&#246;scht und neu aus einer Kopie der Model-Datenbank angelegt wird. Diese Benutzer bekommen dann das Recht &quot;CREATE TABLE&quot;. Dazu k&#246;nnte man sich eine Autostart-Prozedur anlegen, die die anzulegenden User aus einer eigens daf&#252;r anzulegenden Tabelle liest und anlegt.<br \/>\nNach dem Anlegen der Tabelle muss dann der Benutzer die Rechte auf die Tabelle explizit vergeben. Das alles ist umst&#228;ndlich und erfordert jede Menge Aufwand. Daf&#252;r ist es &quot;nach Vorschrift&quot;: Jeder hat nur so viele Rechte, wie er ben&#246;tigt.<br \/>\n2. M&#246;glichkeit: Man gibt der Gruppe Public in der TempDB das Recht &quot;CREATE TABLE&quot;. Auch hier schlage ich eine Autostart-Prozedur vor. Die anzulegenden Tabellen nennt man &quot;tempdb.guest.<name>&quot;. Dann darf sie automatisch jeder lesen, schreiben, allerdings auch l&#246;schen. Sicherheitskritische Daten sollte man aber in so eine Tabelle ohnehin nicht schreiben.<\/p>\n<p><strong>Tabellenvariablen<\/strong><\/p>\n<p>Und dann gibt es da noch die Tabellenvariablen. Sie funktionieren im Grunde fast genau wie lokale tempor&#228;re Tabellen<\/p>\n<p><code lang=\"sql\">DECLARE @MyTempTable table (<br \/>\n    id integer identity(1,1) not null primary key,<br \/>\n\tf nvarchar(100) collate Latin1_General_CI_AS not null);<\/code><\/p>\n<ul>\n<li>Die Tabellenvariable existiert aber nur in dieser Stored-Procedure (SP), aber nicht in den Prozeduren, die aufgerufen werden.<\/li>\n<li>Andere Prozeduren oder Verbindungen k&#246;nnen nicht auf die Tabellenvariable zugreifen. Sie existiert nur &quot;lokal&quot; in dieser Instanz der SP.<\/li>\n<li>Wird die Prozedur in anderen Sitzungen erneut aufgerufen, werden dort jeweils eigene, unabh&#228;ngige tempor&#228;re Tabellenvariablen angelegt.<\/li>\n<li>Es ist <em>nicht<\/em> m&#246;glich einen Index auf die Tabele zu legen oder nachtr&#228;glich weitere Constraints anzulegen.<\/li>\n<\/ul>\n<p><em>Collate in der Praxis<\/em><\/p>\n<p>In obigen Beispielen habe ich immer die Collation angegeben. Das ist immer dann wichtig, wenn ich nicht sicher davon ausgehen kann, dass sie Server-Default-Collation mit der Collation in &quot;meiner&quot; Datenbank &#252;bereinstimmt. Da tempor&#228;re Tabellen in der TempDb angelegt werden, wird f&#252;r Zeichenketten automatisch die Default-Collation des Servers verwendet, wenn es nicht anders angegeben wird.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Am Microsoft SQL Server gibt es drei offizielle Arten von tempor&#228;ren Tabellen, aber tats&#228;chlich sind es sogar f&#252;nf. Je nach Art der Verwendung findet sich leicht etwas passendes. sitzungsbezogene tempor&#228;re Tabellen Die lokale Tabelle wird direkt in einer Session angelegt. Beispiel: create table #localtable( id integer identity(1,1) not null primary key, f nvarchar(100) collate Latin1_General_CI_AS [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[3],"tags":[],"_links":{"self":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/posts\/444"}],"collection":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/comments?post=444"}],"version-history":[{"count":0,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/posts\/444\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/media?parent=444"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/categories?post=444"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/tags?post=444"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}