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

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

Iteration per GO statt per WHILE Schleife

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

Schleifen zum Abarbeiten von Batches bildet man in T-SQL mittels einer WHILE Schleife ab.

 

Ab Microsoft SQL Server 2005 hat man den Batchtrenner, was per Default ja das GO ist, um einen Parameter für die Anzahl der Durchläufe anzugeben.

Also: Schreibe ich GO 3, wird der Batch drei Mal durchlaufen.

 

Demo:

 

 SET NOCOUNT ON; 
 GO 
 -- Bisher: per While Schleife 
 DECLARE @loop smallint = 0; 
 WHILE @loop < 3 
 BEGIN 
  SELECT GETDATE() AS DatumZeit; 
  SET @loop += 1; 
 END 
 GO 
   
 -- Ab Microsoft SQL Server 2005 
 -- Interation per Go + Anzahl Loops 
 SELECT GETDATE() AS DatumZeit; 
 GO 3  -- <= heisst: Führe den gesamten Batch 3 mal aus 

 

Das bekommt man dann nach der Ausführung im SSMS entsprechend gemeldet:

 

 Beginning execution loop 
 DatumZeit 
 ----------------------- 
 2009-10-01 20:24:12.717 
   
 DatumZeit 
 ----------------------- 
 2009-10-01 20:24:12.747 
   
 DatumZeit 
 ----------------------- 
 2009-10-01 20:24:12.763 
   
 Batch execution completed 3 times. 
Weiterlesen

Wann ist +1 Monat?

30. September 2009 , Geschrieben von Olaf Helper Veröffentlicht in #T-SQL

In T-SQL des Microsoft SQL Servers gibt es die Funktion DATEADD, um auf ein Datum ein Intervall-Wert auf bzw. abzurechnen; sein es Tage, Wochen, Monate oder Ein Wert im Datumsbereich.

Einen Tag aufzurechnen, das ist klar und eindeutig: Aus Montag wird Dienstag und wie selbstverständlich wird aus dem 28.02.2009 der 01.03.2009 und nicht der 29.02, da es ja kein Schaltjahr ist.

Doch wie sieht es aus, wenn man einen Monat aufaddiert? Im Bankwesen ist er rechnerisch immer 30 Tage lang, im realen Leben variiert er aber. Wenn ich auf den 31.03. einen Monat rechne, kommt der 30.04. oder der 01.04. raus? Vom 30.04 ausgehend, erhalte ich den 30.05. oder den 31.05, weil es wie das Ausgangsdatum das Monatsende ist?

Bevor ich spekuliere, probiere ich es aus und das diesmal mit dem MS SQL 2008 mit der Möglichkeit der Multiple-Values.

 

T-SQL Statement:

 -- Wann ist +1 Monat? 
 SELECT * 
  ,DATEDIFF(dd, ThisDate, NextMonth) AS DayDiff 
 FROM  
  (SELECT ThisDate 
  ,DATEADD(mm, 1, ThisDate) AS NextMonth 
  FROM 
  (VALUES(CONVERT(date, '20081231')) 
  ,('20090131') ,('20090228') 
  ,('20090331') ,('20090430') 
  ,('20090531') ,('20090630') 
  ,('20090731')  
  ,('20090831') ,('20090930') 
  ,('20091031'), ('20091130') 
  ,('20091231')  
  ) AS Dates (ThisDate) 
  ) AS Dates 

 

Ergebnis: 

 ThisDate NextMonth DayDiff 
 ---------- ---------- ------- 
 2008-12-31 2009-01-31 31 
 2009-01-31 2009-02-28 28 
 2009-02-28 2009-03-28 28 
 2009-03-31 2009-04-30 30 
 2009-04-30 2009-05-30 30 
 2009-05-31 2009-06-30 30 
 2009-06-30 2009-07-30 30 
 2009-07-31 2009-08-31 31 
 2009-08-31 2009-09-30 30 
 2009-09-30 2009-10-30 30 
 2009-10-31 2009-11-30 30 
 2009-11-30 2009-12-30 30 
 2009-12-31 2010-01-31 31 

 

Das Ergebnis ist nicht gerade „deterministisch“: Grundsätzlich wird platt der Monat um eins hoch gezählt und wenn es ein ungültiges Datum ergibt, soweit tageweise zurück gerechnet, bis es gültig ist.

Ist halt so und sollte man immer im Hinterkopf behalten, wenn es um Auswertungen und ähnliches geht, um nicht falsche Zahlen zu erhalten.

Also: Um vom Monatsende auf das Monatsende des Folgemonats zu kommen, ist diese Methode ungeeignet. Besser man rechnet:

+ 1 Tag            (=Monatsanfang Folgemonat)

+ 1 Monat         (=Monatsanfang Übernächster Monat)

– 1 Tage           (=Monatsende Folgemonat)

 

=>

 

 SELECT DATEADD(DD, -1 
  ,DATEADD(MM, 1 
  ,DATEADD(DD, 1 
  ,'20090228' 
  ))) AS FolgeMonatsEnde 
Weiterlesen

