Overblog
Folge diesem Blog Administration + Create my blog
Blog von Olaf Helper

.net

SqlConnection.InfoMessage Ereignis

22. April 2011 , Geschrieben von Olaf Helper Veröffentlicht in #.NET

Wenn man im SSMS = „Microsoft SQL Server Management Studio“ im Query Editor ein T-SQL Statement ausführt, hat man im Standard immer 2 Kartenreiter als Resultat: „Ergebnisse“ und „Meldungen“. Bei einfachen Statements bekommt man unter „Meldungen“ so etwas wie „(5 Zeile(n) betroffen)“ zu sehen. Bei eher administrativen Statements wie DBCC Kommandos werden schon umfangreichere Meldungen ausgegeben und auch die Texte von benutzerdefinierten Meldungen aus PRINT Anweisungen erscheinen dort.
Durchaus informative Meldungen erhält man zum Beispiel bei BACKUP DATABASE Anweisungen; wenn man den Parameter STATS mit angibt, erhält man Fortschrittsmeldungen, wie viel Prozent des Vorganges bereits abgeschlossen sind.

Wenn man solche Kommandos per ADO.NET absetzt, wäre es praktisch, solche Meldungen empfangen zu können, um dem Benutzer ein Feedback zu geben; „Jetzt sind bereits 30% des Backup Vorganges abgeschlossen.“. Nur wie?

Das geht recht einfach über das SqlConnection.InfoMessage Ereignis; hier ein kleines Beispiel als einfache Konsolen Anwendung:

 Imports System.Data.SqlClient 
 Module InfoMessage 
  Sub Main() 
  Console.WriteLine("Start backup") 
  Using conn As New SqlConnection("Data Source=.\SQL105DEV;Initial Catalog=master;Integrated Security=True;") 
   Dim sql = "BACKUP DATABASE [AdventureWorks2008R2] " & _
"TO DISK = N'AdvWorks2K8R2.bak' " & _
"WITH NOFORMAT, INIT, NAME = N'Backup AdventureWorks2008R2' " & _
", SKIP, NOREWIND, NOUNLOAD, COMPRESSION, STATS = 10;"
  Using cmd As New SqlCommand(sql, conn) 
  AddHandler conn.InfoMessage, New SqlInfoMessageEventHandler(AddressOf OnInfoMessage) 
  conn.Open()
cmd.ExecuteNonQuery()
  End Using 
  End Using 
  Console.WriteLine("Press any key to exit.")
Console.ReadKey()
  End Sub 
  Private Sub OnInfoMessage(sender As Object, args As SqlInfoMessageEventArgs) 
  Console.WriteLine(args.Message) 
  For Each err As SqlError In args.Errors
Console.WriteLine(err.Message)
Next
  End Sub 
 End Module 

 

Ergebnis:

SqlInfoMessage.jpg

 

P.S.: Der im BACKUP Command verwendet Parameter COMPRESS war in den Versionen bis einschließlich MS SQL Server 2008 ausschließlich der Enterprise Edition vorbehalten; seit SQL Server 2008 R2 geht das auch bereits ab der Standard Edition; juhu.

Weiterlesen

Microsoft Visual Studio 2010 Express Edition - DEU

29. April 2010 , Geschrieben von Olaf Helper Veröffentlicht in #.NET

Ich hätte ja noch etwas warten können ... nun gibt es die Microsoft Visual Studio 2010 Express Editions auch als deutsche Version im Download.

Weiterlesen

Microsoft Visual Studio 2010 Express Edition - ENU

25. April 2010 , Geschrieben von Olaf Helper Veröffentlicht in #.NET

Microsoft Visual Studio 2010 ist bereits über eine Woche im RTM Status und MSDN Abonnenten können sie herunterladen, mittlerweile auch als deutsch-sprachige Version.

Die Express Edition VS 2010 mit C#, Visual Basic und Web Developer gibt es nun auch zum Download, bisher aber nur in englischer Sprache.

