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

Power Pivot

24. Oktober 2009 , Geschrieben von Olaf Helper Veröffentlicht in #OLAP

Das Kind "Project Gemini" hat nun einen finallen Namen und eine eigene Website bekommen: Power Pivot.
Weiterlesen

SQL Azure und SQL Server Management Studio (SSMS)

22. Oktober 2009 , Geschrieben von Olaf Helper Veröffentlicht in #MSSQL

Es hatte lange gedauert, bis ich nicht nur einen Platz im Sql Azure Beta Programm von Microsoft bekommen habe, sondern auch eine Datenbank; das Angebot ist sehr begrenzt.

Nun habe ich aber endlich eine bekommen (na ja, vor ca. 3 Wochen) und nun auch mal etwas Zeit gefunden, mich zumindest ein wenig damit zu beschäftigen.

Die erste Umsetzung mit SDS war vom Funktionsumfang recht eingeschränkt, vergleichbar mit SimpleDB; ein einfacher Stack, auf dem man Daten ablegen und wieder abrufen kann.

Mit Sql Azure soll nahezu der volle Funktionsumfang des MS SQL Servers abgebildet werden. Man merkt es schon daran, dass man ganz normal den SqlClient von Ado.NET oder ADO verwenden kann und der ConnectionString dafür sieht fast aus, wie der für einen ganz „normalen“ SQL Server; nur das Preset tcp: ist neu.

Server=tcp:a5xxxxxxx.database.windows.net;Database=master;User ID=MeineUid;Password=MeinPwd;Trusted_Connection=False;

Noch besser ist aber, das durch diese Kompatibilität auch (fast) alle vorhandene Tools von Microsoft verwendet werden können, wie SqlCmd oder auch das SQL Server Management Studio (SSMS).

Es klappt ganz gut, es gibt aber natürlich auch Einschränkungen (soweit sie mir in der kurzen Zeit bisher aufgefallen sind):

-       Verbindung geht natürlich nur über eine Sql Account nebst strengen Passwort; klar

-       Hat man die Verbindung als „Registrierter Server“ angelegt, kann der Status nicht ermittelt werden; Sql Browser Dienst, der die Informationen bereit stellt, hätte ich eh nicht erwartet.

-       Der Server kann nicht über den „Object Explorer“ verbunden werden, es kommt eine Fehlermeldung wegen des fehlendes Objektes „sys.configuration“ (es ist eben noch kein vollständig abgebildeter MS SQL Server)

-       Man kann aber eine neue „Abfrage“ über den registrierten Server starten. In der Auswahl der vorhandenen Datenbanken werden auch alle angelegten Datenbanken angezeigt, aber man kann innerhalb einer Verbindung die Datenbank nicht wechseln. Man kann auch nicht mit USE [AndereDatenbank] wechseln, man erhält die Fehlermeldung:
Msg 40508, Level 16, State 1, Line 1
USE statement is not supported to switch between databases. Use a new connection to connect to a different Database

Das bedeutet: Man muss je Datenbank eine eigene Verbindung anlegen, in der man die gewünschte Datenbank als „Default“ Datenbank definiert, nur so geht es.

Alles im Allen nur kleine Einschränkungen, mit denen man (ich) leben kann.

Den ersten Start werte ich jedenfalls als sehr positiv; weitere Erfahrungsberichte werden mit Sicherheit noch folgen.

Weiterlesen

Präsentationen von Brad McGehee

16. Oktober 2009 , Geschrieben von Olaf Helper Veröffentlicht in #Free eBooks

Der bekannte Australier Brad McGehee von Red Gate Software hat zum Start seines neuen Blog mal alle seine Bücher
- How to Become an Exceptional DBA
- Mastering SQL Server Profiler
- Brad’s Sure Guide to SQL Server 2008

