Das Problem hat wahrscheinlich jeder schon einmal gehabt. Man stellt Importanforderungen auf, und die Anwender kümmern sich nicht darum und liefern anstelle von sauber getrennten Strings und Zahlen einen bunten Mischmasch aus beidem.
Zugegeben ist das Subjekt nicht sehr treffend, aber im Moment fällt mir kein Besseres ein.
Gestern stellte jemand auf SQL Server Central.com die Frage, wie man zu jedem Namen mehr als ein Datum anzeigen kann. Genauer gesagt, die beiden aktuellsten Daten. Diese Frage kann man leicht auf die Northwind Beispieldatenbank übertragen: Zeige mir zu jedem Kunden die beiden letzten Bestelldaten ein.
Das nachfolgende Skript löscht alle existierenden Einschränkungen für die angegebene Tabelle. Will man alle Einschränkungen der aktuellen Datenbank löschen, muss man einfach nur die WHERE Zeile auskommentieren oder entfernen.
Gleich vorwegschicken möchte ich, daß dieser Beitrag nicht zur Nachahmung oder zum Einsatz in Produktivsystemen gedacht ist. Vielmehr eher als reine Spielerei mit dem, was möglich ist.
Also, kann die Ausführung eines Triggers umgangen werden? Einfache Antwort: Ja! Und zwar auf mehreren Wegen, von denen ich hier nur einen anführen will.
Die Ausgangssituation:
CREATE TABLE dbo.test_trigger
(
c1 INT
, c2 CHAR(10)
)
GO
CREATE TRIGGER fool_me ON dbo.test_trigger FOR INSERT
AS
BEGIN
UPDATE dbo.test_trigger SET c2 = 'Hallo Welt'
END
GO
Dieser Trigger soll also bei jedem INSERT den Wert 'Hallo Welt' in die Spalte c2 schreiben. Das das funktioniert, kann man einfach feststellen:
INSERT INTO dbo.test_trigger (c1) VALUES(1)
INSERT INTO dbo.test_trigger (c1, c2) VALUES(1, 'wtf')
SELECT * FROM dbo.test_trigger
c1 c2
----------- ----------
1 Hallo Welt
1 Hallo Welt
So, egal,ob man nun explizit einen Wert in die Spalte c2 eintragen will oder nicht, der Wert wird durch den Trigger überschrieben.
Die Manipulation:
Und zwar nutzen wir die Spalte context_info in der master.dbo.sysprocesses Tabelle. Diese kann durch die Einstellung SET CONTEXT_INFO zusätzliche 128 Bytes pro Session oder Connection speichern. Zunächst ändern wir mal unseren Trigger ab.
ALTER TRIGGER fool_me ON dbo.test_trigger FOR INSERT AS
IF NOT (SELECT context_info FROM master.dbo.sysprocesses
WHERE spid = @@SPID) = 0xA
BEGIN
UPDATE dbo.test_trigger SET c2 = 'Hallo Welt'
END
GO
So, nun können wir SET CONTEXT_INFO verwenden:
SET CONTEXT_INFO 0xA
INSERT INTO dbo.test_trigger (c1, c2) VALUES(2, 'q.e.d')
SET CONTEXT_INFO 0
Das Ergebnis:
SELECT * FROM dbo.test_trigger
c1 c2
----------- ----------
1 Hallo Welt
1 Hallo Welt
2 q.e.d
Nochmals der Hinweis: Dies ist kein Skript, was in Produktionssystemen verwendet werden sollte. Die Manipulation von SET CONTEXT_INFO kann zu Nebeneffekten führen bei anderen DB Objekten, die ebenfalls auf diese Einstellung zugreifen.
Danke an Jonathan van Houtte!
Es gibt keine Unterschiede zwischen ISNULL und COALESCE. Diese Meinung kann man recht häufig in Online Communities lesen. Der einzige Unterschied zwischen beiden ist, daß ISNULL SQL Server spezifisch ist, während COALESCE ANSI-SQL Standard ist. Auch dies kann man recht häufig lesen. Beide beschäftigen sich mit der Umwandlung von NULL und damit fehlenden Informationen. Wozu also einen eigenen Beitrag?