Ich konnte natürlich nicht abwarten, bis eine deutsch-sprachige Version verfügbar ist (wozu auch) und habe mir MS Visual Basic 2010 Express herunter geladen. Es ist wieder ein Web-Installer, der selbst 3,2 MB groß ist. Bei meiner Konfiguration wurden dann 150 MB nachgeladen, auf dem Installationsvolume werden insgesamt 2,3 GB freier Platz benötigt. Eine MS SQL Server Express Instanz kann optimional mit installiert werden; und wie die letzten Male ist es keine "gleiche Version", also kein 2008 R2, sondern 2008 mit SP1.

Auf meinem MS Vista 32-bit Rechner lief die Installation problemlos ab, allerdings war zwischendurch ein Reboot nötig.

Weiterlesen

Methoden von CLR Datentypen sind Case Sensitive

16. April 2010 , Geschrieben von Olaf Helper Veröffentlicht in #.NET

Ja, bin ich hier in C#?

 

Wem es noch nicht aufgefallen ist, die Methoden von CLR Datentypen wie Geometry oder Xml sind Case Sensitive und das unabhängig von der Collation des Microsoft SQL Server oder der aktuellen Datenbank. Man muss also die Groß-/Kleinschreibung beachten, sonst gibt es Laufzeitfehler.

 

 -- Diesesmal nicht AdventureWorks, den die 
 -- ist CaseSensitive (CS); diesmal die TempDB (CI) 
 USE [tempdb] 
 GO 
   
 -- So funktioniert es: Richtige Groß-/Kleinschreiubng 
 DECLARE @geo geometry; 
 SET @geo = geometry::STGeomFromText('POINT(1 1)', 0); 
 SELECT @geo.ToString() AS Result; 
 GO 
   
 -- Alles klein geschrieben: IntelliSense erkennt es nicht 
 -- und es gibt einen Laufzeit-Fehler.  
 -- Geometry darf hingegen groß geschrieben werden 
 DECLARE @geo geometry; 
 SET @geo = Geometry::STGeomFromText('POINT(1 1)', 0); 
 SELECT @geo.tostring() AS Result; 
 GO 
   
 -- Bei XML gilt das gleiche, wobei IntelliSense bei "value" 
 -- weder Klein- (was hier korrekt ist) noch Großschreibung 
 -- anerkennt 
 DECLARE @xml XML; 
 SET @xml = '<test attr="Hallo" />'; 
 SELECT x.value('@attr', 'varchar(5)') AS Result 
 FROM @xml.nodes('test') as s(x) 
 GO 
   
 Result 
 ------------------- 
 POINT (1 1) 
   
 (1 row(s) affected) 
   
 Msg 6506, Level 16, State 10, Line 7 
 Die 'tostring'-Methode für den 'Microsoft.SqlServer.Types.SqlGeometry'-Typ wurde in der 'Microsoft.SqlServer.Types'-Assembly nicht gefunden. 
   
 Result 
 ------ 
 Hallo 
   
 (1 row(s) affected) 
 

 

 

 

   
 ClrDatenTypenCS.jpg 
Weiterlesen

Property Getter Setter in VisualBasic.NET 2010

27. Januar 2010 , Geschrieben von Olaf Helper Veröffentlicht in #.NET

Seitdem ich das letzte Projekt in C# (jawohl, nicht VB.NET) umgesetzt habe, weiß ich die Formulierung von einfachen Properties zu schätzen.

In C# 2008:

 namespace ConsoleApplication 
 { 
  class Demo 
  { 
  string myProperty { get; private set; } 
  } 
 } 

 

In VB.NET bis Version 2008 muss man eine private lokale Variable definieren und die Property Get-Set ausformulieren, auch wenn es nur eine einfache Zuweisung & ein Return ist. Es gibt auch einen Assistenten dafür; man gibt Property ein und drückt zweimal auf <TAB> und bekommt den ein Template vorgegeben, das ebenfalls über den Assistenten vervollständig werden kann. Trotzdem bleibt es eine Fleißarbeit.

VbProperty.jpg

In Visual Basic 2010 geht es dann analog zu C# einfacher, nur wie man einen Private Setter bekommt, habe ich noch nicht raus gefunden:

 

 Public Class Class1 
   
  ' Klassisch mit lokaler privater Variable und explizit formulierten Properties 
  Private myPropertyVariable As String 
  Public Property myProperty() As String 
  Get 
  Return myPropertyVariable 
  End Get 
  Private Set(ByVal value As String) 
  myPropertyVariable = value 
  End Set 
  End Property 
   
  ' Neu in VB 2010; Getter/Setter wie in C# 
  ' Allerdings ohne die Möglichkeit zum Private Setter 
  Public Property myPropertyNeu() As String 
   
 End Class 

 