und
Präsentationen
- Getting the Most Out of the SQL Server 2005/2008 Profiler (PDF, 2MB)
- DBA 101: Best Practices All DBAs Should Know (PDF, 800K)
- Introducing the SQL Server 2008 Data Collector (PDF, 800K)
- Introducing the SQL Server 2008 Performance Data Collector (PDF, 800K)
- Introduction to How to Interpret SQL Server Execution Plans (PDF, 800K)

zum Download zusammengestellt.

Weiterlesen

Free eBook: Windows 7 - Auf einen Blick

15. Oktober 2009 , Geschrieben von Olaf Helper Veröffentlicht in #Free eBooks

Noch bis zum 30.10.2009 verschenkt der Microsoft Press Verlag das eBook "Windows 7 - Auf einen Blick" von Jerry Joyce und Marianne Moon.
Wie so häufig muss man sich registrieren, den eigentlichen Download Link bekommt man per E-Mail zugesandt.

[Edit 2009-10-16 17:27]
Hat schon jemand geschafft, das herunter zu laden?
Ich habe mittlerweile mir 2mal einen Link schicken lassen, der Download fängt an, auf der Seite steht dann "kann dauern", es zuckt regelmäßig, nach ein paar Minuten kommt der Hinweis "Download blockiert" (ist halt Vista) und wenn ich das zulasse, geht es von vorne los.
Nach 4mal dieses Spielchen (nerv) kommt nur noch die Meldung "Gültigkeit des Links abgelaufen".
Na, dann halt nicht.
Weiterlesen

Einfache Datenreihen erzeugen

14. Oktober 2009 , Geschrieben von Olaf Helper Veröffentlicht in #T-SQL

Für manche Aufgabenstellungen benötigt man Datenreihen, z.B. fortlaufende Nummern oder alle Tage eines Jahres, um zu überprüfen, ob den für alle Tage auch Daten vorhanden sind.

Natürlich kann man so etwas auch prüfen, indem man die Differenz zum höchsten Vorgänger bildet; die darf dann nicht größer als 1 sein.

Einfacher geht es, wenn man eine Tabelle hat, die alle Werte beinhaltet. Jetzt könnte man eine (temporär) anlegen, sie über eine Schleife befüllen und die dann verwenden. Bei größeren Datenmengen ist das auch zu empfehlen, da man zur Verbesserung der Performanz einen Index anlegen kann.

Wenn man aber nur mal eben alle 365 Tage eines Jahres benötigt, lohnt sich der Aufwand nicht, das geht auch einfach:  Mittels einer rekursiven CTE (Common Table Expression). Das funktioniert wie folgt:

Ausgangspunkt ist eine CTE mit einem SELECT von den statischen Startdaten (Nr 1 / 01.Jan, etc). Das verbindet man mittels UNION mit einer Selektion der CTE (= Rekursion), wobei die Werte um 1 erhöht werden. Die Anzahl der Rekursionen schränkt man über eine WHERE Klausel auf echt-kleiner der Maximal-Werte ein. Echt-kleiner wird verwendet, da ja das (letzte) Ergebnis mit +1 zurück geliefert wird.

Das war es schon, keine große Zauberei.

 

Es gibt nur die „kleine“ Einschränkung auf maximal 32.747 Rekursionen; aber die Lösung ist wie schon erwähnt eh für kleinere Datenreihen gedacht.

 

 WITH [loops] (Sequence, EveryDayOfYear) AS 
  (SELECT 1 AS Sequence 
  ,CONVERT(datetime, '20090101', 112) AS EveryDayOfYear 
  UNION ALL 
  SELECT Sequence + 1 AS Sequence 
  ,DATEADD(d, 1, EveryDayOfYear) AS EveryDayOfYear 
  FROM [loops] 
  WHERE EveryDayOfYear < CONVERT(datetime, '20091231', 112)) 
 SELECT Sequence 
  ,EveryDayOfYear 
  ,CASE WHEN DATEPART(dw, EveryDayOfYear) < 6  
  THEN 'Werktag' 
  ELSE 'Wochenende'  
  END AS IsWeekEnd  
 FROM [loops] 
 OPTION (MAXRECURSION 366); 

 

Ergebnis:

 

