{"id":159,"date":"2006-10-14T19:46:10","date_gmt":"2006-10-14T17:46:10","guid":{"rendered":"http:\/\/www.glorf.it\/blog\/2006\/08\/13\/sql-talk\/sql-server-2005-pivoting-unpivoting"},"modified":"2007-10-19T09:47:24","modified_gmt":"2007-10-19T07:47:24","slug":"sql-server-2005-pivoting-unpivoting","status":"publish","type":"post","link":"http:\/\/www.glorf.it\/blog\/2006\/10\/14\/sql-talk\/sql-server-2005-pivoting-unpivoting","title":{"rendered":"SQL Server 2005: Pivoting &#038; Unpivoting"},"content":{"rendered":"<p>Dem Feature &quot;Pivoting\/Unpivoting&quot; stehe ich etwas zwisp&#228;ltig gegen&#252;ber: Einerseits habe ich in der Vergangenheit schon mehrfach die Anfrage von Entwicklern bekommen, wie man sowas macht (meist noch in den sp&#228;ten 90ern als wir von Btrieve auf Sybase SQL-Anywhere umstellten). Andererseits sind die zugrundeliegenden Ursachen in der Regel eine &quot;schlechte&quot; Datenmodelierung: Wert-Tabellen, wie sie ein index-sequentiellen Systemen &#252;blich waren. Ich bevorzuge echte relationale Datenmodelle. <\/p>\n<p>In den letzten Jahren habe ich aber auch erlebt, dass es mindestens eine Situation gibt, bei der man um solche Tabellen nicht rumkommt: Wenn man mit relationalen Mitteln eine Art OLAP-System nachbilden will, dann ist es sinnvoll alle m&#246;glichen &quot;Fakten&quot; in der gleichen Tabelle unterzubringen und deren Werte im gleichen Feld zu speichern. Damit kann man dann sehr einfach, sehr flexible Auswertungsm&#246;glichkeiten schaffen. Mein Kollege Michael brauchte ziemlich lange, um mich davon zu &#252;berzeugen&#8230; \ud83d\ude09<\/p>\n<p><img decoding=\"async\" id=\"image229\" src=\"http:\/\/www.glorf.it\/blog\/wp-content\/uploads\/2006\/10\/pivoting.jpg\" alt=\"Pivoting\" style=\"padding: 5px\"\/><br \/>\nDie Werte aus einer Werte-Tabelle werden in eine echte Tabellen &#252;bertragen.<br \/>\nDabei bekommen die einzelnen Attribute auch gleich sinnvolle Namen, z.B. wird &quot;attr1&quot; zu &quot;Typ&quot;, &quot;attr2&quot; zu Datum&quot; &quot;attr3&quot; zu &quot;Anzahl&quot; usw.<\/p>\n<p>Der entsprechende PIVOT-Befehl geht so:<\/p>\n<p><code lang=\"sql\">SELECT ObjectID, attr1 as Typ,<br \/>\n\tattr2 as Datum, attr3 as Anzahl,<br \/>\n\tattr4 as Dings, attr5 as Bums<br \/>\nFROM OpenSchema<br \/>\n\t\tPIVOT(\tMax(&quot;Value&quot;)<br \/>\n\t\t\tFOR Attribute IN (&quot;attr1&quot;, &quot;attr2&quot;, &quot;attr3&quot;, &quot;attr4&quot;, &quot;attr5&quot;)<br \/>\n\t\t) AS pvt<br \/>\nORDER BY ObjectID<\/code><\/p>\n<p>Wenn man das Bed&#252;rfnis hat genau den umgekehrten Weg zu gehen: aus einer normalisierten Tabelle die Ergebnisse in Form einer Wert-Tabelle zu bekommen, dann geht das mit UNPIVOT:<\/p>\n<p><code lang=\"sql\">SELECT ObjectID, Attribute, \"Value\"<br \/>\nFROM (\tSELECT ObjectID, cast(Typ as sql_variant) as attr1, cast(Datum as sql_variant) as attr2, cast(Anzahl as sql_variant) as attr3, cast(Dings as sql_variant) as attr4, cast(Bums as sql_variant) as attr5<br \/>\n\t\t\tFROM FixSchema) as &quot;Value&quot;<br \/>\n\tUNPIVOT<br \/>\n\t(<br \/>\n\t\t&quot;Value&quot;<br \/>\n\t\tFOR Attribute IN (&quot;attr1&quot;, &quot;attr2&quot;, &quot;attr3&quot;, &quot;attr4&quot;, &quot;attr5&quot;)<br \/>\n\t) AS pvt<br \/>\nORDER BY ObjectID<\/code><\/p>\n<p>Wer noch genug hat: Eine besonders gute Darstellung des Pivotierens liefert wieder mal Itzik Ben-Gan. Die Folien von seinem Vortrag &quot;Advanced T-SQL Techniques&quot; zur TechEd 2006 in Israel stehen bei <a href=\"http:\/\/www.microsoft.com\/israel\/teched\/tracks\/default.aspx\" target=\"_blank\">microsoft.com<\/a> (siehe &quot;Advanced T-SQL Techniques&quot;). Ich glaube, sie sind auch ohne seinen Text verst&#228;ndlich. Als ich ihn 2005 in London pers&#246;nlich erleben durfte, zeigte er ganz &#228;hnliche Folien. Deswegen bin ich da nicht repr&#228;sentativ.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dem Feature &quot;Pivoting\/Unpivoting&quot; stehe ich etwas zwisp&#228;ltig gegen&#252;ber: Einerseits habe ich in der Vergangenheit schon mehrfach die Anfrage von Entwicklern bekommen, wie man sowas macht (meist noch in den sp&#228;ten 90ern als wir von Btrieve auf Sybase SQL-Anywhere umstellten). Andererseits sind die zugrundeliegenden Ursachen in der Regel eine &quot;schlechte&quot; Datenmodelierung: Wert-Tabellen, wie sie ein index-sequentiellen [&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\/159"}],"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=159"}],"version-history":[{"count":0,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/posts\/159\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/media?parent=159"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/categories?post=159"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.glorf.it\/blog\/wp-json\/wp\/v2\/tags?post=159"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}