Views mit INSTEAD OF UPDATE-Trigger

Ich stand vor der Problemstellung, eine Tabelle zu optimieren - da diese Tabelle aber an vielen Stellen verwendet wird 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

Und nun? Es war schnell herausgefunden, dass mit “an Verknüpfung beteiligt” das UPDATE-Statement selbst gemeint ist. Nach einigen Tests und noch mehr Recherche fand ich dann heraus, dass es an der UPDATE...FROM Anweisung liegt. Ein einfaches UPDATE-Statement(nach ANSI-Standard) funktioniert dagegen hervorragend.

Wozu diese Einschränkung gut sein soll weiß ich nicht. Bei Tabellen funktioniert das Spiel wie gewohnt. Nur Views unterliegen dieser Einschränkung.

Wer’s selbst mal probieren will:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
CREATE VIEW Test_InseteadOfUpdate
AS
SELECT 1 AS test
GO
CREATE TRIGGER dbo.OnUpdate
ON dbo.Test_InseteadOfUpdate
INSTEAD OF UPDATE
AS BEGIN
SET NOCOUNT ON
END
GO
-- Funktioniert
UPDATE Test_InseteadOfUpdate
SET test = 2
WHERE test = 1
GO
-- Fehler
UPDATE Test_InseteadOfUpdate
SET test = upd.b
FROM (
SELECT 1 AS a,
2 AS b
) AS upd
WHERE test = upd.a
GO
DROP VIEW Test_InseteadOfUpdate

Der ANSI-Standard erlaubt auch Unterabfragen. Aber das bringt (zumindest mir) nicht viel, da die bisherigen Abfragen auch ohne jegliche Anpassung noch funktionieren sollen.

Das Gleiche gilt im Übrigen auch für DELETE-Anweisungen und INSTEAD OF DELETE-Trigger auf Views…