Sequence

EveryDayOfYear

IsWeekEnd

1

2009-01-01 00:00:00.000

Werktag

2

2009-01-02 00:00:00.000

Werktag

3

2009-01-03 00:00:00.000

Wochenende

4

2009-01-04 00:00:00.000

Wochenende

5

2009-01-05 00:00:00.000

Werktag

6

2009-01-06 00:00:00.000

Werktag

7

2009-01-07 00:00:00.000

Werktag

359

2009-12-25 00:00:00.000

Werktag

360

2009-12-26 00:00:00.000

Wochenende

361

2009-12-27 00:00:00.000

Wochenende

362

2009-12-28 00:00:00.000

Werktag

363

2009-12-29 00:00:00.000

Werktag

Weiterlesen

Logical Query Processing Poster

10. Oktober 2009 , Geschrieben von Olaf Helper Veröffentlicht in #Download MSSQL

Weißt Du, wie genau T-SQL Statements analysiert und in welcher Reihenfolge verarbeiten sowie ausgeführt werden? Nein? Ich auch nicht so genau.

Aber jetzt weiß ich, wo ich es nach sehen kann. Pinal Dave hat in seinem sehr gutem Blog ein Poster veröffentlich

Es stammt ursprünglich aus dem Buch „Inside Microsoft SQL Server 2008: T-SQL Querying“ von dem bekannten Autor Itzik Ben-Gan aus dem Microsoft Press Verlag

Gibt es hier zum Download.

Weiterlesen

View als Tabellen – Dummy Ressource / Zero Device

9. Oktober 2009 , Geschrieben von Olaf Helper Veröffentlicht in #T-SQL

Stress-Tests für Applikationen, die auf Ressourcen zugreifen, sind mangels eben der Ressourcen nicht immer ganz einfach. Wenn man ein Programm testet, das mal eben 1.000 Seiten und mehr ausdrucken soll, verschwendet man eben mal 1.000 Seiten Papier (macht man natürlich nicht; die armen Bäume) oder lässt es in eine Datei umleiten, was dann auch eine entsprechend große Datei erzeugt. Um solche Test nun für Entwickler Ressourcen-schonend zu ermöglichen gibt es „Dummy Resources“ oder „Zero Devices“; sie verhalten sich wie die echten Ressourcen, machen aber effektiv nichts; sie empfangen die Daten wie gehabt und ... nichts weiter; das ist ja der Sinn & Zweck des Drucktreibers.

Aber Moment mal: MS SQL Server Objekte sind ja auch Ressourcen, mit denen mal Langzeit-Tests durchgeführt werden („Schafft es eine Schleife 1 Mio mal durch zu laufen?“). Da ist ja auch nicht immer unbedingt nötig, mehrere Gigabytes unnötig ins Storage zu schreiben.

Zugegeben, keine Daten wirklich weg zu schreiben, simuliert das Verhalten nicht wirklich, wie es dem echten Sachverhalten entspricht: Ich sage nur Primary Key, Unique Index, Foreign Key usw. um ein paar zu nennen. Trotzdem, für ein paar Test ist auf im MS SQL Server so eine Dummy Ressource durchaus brauchbar und sinnig.

Die Idee dazu ist mir bei „INSERTs abfangen und umleiten“ gekommen.