Weiterlesen

Erstes CLR Assembly für Microsoft Analysis Services (SSAS)

19. Januar 2010 , Geschrieben von Olaf Helper Veröffentlicht in #.NET

Nachdem das Erstellen und Verwenden von eigenen CLR Assemblies im Microsoft SQL Server Datenbankmodul gut funktioniert hat, wie eine eigene Aggregation oder ein Datenexport, wollte ich eigene Assemblies analog mal mit dem Microsoft Analysis Services versuchen.

Leider gibt es weniger Dokumentation zu dem Thema als für den Einsatzbereich des Datenbankmodules. Von Microsoft gibt es zum einen den TechNet Artikel User Defined Functions and Stored Procedures, der die Vorgehensweise beschreibt und dann noch einen kurzen MSDN Artikel Defining Stored Procedures.

Für ein eigenes Assembly wird zunächst das Namespace Microsoft.AnalysisServices.AdomdServer benötigt. Dieses ist natürlich nicht im GAC enthalten, man muss einen Verweis auf die Datei „msmgdsrv.dll“ setzten. Die wiederum findet man etwas versteckt im OLAP\BIN Ordner des Programm-Verzeichnisses der benannten Instanz. Zum Beispiel für meine Instanz „SQL105CTP3“ von der MSAS Version 10.5 ( = 10_50) =>

C:\Program Files\Microsoft SQL Server\MSAS10_50.SQL105CTP3\OLAP\bin\

Über die statische Klasse „Context“ kann man die Verbindungs-Kontext bezogenen Objekte und Verbindung nutzen.

Entgegen einer Assembly fürs Datenbankmodul gibt es keine spezielle Methoden-Properties wie <SqlProcedure(Name:="spNamen")>; wobei die eh optional, wenn auch sinnig sind.

Dafür arbeitet man auch nicht mit speziellen SqlTypes, sondern nur mit den normalen CLS Typen.

Ein ganz einfaches Projekt als Beispiel gibt es hier zum Download: OlafHelper.Ssas.Info

Wie immer ist es ein Microsoft Visual Basic 2008 Express Edition Projekt mit allem dabei, was nötig ist.

 Das erste Beispiel ist wirklich sehr einfach gehalten; nur um zu testen, ob es denn überhaupt funktioniert. Es sind nur ein paar Zeilen, die vom Aufbau her so aussehen: 
   
 Imports AMOS = Microsoft.AnalysisServices.AdomdServer 
   
 Namespace OlafHelper.Ssas 
   
  ''' <summary> 
  ''' CLR Assembly Beispiel für. 
  ''' </summary> 
  Partial Public NotInheritable Class Info 
   
  ''' <summary> 
  ''' Liefert den Namen des Servers der aktuellen Verbindung. 
  ''' </summary> 
  <CLSCompliant(False)> _ 
  Public Shared Function ServerName() As String 
  Return AMOS.Context.Server.Name 
  End Function 
   
  End Class 
   
 End Namespace 
Weiterlesen

Datenexport mittels einer CLR Assembly

13. Januar 2010 , Geschrieben von Olaf Helper Veröffentlicht in #.NET

Für den aufbereiteten Export von Daten aus dem Microsoft Sql Server gibt es diverse Möglichkeiten und Tools, so bietet bereits nahezu jede Report Engine die Möglichkeit, die Berichtsdaten als Excel oder PDF-Datei zu speichern. Serverbasiert ist der SSIS (MS Sql Server Integration Services) prädestiniert für diese Aufgabe, ebenso der SSRS (MS Sql Server Reporting Service).

Es gibt aber auch regelmäßig mal die Anforderung, einen Export per T-SQL Befehl ausführen zu können. Das Problem ist nur, dass man das mit T-SQL nicht wirklich gut abbilden kann. Zwar kann man mit ActiveX Objekten arbeiten (siehe Stored Procedures sp_OA…), aber das ist alles andere als komfortable.