Aktivität und Fortschritt einer Transaktion ermitteln

29. September 2009 , Geschrieben von Olaf Helper Veröffentlicht in #T-SQL

Lange Transaktion wie umfangreiche Updates in einem Dataware House lässt man meist per Job über Nacht laufen, da sitzt man nicht daneben und muss waren, bis es fertig ist; Hauptsache es ist bis zum nächsten morgen fehlerfrei durchgelaufen.

Wenn man aber gerade dabei ist, ein System auszubauen, muss man auch schon mal einen Langläufer anstarten und dann sitzt man da: Wie lange dauert es denn noch, wie weit ist die Transaktion bereits und macht er überhaupt noch was? Da wäre es schön, mal in den Microsoft SQL Server hineinschauen zu können.

Während einer solchen Wartezeit habe ich mal versucht, über die DMV (Dynamic Management Views) den Fortschritt einer Transaktion zu ermitteln; bei der DMV  sys.dm_tran_database_transactions bin ich fündig geworden. Die View liefert einem zu einer Transaktion die Anzahl der Transaktionsprotokoll-Einträge sowie die reservierte und verwendet Größe des Logs.

Das ist recht interessant und leicht verwirrend zu beobachten. Ich habe mal auf einem MS SQL Server 2005 mit SP 3 (9.00.4035.00) folgendes ausgeführt:

 

 UPDATE Tabelle 
 SET Feld1 = Feld1 
 WHERE id <= 500000 

 

Id ist eine Identity, es werden also 500k Datensätze upgedatet, wobei sich eigentlich nicht ändert, da das Feld der aktuelle Wert zugewiesen wird. Aber das kennt man schon, das trotzdem ein Update und damit eine Protokollierung im LOG erfolgt.

Das untenstehende zeigt das auch schon auf, man kann zusehen, wie die benötigt Größe & Anzahl steigt. Nun das interessante und zwar start ich das gleiche Update noch einmal, nur mit der WHERE Klausel

 WHERE id <= 600000 

Es werden also noch mal die gleichen 500k + weitere 100k an Datensätze upgedatet.

Beobachtet man mit dem Script diese Transaktion, werden zunächst nur 2 Einträge im LOG erzeugt, dann geschieht eine Zeit lang erst mal nichts weiter, bis dann doch noch 100k Sätze ins Log geschrieben werden; wohl die für die erstmal upgedateten.

Da scheint doch zumindest etwas optimiert zu sein.

 

Ich habe auch schon versucht, die „Restlaufzeit“ aufgrund der Daten zu schätzen, aber aufgrund des zuvor genannten Verhaltens ist das nicht so einfach. Vielleicht hat da jemand anderes noch eine Lösung zu.

 

Hier nun das T-SQL Script dazu, viel Vergnügen beim der Trans-Beobachtung:

 

 -- Selektion der Transaktionen eines Prozesses mit den  
 -- Daten des Transaktionsprotokolles wie Größe und 
 -- Anzahl Log-Sätze 
 DECLARE @spid as int; 
 SET @spid = 57; 
   
 SELECT PRO.spid, TDT.transaction_id, 
  CASE TDT.database_transaction_type 
  WHEN 1 THEN 'Read/Write' 
  WHEN 2 THEN 'ReadOnly' 
  WHEN 3 THEN 'System'  
  END AS TransType, 
  CASE TDT.database_transaction_type 
  WHEN 1 THEN 'Not initialized' 
  WHEN 3 THEN 'Initialized, no LOG generated' 
   WHEN 4 THEN 'LOG generated' 
  WHEN 5 THEN 'Preparing trans' 
  WHEN 10 THEN 'Committed' 
  WHEN 11 THEN 'Rolling back' 
  WHEN 12 THEN 'Committted, LOG generated, but not persisted'  
  END AS TransState, 
  PRO.waittime, PRO.waitresource, PRO.last_batch, 
  TDT.database_transaction_begin_time AS TransBegin, 
  TDT.database_transaction_log_record_count AS LogRecordCount, 
  TDT.database_transaction_log_bytes_used / 1024 AS LogKBUsed, 
   TDT.database_transaction_log_bytes_reserved / 1024 AS LogKBReserved, 
  CONVERT(decimal(8, 2),  
  DATEDIFF(ss, TDT.database_transaction_begin_time, GetDate()) / 60.0) AS DurationMin 
 FROM sys.dm_tran_database_transactions AS TDT 
  INNER JOIN sys.dm_tran_session_transactions AS TST 
  ON TDT.transaction_id = TST.transaction_id 
  INNER JOIN sys.sysprocesses AS PRO 
  ON TST.session_id = PRO.spid 
 WHERE PRO.spid = @spid 
  AND NOT TDT.database_transaction_begin_time IS NULL 
Weiterlesen

Aktuelle TechNet WebCasts und Seminare im Quartal 4 - 2009

27. September 2009 , Geschrieben von Olaf Helper Veröffentlicht in #Event

Im den kommenden 2 Monaten finden wieder, dem Titel nach zu urteilen interessante, TechNet WebCasts und TechNet Seminare zum Thema Microsoft SQL Server 2008 und 2008 R2 statt.

 