So geht es und das ganz einfach:

 

 USE [AdventureWorks] 
 GO 
 SET NOCOUNT ON; 
 GO 
 -- View als Dummy Resource anlegen 
 CREATE VIEW dbo.DummyResource 
 AS 
 SELECT CONVERT(int, 1) AS ID 
  ,'String' AS String 
  ,N'Unicode' AS Unicode 
  ,CONVERT(money, 123.4567) AS Betrag 
  ,GETDATE() AS Datum 
  ,CHAR(8000) AS BigString -- Um goroße Daten zu simulieren 
 GO 
   
 -- InsteadOf Trigger zum Abfangen von DML Kommandos 
 CREATE TRIGGER dbo.TR_All_DummyResource ON dbo.DummyResource 
 INSTEAD OF INSERT, UPDATE, DELETE 
 AS 
  -- Ich mach nichts und erzähle es niemanden 
  SET NOCOUNT ON; 
 GO 
   
 -- Und nun befeueren wir es mal 
 SELECT GETDATE() AS Start; -- Zeitmessung 
 GO 
 INSERT INTO dbo.DummyResource (ID) 
 VALUES (0); -- Alle NULLable, ein Feld reicht 
 GO 100000  -- 100T mal 
 DELETE FROM dbo.DummyResource; -- Alles weg 
 GO 
 SELECT GETDATE() AS Stop; -- Zeitmessung 
 GO 
   
 Ergebnis: 
   
 Start 
 ----------------------- 
 2009-10-09 19:36:14.040 
   
 Beginning execution loop 
 Batch execution completed 100000 times. 
 Stop 
 ----------------------- 
 2009-10-09 19:36:36.500 

 

Da kann man in der AdventureWorks oder TempDb nachsehen; da hat sich nichts passiert. Selbst das Änderungsdatum der Datenbank-Dateien ändert sich nicht; weshalb auch, es passiert wie gewünscht: Nix!

Weiterlesen

INSERTS abfangen und umleiten

9. Oktober 2009 , Geschrieben von Olaf Helper Veröffentlicht in #T-SQL

Vorab: Das Ganze ist hier mehr exemplarisch und war eher als „proof of concept“ gedacht. Das Beispiel ist extra einfach gehalten und soll das Verfahren nur verdeutlichen.

 

Problemstellung:

Wir haben eine externe Software, die mit einer proprietärer Datenbank arbeitet, auf die man von Außen nicht zugreifen kann, wir aber nun die Daten benötigen. Es steht nur eine Exportfunktion zur Verfügung, um den Bestand komplett zu exportieren. Neben einem Flatfile-Export kann die Software auch in eine SQL Server Datenbank schreiben, aber

-          festes, denormalisiertes Tabellendesign

-          nur Varchar-Felder / Daten

-          nur INSERT Statements

Also ein ganz „toller“ SQL Export, wurde wohl nur zu Marketing-Zwecken eingebaut, „Tooles Feature, wir können in eine SQL DB schreiben!“ (boah, ey).

 

Nun könnte man sagen: „Lass machen; wenn es fertig ist, bereite ich mir die Daten anderweitig mit SSIS und/oder SQL Scripten auf“; also ein Staging-Bereich im Dataware House zu Verfügung stellen und damit weiter arbeiten. Bei einem umfangreichen Szenario, sprich viel Tabelle und/oder Daten, wäre der Aufwand zur Sicherstellung der Daten-Qualität und Performanz gerechtfertig.

 

Und wie könnte man es ohne großen Aufwand als kleine, prozessunabhängige Lösung umsetzen?

 

Lösungsansatz:

Des Softwares Wille soll sein Himmelreich (oder was immer) sein. Aber eine Tabelle gibt es trotzdem nicht, da bin ich Stur.

Die eigentlichen Tabellen lege ich nach meinen Vorstellungen und natürlich normalisiert an. Hinzu kommt dann ein View, das von den Feldern her dem geforderten Tabellendesign entspricht und die Daten aus meinen Tabellen selektiert.

Dieses View ist aber definitiv nicht aktualisierbar, INSERTs können darauf nicht ausgeführt werden; wie kann jetzt trotzdem die externe Software hier rein schreiben?

Ganz einfach, mittels eines INSTEADOF Trigger, der, wieder Name schon sagt, statt des eigentlichen INSERTs ausgeführt wird und in der virtuellen Tabelle „inserted“ die Daten mit Tabellendesigns der View hat. Im Trigger kann man dann die Business Logic umsetzten, mit der man die Daten in die eigentlichen Tabellen weg schreibt.

 