Danke der .NET Integration und der Verwendbarkeit von CLR Assemblies im MS Sql Server ab Version 2005 geht es nun auch bequemer. Eine solche Lösung habe ich einmal für ein paar Dateiformate umgesetzt. Für alle Exportformate gilt, dass diese erste Version alle Werte einfach per .ToString() ohne weitere Formatierungsangaben oder CultureInfo umwandelt, es werden deswegen die Ländereinstellungen des Servers verwendet.

 

Entwickelt habe ich es mit Microsoft Visual Basic 2008 Express Edition, damit kann auch jeder kostenfrei an die IDE zum Öffnen und Bearbeiten des Projektes kommen. Das Projekt ist mit einer SNK (Strong Name Key) signiert (Batch zum Erstellen liegt bei), ebenso gibt es wie immer ein MS FxCop Datei dazu. Die SQL Scripte zur Anlage der Stored Procedures sowie ein Testscript liegen im Unterordner „Sql“.

Die erste Version 0.0.0.1 des Assemblies ist für mich erst mal nur die grobe Umsetzung (Proof Of Concept), die ich bisher auch nur minimal getestet habe. Zudem will ich noch andere Funktionen hinzufügen wie das Exportieren von BLOB‘s oder FileStream Dateien. Wer will, kann sich das Projekt aber schon ansehen.

Download: OlafHelper.SqlServer.Export (104 KB)

 

Hier noch ein paar Detail-Informationen dazu:

 

Parameter „multiQuery“

Alle Export Prozeduren bieten den Parameter „multiQuery“ an. Wenn der Wert True übergeben wird, werden alle Statements des Batches aus dem Parameter „sqlStatement“ ausgewertet und die Daten exportiert. Bei CSV und HTML stehen die Tabellen in einer Datei untereinander, getrennt durch eine Leerzeile; bei CSV zugegeben nicht wirklich sinnvoll. Bei ExcelXml wird je Ergebnismenge ein weiteres ExcelWorksheet erstellt.

Der wichtigere Unterschied ist aber die interne Ausführung. Wenn multiQuery = True gesetzt wird, wird ein DataSet zum Abrufen der Daten verwendet. Für Client-Anwendungen ist ein DataSet optimal, man baut eine Verbindung zum Server auf, lässt per SqlCommand das DataSet füllen und trennt die Verbindung wieder. Anschließend kann man „verbindungslos“ weiter arbeiten, bis man wieder die Änderungen übertragen will. Zudem unterstützt das DataSet mehrere Resultsets, man kann also ein Sql Batch aus mehreren Statements ausführen und erhält für jedes ein eigenes Table im DataSet. Das bedeutet aber auch, dass die Daten die ganze Zeit im Speicher gehalten werden müssen. Wie gesagt, für einen Client optimal, aber nicht „innerhalb“ des MS Sql Servers, den dann hat man de facto die Daten auf der Maschine doppelt im Speicher und das wo man doch so nahe an der Quelle ist.

Wenn multiQuery = False übergeben wird, wird intern hingegen ein SqlDataReader verwendet, der wie ein Cursor die Datensätze arbeitet und immer nur die Daten für den aktuellen Datensatz abruft. Das spart Hauptspeicher-Platz.

Dieses sollte man bedenken, wenn man multiQuery verwenden will. Für kleine Datenmenge funktioniert es problemlos, bei größeren Datenmengen kann es Speicherplatz-Probleme verursachen => Verwendung auf eigene Gefahr.

 

Format CSV

Der Export erfolgt als einfache Coma Separated Values, die Feld- und Zeilentrennzeichen kann man als Parameter an die SP übergeben.

 

Format HTML

Es wird hier eine einfache HTML Datei erstellt, die je Tabelle ein <table/> verwendet. Es wird keine gesonderte Formatierung angegeben, alle Spalten der Tabelle haben die gleiche Breite.

 

Format ExcelXML

Das neue Excel XML Format (Office Open XML), das mit Office 2007 eingeführt wurde. ist erfreulich einfach aufgebaut im XML Format. Für ältere Office Version bis zurück zu 2000 gibt es das "Compatibility Pack for Open XML", um das Fomat öffnen zu können.

