SQL Server: Von wiederhergestellten Datenbanken und verwaisten Benutzern

by wolfgang@gehirnwindung.de (Wolfgang) Mai 10, 2010 23:04

Immer wieder - jedoch insgesamt selten und aus dem Grund auch leider immer wieder mit einer Suche verbunden - brauch ich nach der Wiederherstellung einer Datenbank eine Stored Procedure, um die Benutzer aus der wiederhergestellten Datenbank und die Logins des Servers wieder in "Einklang" zu bringen.

Das Problem tritt z.B. auf, wenn die DB in einem anderem Server wiederhergestellt wird. Die Ursache ist, dass zwar evtl. der Login- und der Username gleich, die im Hintergrund wirkenden ID's aber unterschiedlich sind.

Nun. Hierfür gibt es die SP sp_change_users_login. Mit einem Administratorkonto (sysadmin oder db_owner) an der Datenbank anmelden und folgendes Ausführen:

Um eine Übersicht über die Benutzer zu bekommen, die verwaist sind

EXEC sp_change_users_login @action='Report'


Wenn der Login inkl. Passwort bereits eingerichtet ist, der Benutzer aber noch zugeordnet werden muss.

EXEC sp_change_users_login @action='Auto_Fix', @userNamePattern='user'


Wenn der Benutzer zugeordnet und ein Login mit Passwort erstellt werden muss (ist der Login bereits vorhanden, wird @password ignoriert)

EXEC sp_change_users_login @action='Auto_Fix', @userNamePattern='user', @password='password'


Man kann auch einen Benutzer mit einem Login verbinden, wenn die beiden nicht den gleiche Namen haben. Dann sieht es so aus (auch hier kann noch optional ein Passwort angegeben werden)

EXEC sp_change_users_login @action='Update_One', @userNamePattern='user', @loginName='login'

 

So, und beim nächsten Mal weiß ich, wo ich suchen muss ;)

Tags:

Microsoft SQL Server

Der geography-Datentyp und warum die Länge einer Linie nicht unbedingt auch die Distanz zwischen deren Endpunkten ist

by wolfgang@gehirnwindung.de (Wolfgang) Juli 28, 2009 23:52

Seltsamer Titel? Stimmt. Das war aber heute eine Frage in einem Microsoft-Forum. Warum ist die Länge nicht gleich der Distanz zwischen 2 Punkten?

Nun, das stimmt natürlich nicht - zum Glück. Bei der Fehlersuche ist allerdings eine Besonderheit des SQL Servers aufgefallen. Zuerst aber mal ein Beispiel

DECLARE @line geography, @pointStart geography, @pointEnd geography
SELECT @line = geography::STGeomFromText('LINESTRING(1 2, 3 4)', 4326),
       @pointStart = geography::Point(1, 2, 4326),
       @pointEnd = geography::Point(3, 4, 4326)

SELECT @line.STLength() AS Length,
       @pointEnd.STDistance(@pointStart) AS Distance

Heraus kommen die Werte

Length Distance
313588,386985478 313705,435222058

Doch warum sollte hier ein Unterschied bestehen... STLength() gibt die Länge des LINESTRINGs zurück und STDistance() berechnet die Distanz zwischen 2 Punkten. Wie bereits vorweggenommen ist das Ergebnis so an sich also falsch - trotzdem ist es so, dass der SQL Server korrekt rechnet. Bleibt als einzige Fehlerquelle also nur noch der Code selbst übrig...

Laut MSDN-Referenz zu geography::Point werden 3 Parameter erwartet: Latitude, Longitude und die SRID. Die Funktion geography::STGeomFromText interpretiert die Angaben aber anders herum. Um genauer zu sein in der Reihenfolge Longitude (geographischer Länge) und danach Latitude (geographischer Breite).

Und das war auch schon das ganze Geheimnis ;) Warum geography::Point hier die Werte anders herum erwartet ist mir ein Rätsel und wird es wohl auch bleiben - die Reihenfolge wie sie geography::STGeomFromText interpretiert entspricht den Vorgaben der OGC und erscheinen damit in allen möglichen Bereichen eben in dieser Reihenfolge (und damit u.a. auch in GML).

Wie dem auch sei. Es ist alles noch korrekt - man muss nur drank denken ;)

Tags: ,

Microsoft SQL Server

Replace von CHAR(0) in SQL Server varchar-Spalte