Webcasts

-       SQL Server 2008 R2 – Überblick über die CTP 2 (Level 200)

-       Projekt Gemini in SQL Server 2008 R2 – Teil 1: Die Clientseite

-       Reporting Services in SQL Server 2008 R2 – Maps und mehr (Level 200)

 

TechNet Seminare

-       SQL Server 2008 Clustering auf Windows Server 2008

-       SQL Server 2008 - Performance Tuning - Methoden, Werkzeuge und Best Practices

-       SQL Server 2008 aus der Sicht eines Softwareentwicklers

 

Preise für die Seminare habe ich bisher nicht gesehen, von daher gehe ich davon aus, dass sie (wie häufig) kostenfrei sind.

Die Seminare in Köln finden im Oktober statt, in Unterschleißheim im Dezember.

 

Die aktuellen Termine findet man am einfachsten über die Suche der Veranstaltungen.

Weiterlesen

Free eBook: SQL Server Tacklebox - Essential Tools and Scripts for the day-to-day DBA

27. September 2009 , Geschrieben von Olaf Helper Veröffentlicht in #Free eBooks

Die Firma Red-Gate hat ein weiteres eBook mit dem Titel „SQL Server Tacklebox - Essential Tools and Scripts for the day-to-day DBA” vom Autor Rodney Landrum veröffentlich, das es kostenlos zum Download gibt; eine Registrierung ist nicht nötig, man kommt ganz oben über „…If it does not, please click here zum Download.

Ich habe es bisher nur kurz überfolgen, es umfasst aber dem Titel entsprechend mit seinen 240 Seiten in leicht gekürzter Form alle Aspekte des DBA-Daseins.

Insbesondere die enthaltenen SQL Scripte sind sehr interessant, z.B. gleich das erste, um eine SQL Server Instanz nach den gewünschten Vorgaben zu konfigurieren.

Weiterlesen

„Create Or Alter“ für MS SQL Server

25. September 2009 , Geschrieben von Olaf Helper Veröffentlicht in #T-SQL

Bei Oracle und anderen DBMS gibt es die DDL Anweisung „Create Or Alter“ für Procedures, Functions und Views. Das ist praktisch, da man sich keine Gedanken machen muss, ob das Objekt schon vorhanden ist: Ist es vorhanden, wird es aktualisiert, sonst eben neu angelegt.

 

Im MS SQL Server gibt es so etwas leider nicht. Man behilft sich damit, dass man ein vorhandenes Objekt zunächst löscht (DROP) und dann wieder neu anlegt (CREATE). Das hat nur den großen Nachteil, dass alle vorhandenen Berechtigungen auch mit entfernt werden.

 

Dann gibt es noch zwei Möglichkeiten

-          Man pflegt die Berechtigungen im DROP/CREATE Script immer mit, was bei bei regelmäßigen Änderungen einen entsprechenden zusätzlichen Aufwand darstellt; und damit fehleranfällig. 

-          Man erstellt bei Design-Änderungen ein zusätzliches ALTER Script, nur wenn man eine neue Datenbank anlegt muss man daran denken, erst das CREATE und dann das ALTER Script auszuführen.

Beides nicht gerade komfortable und auch etwas fehlerträchtig.

 

Um „Create Or Alter“ nun doch noch abbilden zu können, habe ich mir folgendes überlegt

-          Wenn Objekt nicht vorhanden, dann mit „leerem“ Inhalt anlegen

-          Anschließend ein ALTER mit dem eigentlichen Design ausführen.

Dabei gibt es aber wieder ein kleines Problem, den die CREATE Anweisung muss die erste in einem Batch sein und somit kann man vorab nicht prüfen, ob das gewünschte Objekt bereits besteht. Aber das ist eben nur ein kleines Problem, dann legen über sp_executesqlmit einem SQL Script als Text an.

 

Beispiel:

 USE [AdventureWorks] 
 GO 
   
 IF OBJECT_ID('dbo.spTestSp', 'P ') IS NULL 
  EXEC sp_executesql N'CREATE PROCEDURE dbo.spTestSp AS SET NOCOUNT ON;' 
 GO 
   
 ALTER PROCEDURE dbo.spTestSp 
  @AddressID int 
 AS 
  SELECT * 
  FROM Person.Address 
  WHERE AddressID = @AddressID; 

 

Kein wirklicher Ersatz, aber mit T-SQL geht es halt nicht besser; zumindest nicht, das ich wüsste.

 

Weiterlesen

Microsoft SQL Server 2008-Onlinedokumentation (Juli 2009)

18. September 2009 , Geschrieben von Olaf Helper Veröffentlicht in #Download MSSQL

Eine aktualisierte Version der BOL (Books Online) für den Microsoft SQL Server 2008 Stand Juli 2009 (veröffentlicht 08.09.2009) gibt es im Download Center.
Die englischsprachige Version wurde zuvor bereits am 20.08.2009 publiziert.

Weiterlesen
<< < 10 11 12 13 14 15 16 17 18 19 20 > >>