Hier mein Demo Script dazu:

 

 SET NOCOUNT ON; -- Kein Feedback über Anzahl 
   
 -- Basistabellen anlegen 
 CREATE TABLE dbo.FirstNames 
   (Id int IDENTITY(1, 1) NOT NULL PRIMARY KEY CLUSTERED, 
   firstname nvarchar(50) NOT NULL UNIQUE); 
   
 CREATE TABLE dbo.LastNames 
   (Id int IDENTITY(1, 1) NOT NULL PRIMARY KEY, 
   lastname nvarchar(50) NOT NULL UNIQUE); 
   
 CREATE TABLE dbo.Names 
   (Id int IDENTITY(1, 1) NOT NULL PRIMARY KEY, 
   firstname_id int NOT NULL, 
   lastname_id int NOT NULL); 
 GO 
 -- Kombination Vor/Nachname Unique 
 CREATE UNIQUE NONCLUSTERED INDEX [UQ_FirstLastName] 
 ON [dbo].[Names] 
   ([firstname_id] ASC, 
   [lastname_id] ASC  ) 
 GO 
   
 -- Sicht mit den Namen auf die Basistabellen 
 CREATE VIEW dbo.vwNames 
 AS 
   SELECT N.Id, F.firstname, L.lastname 
   FROM dbo.Names AS N 
   INNER JOIN dbo.FirstNames AS F 
   ON N.firstname_id = F.Id 
   INNER JOIN dbo.LastNames AS L 
   ON N.lastname_id = L.Id; 
 GO 
 -- Geht natürlich (noch) nicht 
 INSERT INTO dbo.vwNames (firstname, lastname) 
 VALUES ('Olaf', 'Helper');  
 GO 
   
 -- InsteadOf Trigger zum Abfangen der INSERTS 
 CREATE TRIGGER dbo.TRI_vwNames ON dbo.vwNames 
 INSTEAD OF INSERT 
 AS 
 BEGIN 
   -- Fehlende Vornamen eintragen 
   INSERT INTO dbo.FirstNames (firstname) 
   SELECT DISTINCT I.firstname  -- Distinct wegen Unique!! 
   FROM inserted as I 
   LEFT JOIN dbo.FirstNames AS F 
   ON I.firstname = F.firstname 
   WHERE F.firstname IS NULL 
   AND NOT I.firstname IS NULL 
   
   -- Dito Nachnamen 
   INSERT INTO dbo.LastNames (lastname) 
   SELECT DISTINCT I.lastname  -- Distinct wegen Unique!! 
   FROM inserted as I 
   LEFT JOIN dbo.LastNames AS L 
   ON I.lastname = L.lastname 
   WHERE L.lastname IS NULL 
   AND NOT I.lastname IS NULL 
   
   -- Nun fehlende Namenseinträge 
   INSERT INTO dbo.Names (firstname_id, lastname_id) 
   SELECT DISTINCT F.Id, L.Id  -- Distinct wegen Unique!! 
   FROM inserted AS I 
   INNER JOIN dbo.FirstNames AS F 
   ON I.firstname = F.firstname 
   INNER JOIN dbo.LastNames AS L 
   ON I.lastname = L.lastname 
   LEFT JOIN dbo.Names AS N 
   ON N.firstname_id = F.Id 
   AND N.lastname_id = L.Id 
   WHERE N.Id IS NULL 
 END; 
 GO 
   
 -- Nun mehrere Datensätze in einem Rutsch 
 -- direkt ins View schreiben 
 INSERT INTO dbo.vwNames 
   (firstname, lastname) 
 SELECT 'Olaf' AS firstname, 'Helper' AS lastname 
 UNION ALL SELECT 'Peter',  'Mustermann' 
 UNION ALL SELECT 'Anonymus', 'Unbekannt' 
 UNION ALL SELECT 'Peter',  'Unbekannt' -- Vorhandener Vor+Nachname 
 UNION ALL SELECT 'Olaf',  'Helper'  -- Doppelter Name 
 UNION ALL SELECT NULL,  NULL  -- Schrott 
 GO 
   
 -- Angekommen? Jawoll! 
 SELECT * FROM dbo.vwNames 
 GO 
   
 Ergebnis: 
   
 Id  firstname  lastname 
 --- ---------- ------------ 
 1  Anonymus  Unbekannt 
 2  Olaf  Helper 
 3  Peter  Mustermann 
 4  Peter  Unbekannt 

 