by Wolfgang Kluge Juni 30, 2009 18:46

Heute kam es in einem meiner Projekt zu folgendem Fehler

Msg 6841, Level 16, State 1, Line 1
FOR XML konnte die Daten für den 'Tabelle'-Knoten nicht serialisieren, weil ein in XML unzulässiges Zeichen (0x0000) enthalten ist. Um diese Daten mithilfe von FOR XML abzurufen, konvertieren Sie sie in den Datentyp 'binary', 'varbinary' oder 'image', und verwenden Sie die BINARY BASE64-Direktive.

Nach kurzem Suchen bemerkte ich dann, dass nicht die Ausgabe mittels FOR XML fehlerhaft war, sondern in einzelnen Feldern einer Tabelle CHAR(0)-Zeichen enthalten waren, die da nicht hingehörten. Die Tabelle wird von anderer Stelle gefüllt und eigentlich wird dabei der entsprechende Text abgeschnitten, dieses Sonderzeichens in dem Fall wohl aber nicht mehr. Nachdem die Befüllung geändert wurde, mussten die bereits geschriebenen CHAR(0)-Einträge noch geändert werden, doch dass stellte sich als schwerer heraus als zuerst angenommen. Sicher war, dass die Zeichen nur am Ende eines Textes vorkamen. Zum Testen gab es folgende temporäre Tabelle

DECLARE @test table(
    Name varchar(30) NULL COLLATE Latin1_General_CI_AS
)
INSERT INTO @test (Name)
           SELECT 'Hallo Welt 1' + CHAR(0) + CHAR(0) + CHAR(0) + CHAR(0)
 UNION ALL SELECT 'Hallo Welt 2' + CHAR(0)
 UNION ALL SELECT 'Hallo Welt 3'
 UNION ALL SELECT ''
 UNION ALL SELECT CHAR(0)
 UNION ALL SELECT CHAR(0) + CHAR(0)
 UNION ALL SELECT NULL

Das Problem sollte schnell gelöst werden können.

UPDATE  @test
SET     Name = SUBSTRING(Name, 1, CHARINDEX(CHAR(0), Name) - 1)
WHERE   Name LIKE '%' + CHAR(0) + '%'

Sieht einfach aus, macht - zumindest theoretisch - genau dass, was ich will, funktioniert aber nicht :(

vollständigen Artikel anzeigen...

Tags: ,

Microsoft SQL Server

Partitionierte Views anlegen

by Wolfgang Kluge Mai 02, 2009 12:23

Mit Partitionierung ist ein Aufteilen der Daten anhand bestimmter Kriterien gemeint - vor allem riesige Datenbestände können so einen echten Performancegewinn "erleiden" ;) Man kann dabei auch auf Remote-Tabellen zugreifen(Distributed Partitioned View) - aber dieser Artikel soll nur eine kleine Einführung geben.

Partitionierte Views sind dabei kein wirklicher Ersatz für die partitionierten Tabellen. Man kann sich aber zumindest teilweise helfen.

Eine partitionierte View und deren Tabellen unterliegen einigen Einschränkungen. So muss die Kriteriumsspalte innerhalb des Primary Keys vorkommen (oder selbst der Primary Key sein) und eine Identity-Spalte führt zum Fehler. Alle Tabellen müssen gleiche Primary Keys vorweisen. Das Kriterium muss der jeweiligen Tabelle mittels CHECK-Einschränkung bekannt gegeben werden. Dabei darf die CHECK-Einschränkung nur aus folgenden Operatoren bestehen: AND, OR, BETWEEN, <, <=, =, >= und >. Da gibt es noch ein paar Einschränkungen, aber für den Anfang muss das ausreichen...

vollständigen Artikel anzeigen...

Tags: ,

Microsoft SQL Server

Views mit INSTEAD OF UPDATE-Trigger

by Wolfgang Kluge Mai 01, 2009 18:01

Ich stand vor der Problemstellung, eine Tabelle zu optimieren, da die Tabelle an vielen Stellen verwendet wird aber gleichzeitig dafür zu sorgen, dass die Umstellung "abwärtskompatibel" bleibt.