Zwar gibt es mittlerweile ein Open XML SDK 2.0 for Microsoft Office, das steht aber natürlich im MS Sql Server zur Verfügung, deshalb habe ich eine eigene Klasse zum Generieren erstellt.

Im Format gibt ein paar Header Tags, je Worksheet einen weiteren Tag, in dem man die Zeilen mit <Row/> und die Zellen mit <Cell/> angibt. Es wird dabei nicht die Klasse System.Xml.XmlDocument verwendet, da diese wieder komplett im Speicher gehalten wird, sondern System.Xml.XmlWriter. Das ist von der Handhabung her nicht ganz zu bequem, dafür werden die Daten gleich in die Ausgabedatei geschrieben. Um im Fehlerfall alle Resourcen frei zu geben, wird dazu eine eigene Klasse verwendet, die IDisposable implementiert. Schließlich soll auf keinen Fall der Sql Server Dienst in Mitleidenschaft gezogen werden.

 

Format XML

Es wird eine einfache XML Datei mit dem übergeben RootNode angelegt. Die Implementierung ist analog zu ExcelXML.

 

Weiterlesen

Microsoft Visual Studio 2010 Beta SP1 als Virtual Maschine

4. Januar 2010 , Geschrieben von Olaf Helper Veröffentlicht in #.NET

Mit MS Visual Studio 2010 und dem dazu gehörendem .NET 4.0 Framework, das als Release für Februar 2010 angekündigt ist, soll es einige neu Features geben.

So sollen diverse Features aus Visual Basic in C# übergehen und umgekehrt.

 

Für alle, die diese Beta Version testen möchten, ohne den eigenen Rechner mit einer Beta „verhunzen“ wollte, bieten Microsoft im Download Center diverse Variationen von VM (Virtual Maschine) an, die man gefahrlos auf seiner RM (Real Maschine) laufen lassen kann.

Es sei aber vorgewarnt, die Downloads sind alles andere als klein; auf eine DVD passen die nicht mehr drauf.

 

Microsoft® Visual Studio® 2010 and Team Foundation Server® 2010 Beta 2 virtual image for Windows Virtual PC  (7369 MB)

Microsoft® Visual Studio® 2010 and Team Foundation Server® 2010 Beta 2 virtual image for Windows Server 2008 Hyper-V (7316 MB)

Microsoft® Visual Studio® 2010 and Team Foundation Server® 2010 Beta 2 for Microsoft® Virtual PC 2007 SP1 Image (7325 MB)

 

Voraussetzung ist Microsoft Virtual PC 2007 mit SP1 oder Hyper-V.

Als Betriebssystem läuft MS Windows Server 2008. MS Visual Studio 2010 liegt hier in der Ultimate Edition vor.

Das Passwort für die Anmeldung findet man auf einem Startfenster vor dem Logon. Es wird etwas leicht irritierend dargestellt, die Bindestriche muss man nicht mit eingeben, die dienen nur zur Trennung. Dann steht es in eckigen Klammern noch ein zweites Mal dahinter, wo die Ziffern ausgeschrieben sind. Es müssen also nur die eigentlichen 8 Buchstaben / Ziffern eingegeben werden.
Weiterlesen

SQL Statements in MS Visual Basic 2008

2. Oktober 2009 , Geschrieben von Olaf Helper Veröffentlicht in #.NET

SQL Statements in Source Code sind immer so eine Sache, was die Formatierung und den Aufbau betrifft, insbesondere bei (sehr) langen Statements.