Fazit:

Mit der Methode kann man zum einen Fremdappliaktionen einen Schreibzugriff einrichten und zugleich die eigentliche Datenbankstruktur gegenüber Außen völlig transparent halten. Zudem lässt sich so eine kleiner datengetriebener ETL Prozeß realisieren.

 

Zugegeben, nichts neues, nichts wildes, aber wollte ich halt mal ausprobieren.

Weiterlesen

CONVERT liefert Sternchen (Asterisk *)

6. Oktober 2009 , Geschrieben von Olaf Helper Veröffentlicht in #T-SQL

Wenn man versucht einen Text, der keine gültige Zahl darstellt, in eine Zahl zu konvertieren, gibt es einen Laufzeitfehler; ist klar.

 SELECT CONVERT(int, 'Text') AS Try 
 Meldung 245, Ebene 16, Status 1, Zeile 1 
 Fehler beim Konvertieren des varchar-Wertes 'Text' in den int-Datentyp. 

 

Wie sieht es mit der „Gegenrichtung“ aus, kann man nach belieben nach VarChar konvertieren, sofern der Datentyp + CONVERT es prinzipiell unterstützt?

 

Datum ist jedenfalls kein Problem, auch wenn ich das Ergebnis mit VarChar auf 3 Zeichen begrenze; bekomme ich halt den Tag und den ersten Punkt zurück.

 SELECT CONVERT(varchar(3), GetDate(), 104) AS Datum 
 Datum 
 ----- 
 06. 

 

Wenn ich nun Numeric umwandeln will, sieht es schon anders aus.

 SELECT CONVERT(varchar(4), 1234.567) AS Fliess 
 Fliess 
 ------ 
 Meldung 8115, Ebene 16, Status 5, Zeile 1 
 Arithmetischer Überlauffehler beim Konvertieren von numeric in den varchar-Datentyp. 


Die Konvertierung kann die Zahl mit 4 Zeichen nicht vollständig umwandeln und sie schlägt deshalb fehl; mit VarChar(8) würde es gehen. Gleiches geschieht auch bei GUID, es werden die benötigte Anzahl an Zeichen erwartet.

 

Damit wäre ja alles klar … oder doch nicht?

Ein weitere Versuch mit Ganzzahlen smallint / int:

 

 -- Substitute auf * (Sternchen, Asterisk) 
 SELECT Zahl 
   ,CONVERT(varchar(2), Zahl) AS Str2 
   ,CONVERT(varchar(3), Zahl) AS Str3 
   ,SUBSTRING(CONVERT(varchar(6), Zahl), 1, 2) AS Sub2 
 FROM (SELECT CONVERT(smallint, 1) AS Zahl 
   UNION ALL SELECT 10 
   UNION ALL SELECT 100 
   UNION ALL SELECT 1000) AS Quelle 
   
 Ergebnis: 
   
 Zahl  Str2 Str3 Sub2 
 ----------- ---- ---- ---- 
 1  1  1  1 
 10  10  10  10 
 100  *  100  10 
 1000  *  *  10 

 

Kein Laufzeitfehler, dafür findet man im Ergebnis nun plötzlich Sternchens * wieder (getestet mit MS SQL Server 2000, 2005, 2008 und 2008 R2 CTP). Verwendet man hingegen NVarChar, gibt es auf einmal einen Laufzeitfehler; nicht sehr konsequent.

Wenn man in der BOL dann unter „CAST und CONVERT (Transact-SQL)“ nachsieht, findet man das auch genau so im Absatz „Abschneiden und Runden von Ergebnissen“ dokumentiert.

Muss man halt nur wissen, sonst wundert man sich über das Ergebnis.

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
1 2 > >>