Die Tabelle ist schon etwas älter, mittlerweile gut gefüllt und es werden einige Daten ständig wiederholt - ich wollte also als erstes mal umstrukturieren. Mein erster Gedanke war, eine View zu verwenden, damit andere Abfragen noch genauso funktionieren wie zuvor. Am Anfang reicht es aus, die "wichtigsten" Abfragen zu optimieren und mit der Zeit könnte man dann langsam alle anderen Abfragen ändern sprich optimieren.

Gesagt, getan. Ich habe also die Tabellen angelegt und eine View nach dem Vorbild der Ursprungstabelle angelegt (und aus Performancegründen eine Indexed View verwendet). Damit auch INSERT-, UPDATE- und DELETE-Anweisungen weiterhin funktionieren, wurden entsprechende INSTEAD OF-Trigger geschrieben...

Doch dann durchkreuzte eine simple aber folgenreiche Fehlermeldung mein ganzes Vorhaben.

Msg 414, Level 16, State 1, Line <line>
UPDATE ist nicht zulässig, weil die Anweisung die "<view name>"-Sicht aktualisiert, die an einer Verknüpfung beteiligt ist und einen INSTEAD OF UPDATE-Trigger aufweist.

bzw.

Msg 414, Level 16, State 1, Line <line>
UPDATE is not allowed because the statement updates view <view name> which participates in a join and has an INSTEAD OF UPDATE trigger

vollständigen Artikel anzeigen...

Tags: ,

Microsoft SQL Server

Identitätsspalte zurücksetzen

by wolfgang@gehirnwindung.de (Wolfgang) April 16, 2009 18:44

Manchmal kommt es vor, dass man (z.B. nach letzten Tests) seine Daten aus Tabellen löschen und dabei entsprechende Identitätsspalten zurücksetzen will.

Hierbei gibt es mehrere Möglichkeiten. Man kann z.B. mittels TRUNCATE TABLE gleich beides auf einmal erledigen. Das empfiehlt sich aber nicht wirklich, da dies spätestens dann aufhört, wenn die Tabelle repliziert wird oder Foreign Keys gesetzt sind. Die Replikation kann auch dafür verantwortlich sein, dass man eine Tabelle nicht einfach so löschen und neu anlegen kann.

Mit all diesen Versuchen kann man aber - wenn Sie denn überhaupt gelingen - immer nur ganz von vorne anfangen. Es müssen alle Daten gelöscht werden. Falls Daten erhalten bleiben sollen, müssen diese zuerst gelöscht und danach wieder eingefügt werden.

Aber es gibt natürlich noch eine andere Möglichkeit. Der Befehl

DBCC CHECKIDENT ('table'[, NORESEED|RESEED[, seed_value]] )

ist zwar nicht sonderlich bekannt, wird aber durchaus verwendet. Dennoch, auch DBCC CHECKIDENT hat so seine Tücken. Zum Einen werden neu erstellte und bereits verwendete Tabellen unterschiedliche behandelt. Dadurch fällt es wiederum etwas schwerer, DBCC CHECKIDENT innerhalb eines Scripts zu verwenden.

vollständigen Artikel anzeigen...

Tags: ,

Microsoft SQL Server

Globale Stored Procedure im SQL Server

by Wolfgang Kluge April 14, 2009 17:38

Um eine Stored Procedure im SQL Server global (d.h. über mehrere Datenbanken hinweg) verfügbar zu machen, gibt es den nur wenig (bzw. offiziell gar nicht) dokumentierten Befehl sp_ms_marksystemobject. Damit es funktioniert muss der Name der Stored Procedure mit "sp_" beginnen und in der master-Datenbank gespeichert sein! Es gibt keine Fehlermeldung, falls dies nicht so wäre...

Folgende Tabelle soll den Unterschied verdeutlichen. Die Aufgerufene Stored Procedure gibt (wie in dem Beispiel unten) lediglich den aktuellen Datenbanknamen zurück.

SP Aufruf aus AdventureWorks-DB DB_NAME()
in master-Datenbank, aber nicht als System Object markiert
EXEC master.dbo.StoredProcedure
master
EXEC dbo.StoredProcedure
Fehler
in master-Datenbank und als System Object markiert
EXEC master.dbo.StoredProcedure
master
EXEC dbo.StoredProcedure
AdventureWorks

vollständigen Artikel anzeigen...

Tags: ,

Microsoft SQL Server

Powered by BlogEngine.NET 1.6.1.6
Theme by Mads Kristensen | Modified by Mooglegiant and me ;)