Die einen nutzen den StringBuilder, um es zeilenweise aufzubauen. In Visual Basic gibt es noch die Alternative, mittels der Zeilenfortsetzung-Zeichen (was man sich in C# sparen kann) den String zu konkatenieren. Das ist aber auch nicht so ohne: Wenn man das Statement im Management Studio erarbeitet + getestet hat, kopiert man es in Visual Studio und darf es überarbeiten, also alles in Anführungszeichen setzen und sie eben zu verbinden. Will man irgendwann mal wieder mit dem Statement in SSMS zurück, muss man dort wieder die Anführungszeichen etc. wieder entfernen.

Mit Microsoft Visual Basic 2008 gibt es die Möglichkeit im Source Code XML direkt zu erfassen, also nicht als String, und das kann man für SQL Statements etwas „zweckentfremden“: Man erfasst ein einfaches Tag und schreibt das SQL Script als Inhalt rein:

 

 Module SqlString 
   
  Sub Main() 
  'Der klassische Weg: Als String konkateniert mit Zeilenfortsetzung 
  Dim sql As String 
  sql = "SELECT [AddressLine1] " & _ 
  ",[AddressLine2] " & _ 
  ",[City] " & _ 
  ",[PostalCode] " & _ 
  "FROM [AdventureWorks].[Person].[Address] " & _ 
  "WHERE [AddressID] = @addressId" 
   
  'Als implizites XML; ermöglicht es, das Statement direkt aus  
  'SSMS hierein und wieder zurück zu kopieren 
  Dim xml 
  xml = <sql> 
  SELECT [AddressLine1] 
  ,[AddressLine2] 
  ,[City] 
  ,[PostalCode] 
  FROM [AdventureWorks].[Person].[Address] 
  WHERE [AddressID] = @addressId 
  </sql> 
  'Klassisch kann man den String "as it" verwenden  
  Console.WriteLine(sql) 
   
  'XML Objekt als String ausgeben und die Tags abschnippel 
  'dazu muss der Tag aber immer gleich (lang) sein 
  Console.WriteLine(xml.ToString.Substring(6, xml.ToString.Length - 12)) 
   
  'Aufwendiger über XML Objekt, dafür flexibler und sicherer 
  Dim doc As New Xml.XmlDocument 
  doc.LoadXml(xml.ToString) 
  Console.WriteLine(doc.FirstChild.InnerText) 
  doc = Nothing 
   
  'Warte auf Key 
  Console.ReadKey() 
  End Sub 
   
 End Module 

 

Nun kann man bequem das Statement aus SSMS heraus und ebenso wieder zurück kopieren, ohne etwas ändern zu müssen. Dynamisch zusammen gestelltes SQL ist so nicht möglich, aber wir arbeiten ja eh immer brav & artig mit Parameter, gelle?

Das Handling ist etwas aufwendiger als über reinen String, hält sich aber in Grenzen.

Was mir nicht so gefällt sind die vielen Leerzeichen. Zwar stören sie nicht, aber sie sind ja nun unnötig und stellen zusätzlichen Traffic für die Übertragung dar; nicht viel, aber Kleinvieh mach auch Mist, vor allem wenn es häufig ausgeführt wird.

Das Ergebnis sieht so aus:

 

 SELECT [AddressLine1] ,[AddressLine2] ,[City] ,[PostalCode] FROM [AdventureWorks].[Person].[Address] WHERE [AddressID] = @addressId 
   
   
  SELECT [AddressLine1] 
  ,[AddressLine2] 
  ,[City] 
  ,[PostalCode] 
  FROM [AdventureWorks].[Person].[Address] 
   WHERE [AddressID] = @addressId 
Weiterlesen

Verborgener Schatz: Microsoft.SqlServer.SqlParser.dll

8. August 2009 , Geschrieben von Olaf Helper Veröffentlicht in #.NET

Hast Du schon man Dein Systemlaufwerk danach durchsucht, wie viele & welche DLL (Dynamic Linked Library) es so gibt?

Wenn nicht: Lass es, es gibt sprichwörtlich unendliche viele davon.

Findet man dann eine vom Namen her interessante DLL und sucht dann danach im Internet, bekommt man nicht unbedingt immer die gewünschten Infos oder gar eine umfassende Dokumentation dazu.

Das wiederum ist echt schade, denn einige dieser DLL bieten sehr interessante und gut brauchbare Funktionen; würde man die kennen, müsste man so einiges nicht selbst programmieren; wirklich echte verborgene Schätze, die da brach liegen.

 

Über einen dieser kleinen Schätze bin ich gestolpert und der hat durchaus interessante Funktionen und sich daraus ergebene Möglichkeiten.

Es ist die Microsoft.SqlServer.SqlParser.dll, die eine komplette SQL Parser Funktionalität biete. Man übergibt ein SQL Statement oder gar ganze SQL Batches und die Klasse „Parser“ analysiert es, gibt als Ergebnis die gefundenen Fehler und, was wesentlich interessanter ist, splittet die einzelne Teile des SQL Statements in einzelne Tokens auf. Diese kann man dann selbst weiter auswerten.

 

Hier der Visual Basic.NET 2008 Source Code als kleine Demo (Konsolen-Anwendung) dazu, dass das SQL Statement in meinem Sinne etwas besser automatisiert formatiert:

 

 Module SqlParserTest  
  ''' <summary>  ''' Demo zu Microsoft.SqlServer.SqlParser.dll als Konsolen-Applikation  ''' </summary>  ''' <remarks>Olaf Helper, 08.08.2009  ''' Verweis setzen auf:  ''' C:\Program Files\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\Microsoft.SqlServer.SqlParser.dll  ''' </remarks>  Sub Main()  Dim sql As String  Dim script As Microsoft.SqlServer.SqlParser.SqlCodeDom.SqlScript  Dim stringBuilder As New System.Text.StringBuilder  Dim token As Microsoft.SqlServer.SqlParser.Parser.Token  
  sql = "-- Erstes Statement völlig Valide, aber mies formatiert " & vbNewLine & _  "select [AddressID] " & _  ", [AddressLine1] " & _  ",[AddressLine2] " & _  ", [City] " & _  "fRoM [AdventureWorks].[Person].[Address] " & _  "whERe PostalCode = '98011';" & vbNewLine & _  "GO;" & vbNewLine & _  "-- Zweites Statement: So strunz fehlerhaft " & vbNewLine & _  "-- das es schon weh tut; Format auch nicht besser " & vbNewLine & _  "select * " & _  "FRoM TabelleA oder TabelleB " & _  "where Ja = Vielleicht <> Nein;"    script = Microsoft.SqlServer.SqlParser.Parser.Parser.Parse(sql)  System.Console.WriteLine("Anzahl Batches: " & script.Batches.Count.ToString)  System.Console.WriteLine("Anzahl Fehler: " & script.Errors.Count.ToString)  
  For Each token In script.Tokens  Select Case token.Id  Case 40, 41, 59, 61  'Separatoren wie ()=; die dürfen ohne Spaces sein  stringBuilder.Append(token.Text.Trim)  Case 42, 171  'Felder; die nur trimmen  stringBuilder.Append(token.Text.Trim)  Case 44, 498  'Leerbereich; hier nur max. ein Space  stringBuilder.Append(token.Text.Trim & " ")  Case 242, 287, 307  'SQL Klauseln wie SELECT FROM WHERE  'Die als UPPER in nächster Zeile   stringBuilder.Append(vbNewLine & token.Text.ToUpper(System.Globalization.CultureInfo.CurrentCulture))  Case 499  'Kommentare; in neue Zeile & keine unnötigen Spaces  stringBuilder.Append(vbNewLine & token.Text.Trim.Replace(" ", " "))  Case 501
'Batchtrenner GO; immer in neuer Zeile
stringBuilder.Append(vbNewLine & token.Text.Trim)
Case Else
'Alles andere unverändert zurückgeben
stringBuilder.Append(token.Text)
End Select Next
System.Console.WriteLine(stringBuilder.ToString)
System.Console.WriteLine("Press key to continue")
System.Console.ReadLine()
End Sub
 End Module   

Und das Ergebnis ist:

 

 -- Erstes Statement völlig Valide, aber mies formatiert
SELECT [AddressID] , [AddressLine1] , [AddressLine2] , [City]
FROM [AdventureWorks].[Person].[Address]
WHERE PostalCode = '98011';
GO;
-- Zweites Statement: So strunz fehlerhaft
-- das es schon weh tut; Format auch nicht besser
SELECT *
FROM TabelleA oder TabelleB WHERE Ja = Vielleicht <> Nein;

Der als solche auch erkannte SQL Bug ist immer noch drin, aber es ist schon durch diese einfache kleine Routine wesentlich besser formatiert. Verbesserungspotential gibt es wie immer auch hier.

 

Mmmh, das ist doch einen nette Funktionalität für ein SSMS Addin. ;-)

Wenn ich nur mehr Zeit hätte …

Weiterlesen
1 2 > >>