Als Teil der Serie zu Tabellenausdrücken habe ich letzten Monat mit der Berichterstattung über Ansichten begonnen. Insbesondere habe ich mit der Behandlung logischer Aspekte von Views begonnen und deren Design mit dem von abgeleiteten Tabellen und CTEs verglichen. In diesem Monat werde ich die Behandlung logischer Aspekte von Ansichten fortsetzen und meine Aufmerksamkeit auf SELECT *- und DDL-Änderungen richten.
Der Code, den ich in diesem Artikel verwende, kann in jeder Datenbank ausgeführt werden, aber in meinen Demos verwende ich TSQLV5 – dieselbe Beispieldatenbank, die ich in früheren Artikeln verwendet habe. Das Skript, das TSQLV5 erstellt und füllt, finden Sie hier und sein ER-Diagramm hier.
Die Verwendung von SELECT * in der inneren Abfrage der Ansicht ist eine schlechte Idee
Im Schlussabschnitt des Artikels vom letzten Monat habe ich eine Frage als Denkanstoß gestellt. Ich habe erklärt, dass ich früher in der Serie für die Verwendung von SELECT * in den inneren Tabellenausdrücken plädiert habe, die mit abgeleiteten Tabellen und CTEs verwendet werden. In Teil 3 der Serie finden Sie Einzelheiten, wenn Sie Ihr Gedächtnis auffrischen müssen. Ich habe Sie dann gebeten, darüber nachzudenken, ob die gleiche Empfehlung noch für den inneren Tabellenausdruck gelten würde, der zum Definieren von View verwendet wird. Vielleicht war der Titel dieses Abschnitts schon ein Spoiler, aber ich sage gleich, dass es mit Views eigentlich eine sehr schlechte Idee ist.
Ich beginne mit Ansichten, die nicht mit dem SCHEMABINDING-Attribut definiert sind, das relevante DDL-Änderungen an abhängigen Objekten verhindert, und erkläre dann, wie sich die Dinge ändern, wenn Sie dieses Attribut verwenden.
Ich werde direkt zu einem Beispiel springen, da dies der einfachste Weg ist, mein Argument zu präsentieren.
Verwenden Sie den folgenden Code, um eine Tabelle mit dem Namen dbo.T1 und eine Ansicht mit dem Namen dbo.V1 basierend auf einer Abfrage mit SELECT * für die Tabelle zu erstellen:
TSQLV5 VERWENDEN; DROP VIEW IF EXISTS dbo.V1;DROP TABLE IF EXISTS dbo.T1;GO CREATE TABLE dbo.T1( keycol INT NOT NULL IDENTITY CONSTRAINT PK_T1 PRIMARY KEY, intcol INT NOT NULL, charcol VARCHAR(10) NOT NULL); INSERT INTO dbo.T1(intcol, charcol) VALUES (10, 'A'), (20, 'B');GO CREATE OR ALTER VIEW dbo.V1AS SELECT * FROM dbo.T1;GO
Beachten Sie, dass die Tabelle derzeit die Spalten keycol, intcol und charcol enthält.
Verwenden Sie den folgenden Code, um die Ansicht abzufragen:
SELECT * FROM dbo.V1;
Sie erhalten die folgende Ausgabe:
keycol intcol charcol---------- ----------- ----------1 10 A2 20 B
Nichts Besonderes hier.
Wenn Sie eine Ansicht erstellen, zeichnet SQL Server Metadateninformationen in einer Reihe von Katalogobjekten auf. Es zeichnet einige allgemeine Informationen auf, die Sie über sys.views abfragen können, die Ansichtsdefinition, die Sie über sys.sql_modules abfragen können, Spalteninformationen, die Sie über sys.columns abfragen können, und weitere Informationen sind über andere Objekte verfügbar. Was für unsere Diskussion auch relevant ist, ist, dass Sie mit SQL Server Zugriffsberechtigungen für Ansichten steuern können. Wovor ich Sie warnen möchte, wenn Sie SELECT * im inneren Tabellenausdruck der Ansicht verwenden, ist, was passieren kann, wenn DDL-Änderungen auf zugrunde liegende abhängige Objekte angewendet werden.
Verwenden Sie den folgenden Code, um einen Benutzer namens user1 zu erstellen, und erteilen Sie dem Benutzer die Berechtigung, die Spalten keycol und intcol aus der Ansicht auszuwählen, aber nicht charcol:
BENUTZER LÖSCHEN, WENN VORHANDEN user1; BENUTZER ERSTELLEN user1 OHNE LOGIN; GRANT SELECT ON dbo.V1(keycol, intcol) TO user1;
Lassen Sie uns an dieser Stelle einige der aufgezeichneten Metadaten zu unserer Ansicht untersuchen. Verwenden Sie den folgenden Code, um den Eintrag zurückzugeben, der die Ansicht von sys.views darstellt:
SELECT SCHEMA_NAME(schema_id) AS schemaname, name, object_id, type_descFROM sys.viewsWHERE object_id =OBJECT_ID(N'dbo.V1');
Dieser Code generiert die folgende Ausgabe:
schemaname name object_id type_desc---------- ----- ----------- ----------dbo V1 130099504 VIEWVerwenden Sie den folgenden Code, um die Ansichtsdefinition von sys.modules abzurufen:
SELECT-Definition FROM sys.sql_modulesWHERE object_id =OBJECT_ID(N'dbo.V1');Eine andere Möglichkeit ist die Verwendung der OBJECT_DEFINITION-Funktion wie folgt:
SELECT OBJECT_DEFINITION(OBJECT_ID(N'dbo.V1'));Sie erhalten die folgende Ausgabe:
CREATE VIEW dbo.V1AS SELECT * FROM dbo.T1;Verwenden Sie den folgenden Code, um die Spaltendefinitionen der Ansicht aus sys.columns abzufragen:
SELECT name AS column_name, column_id, TYPE_NAME(system_type_id) AS data_typeFROM sys.columnsWHERE object_id =OBJECT_ID(N'dbo.V1');Wie erwartet erhalten Sie Informationen zu den drei Spalten der Ansicht keycol, intcol und charcol:
column_name column_id data_type------------ ----------- ----------keycol 1 intcol 2 intcharcol 3 varcharBeachten Sie die Spalten-IDs (Ordnungsstellen), die den Spalten zugeordnet sind.
Sie können ähnliche Informationen erhalten, indem Sie die standardmäßige Informationsschemaansicht INFORMATION_SCHEMA.COLUMNS wie folgt abfragen:
SELECT COLUMN_NAME, ORDINAL_POSITION, DATA_TYPEFROM INFORMATION_SCHEMA.COLUMNSWHERE TABLE_SCHEMA =N'dbo' AND TABLE_NAME =N'V1';Um die Abhängigkeitsinformationen der Ansicht (Objekte, auf die sie sich bezieht) abzurufen, können Sie sys.dm_sql_referenced_entities wie folgt abfragen:
SELECT OBJECT_NAME(referenced_id) AS referenced_object, referenced_minor_id, COL_NAME(referenced_id, referenced_minor_id) AS column_nameFROM sys.dm_sql_referenced_entities(N'dbo.V1', N'OBJECT');Die Abhängigkeit finden Sie in der Tabelle T1 und in ihren drei Spalten:
referenziertes_Objekt referenzierte_Minor_ID Spaltenname------------------ ------------------- ------- ----T1 0 NULLT1 1 keycolT1 2 intcolT1 3 charcolWie Sie wahrscheinlich erraten können, ist der Wert reference_minor_id für Spalten die Spalten-ID, die Sie zuvor gesehen haben.
Wenn Sie die Berechtigungen von Benutzer1 für V1 erhalten möchten, können Sie sys.database_permissions wie folgt abfragen:
SELECT OBJECT_NAME(major_id) AS referenced_object, minor_id, COL_NAME(major_id, minor_id) AS column_name, permission_nameFROM sys.database_permissionsWHERE major_id =OBJECT_ID(N'dbo.V1') AND grantee_principal_id =USER_ID(N'user1');Dieser Code generiert die folgende Ausgabe, die bestätigt, dass Benutzer1 tatsächlich ausgewählte Berechtigungen nur für keycol und intcol hat, aber nicht für charcol:
Referenziertes_Objekt untergeordnete_ID Spaltenname Berechtigungsname------------------ ----------- ------------ -- --------------V1 1 keycol SELECTV1 2 intcol SELECTAuch hier ist der Wert minor_id die Spalten-ID, die Sie zuvor gesehen haben. Unser Benutzer user1 hat Berechtigungen für die Spalten mit den IDs 1 und 2.
Führen Sie als Nächstes den folgenden Code aus, um sich als Benutzer1 auszugeben und zu versuchen, alle Spalten von V1 abzufragen:
ALS BENUTZER AUSFÜHREN =N'user1'; SELECT * FROM dbo.V1;Wie zu erwarten, erhalten Sie einen Berechtigungsfehler aufgrund fehlender Berechtigung zum Abfragen von charcol:
Msg 230, Level 14, State 1, Line 141
Die SELECT-Berechtigung wurde für die Spalte „charcol“ des Objekts „V1“, Datenbank „TSQLV5“, Schema „dbo“ verweigert.Versuchen Sie, nur keycol und intcol abzufragen:
SELECT keycol, intcol FROM dbo.V1;Diesmal wird die Abfrage erfolgreich ausgeführt und die folgende Ausgabe generiert:
keycol intcol---------- -----------1 102 20Bisher keine Überraschungen.
Führen Sie den folgenden Code aus, um zu Ihrem ursprünglichen Benutzer zurückzukehren:
Zurück;Lassen Sie uns nun ein paar strukturelle Änderungen an der zugrunde liegenden Tabelle dbo.T1 vornehmen. Führen Sie den folgenden Code aus, um zuerst zwei Spalten namens datecol und binarycol hinzuzufügen und dann die Spalte intcol zu löschen:
ALTER TABLE dbo.T1 ADD datecol DATE NOT NULL DEFAULT('99991231'), binarycol VARBINARY(3) NOT NULL DEFAULT(0x112233); ALTER TABLE dbo.T1 DROP COLUMN intcol;SQL Server hat die strukturellen Änderungen an Spalten, auf die von der Ansicht verwiesen wird, nicht abgelehnt, da die Ansicht nicht mit dem SCHEMABINDING-Attribut erstellt wurde. Nun zum Fang. Zu diesem Zeitpunkt hat SQL Server die Metadateninformationen der Ansicht in den verschiedenen Katalogobjekten noch nicht aktualisiert.
Verwenden Sie den folgenden Code, um die Ansicht abzufragen, immer noch mit Ihrem ursprünglichen Benutzer (noch nicht Benutzer1):
SELECT * FROM dbo.V1;Sie erhalten die folgende Ausgabe:
keycol intcol charcol---------- ---------- ----------1 A 9999-12-312 B 9999-12-31Beachten Sie, dass intcol tatsächlich den Inhalt von charcol und charcol den Inhalt von datecol zurückgibt. Denken Sie daran, es gibt kein intcol mehr in der Tabelle, aber es gibt datecol. Außerdem erhalten Sie die neue Spalte "binarycol" nicht zurück.
Um herauszufinden, was los ist, verwenden Sie den folgenden Code, um die Spaltenmetadaten der Ansicht abzufragen:
SELECT name AS column_name, column_id, TYPE_NAME(system_type_id) AS data_typeFROM sys.columnsWHERE object_id =OBJECT_ID(N'dbo.V1');Dieser Code generiert die folgende Ausgabe:
column_name column_id data_type------------ ----------- ----------keycol 1 intcol 2 intcharcol 3 varcharWie Sie sehen können, werden die Metadaten der Ansicht immer noch nicht aktualisiert. Sie können intcol als Spalten-ID 2 und charcol als Spalten-ID 3 sehen. In der Praxis existiert intcol nicht mehr, charcol soll Spalte 2 sein und datecol soll Spalte 3 sein.
Lassen Sie uns prüfen, ob sich die Berechtigungsinformationen geändert haben:
SELECT OBJECT_NAME(major_id) AS referenced_object, minor_id, COL_NAME(major_id, minor_id) AS column_name, permission_nameFROM sys.database_permissionsWHERE major_id =OBJECT_ID(N'dbo.V1') AND grantee_principal_id =USER_ID(N'user1');Sie erhalten die folgende Ausgabe:
Referenziertes_Objekt untergeordnete_ID Spaltenname Berechtigungsname------------------ ----------- ------------ -- --------------V1 1 keycol SELECTV1 2 intcol SELECTBerechtigungsinformationen zeigen, dass Benutzer1 Berechtigungen für die Spalten 1 und 2 in der Ansicht hat. Obwohl Metadaten davon ausgehen, dass Spalte 2 intcol heißt, wird sie in der Praxis tatsächlich auf charcol in T1 abgebildet. Das ist gefährlich, da Benutzer1 keinen Zugriff auf charcol haben soll. Was ist, wenn diese Spalte im wirklichen Leben vertrauliche Informationen wie Passwörter enthält?
Lassen Sie uns wieder user1 imitieren und alle View-Spalten abfragen:
ALS BENUTZER AUSFÜHREN ='user1'; SELECT * FROM dbo.V1;Sie erhalten einen Berechtigungsfehler, der besagt, dass Sie keinen Zugriff auf charcol:
haben Nachricht 230, Ebene 14, Status 1, Zeile 211
Die SELECT-Berechtigung wurde für die Spalte „charcol“ des Objekts „V1“, Datenbank „TSQLV5“, Schema „dbo“ verweigert.Sehen Sie sich jedoch an, was passiert, wenn Sie explizit nach keycol und intcol fragen:
SELECT keycol, intcol FROM dbo.V1;Sie erhalten die folgende Ausgabe:
keycol intcol---------- ----------1 A2 BDiese Abfrage ist erfolgreich, sie gibt nur den Inhalt von charcol unter intcol zurück. Unser Benutzer user1 soll keinen Zugriff auf diese Informationen haben. Hoppla!
Kehren Sie an dieser Stelle zum ursprünglichen Benutzer zurück, indem Sie den folgenden Code ausführen:
Zurück;SQL-Modul aktualisieren
Sie können deutlich sehen, dass die Verwendung von SELECT * im inneren Tabellenausdruck der Ansicht eine schlechte Idee ist. Aber es ist nicht nur das. Im Allgemeinen ist es eine gute Idee, die Metadaten der Ansicht nach jeder DDL-Änderung an referenzierten Objekten und Spalten zu aktualisieren. Sie können dies mit sp_refreshview oder dem allgemeineren sp_refreshmodule wie folgt tun:
EXEC sys.sp_refreshsqlmodule N'dbo.V1';Fragen Sie die Ansicht erneut ab, nachdem ihre Metadaten aktualisiert wurden:
SELECT * FROM dbo.V1;Diesmal erhalten Sie die erwartete Ausgabe:
keycol charcol datecol binarycol---------- ---------- ---------- ---------1 A 9999 -12-31 0x1122332 B 9999-12-31 0x112233Die Spalte charcol ist richtig benannt und zeigt die richtigen Daten; Sie sehen intcol nicht, und Sie sehen die neuen Spalten datecol und binarycol.
Fragen Sie die Spaltenmetadaten der Ansicht ab:
SELECT name AS column_name, column_id, TYPE_NAME(system_type_id) AS data_typeFROM sys.columnsWHERE object_id =OBJECT_ID(N'dbo.V1');Die Ausgabe zeigt jetzt die korrekten Spaltenmetadateninformationen:
column_name column_id data_type------------ ----------- ----------keycol 1 intcharcol 2 varchardatecol 3 datebinarycol 4 varbinaryAbfrage der Berechtigungen von Benutzer1 für die Ansicht:
SELECT OBJECT_NAME(major_id) AS referenced_object, minor_id, COL_NAME(major_id, minor_id) AS column_name, permission_nameFROM sys.database_permissionsWHERE major_id =OBJECT_ID(N'dbo.V1') AND grantee_principal_id =USER_ID(N'user1');Sie erhalten die folgende Ausgabe:
Referenziertes_Objekt untergeordnete_ID Spaltenname Berechtigungsname------------------ ----------- ------------ -- --------------V1 1 keycol SELECTDie Berechtigungsinformationen sind jetzt korrekt. Unser Benutzer user1 hat nur die Berechtigung, keycol auszuwählen, und die Berechtigungsinformationen für intcol wurden entfernt.
Um sicherzugehen, dass alles in Ordnung ist, testen wir dies, indem wir uns als Benutzer1 ausgeben und die Ansicht abfragen:
ALS BENUTZER AUSFÜHREN ='user1'; SELECT * FROM dbo.V1;Sie erhalten zwei Berechtigungsfehler aufgrund fehlender Berechtigungen für datecol und binarycol:
Msg 230, Level 14, State 1, Line 281
Die SELECT-Berechtigung wurde für die Spalte „datecol“ des Objekts „V1“, Datenbank „TSQLV5“, Schema „dbo“ verweigert.Msg 230, Level 14, State 1, Line 281
Die SELECT-Berechtigung wurde für die Spalte „binarycol“ des Objekts „V1“, Datenbank „TSQLV5“, Schema „dbo“ verweigert.Versuchen Sie, keycol und intcol abzufragen:
SELECT keycol, intcol FROM dbo.V1;Diesmal sagt der Fehler korrekterweise, dass es keine Spalte mit dem Namen intcol:
gibt Nachricht 207, Ebene 16, Status 1, Zeile 279Ungültiger Spaltenname 'intcol'.
Abfrage nur intcol:
SELECT keycol FROM dbo.V1;Diese Abfrage wird erfolgreich ausgeführt und generiert die folgende Ausgabe:
keycol-----------12Kehren Sie an dieser Stelle zu Ihrem ursprünglichen Benutzer zurück, indem Sie den folgenden Code ausführen:
Zurück;Reicht es aus, SELECT * zu vermeiden und explizite Spaltennamen zu verwenden?
Wenn Sie einer Praxis folgen, die besagt, dass kein SELECT * im inneren Tabellenausdruck der Ansicht enthalten ist, würde dies ausreichen, um Sie vor Ärger zu bewahren? Mal sehen...
Verwenden Sie den folgenden Code, um die Tabelle und die Ansicht neu zu erstellen, nur listen Sie diesmal die Spalten explizit in der inneren Abfrage der Ansicht auf:
DROP VIEW IF EXISTS dbo.V1;DROP TABLE IF EXISTS dbo.T1;GO CREATE TABLE dbo.T1( keycol INT NOT NULL IDENTITY CONSTRAINT PK_T1 PRIMARY KEY, intcol INT NOT NULL, charcol VARCHAR(10) NOT NULL); INSERT INTO dbo.T1(intcol, charcol) VALUES (10, 'A'), (20, 'B');GO CREATE OR ALTER VIEW dbo.V1AS SELECT keycol, intcol, charcol FROM dbo.T1;GOAnsicht abfragen:
SELECT * FROM dbo.V1;Sie erhalten die folgende Ausgabe:
keycol intcol charcol---------- ----------- ----------1 10 A2 20 BErteilen Sie erneut user1 die Berechtigung, keycol und intcol auszuwählen:
GRANT SELECT ON dbo.V1(keycol, intcol) TO user1;Wenden Sie als Nächstes dieselben strukturellen Änderungen wie zuvor an:
ALTER TABLE dbo.T1 ADD datecol DATE NOT NULL DEFAULT('99991231'), binarycol VARBINARY(3) NOT NULL DEFAULT(0x112233); ALTER TABLE dbo.T1 DROP COLUMN intcol;Beachten Sie, dass SQL Server diese Änderungen akzeptiert hat, obwohl die Ansicht einen expliziten Verweis auf intcol enthält. Das liegt wiederum daran, dass die Ansicht ohne die SCHEMABINDING-Option erstellt wurde.
Ansicht abfragen:
SELECT * FROM dbo.V1;An diesem Punkt generiert SQL Server den folgenden Fehler:
Nachricht 207, Ebene 16, Status 1, Prozedur V1, Zeile 5 [Batch-Startzeile 344]
Ungültiger Spaltenname 'intcol'.Msg 4413, Level 16, State 1, Line 345
Die Ansicht oder Funktion 'dbo.V1' konnte aufgrund von Bindungsfehlern nicht verwendet werden.SQL Server hat versucht, die intcol-Referenz in der Ansicht aufzulösen, und war natürlich nicht erfolgreich.
Aber was wäre, wenn Ihr ursprünglicher Plan darin bestand, intcol zu löschen und später wieder hinzuzufügen? Verwenden Sie den folgenden Code, um es wieder hinzuzufügen, und fragen Sie dann die Ansicht ab:
ALTER TABLE dbo.T1 ADD intcol INT NOT NULL DEFAULT(0); SELECT * FROM dbo.V1;Dieser Code generiert die folgende Ausgabe:
keycol intcol charcol---------- ----------- ----------1 0 A2 0 BDas Ergebnis scheint korrekt zu sein.
Wie wäre es, wenn Sie die Ansicht als Benutzer1 abfragen? Versuchen wir es:
ALS BENUTZER AUSFÜHREN ='user1';SELECT * FROM dbo.V1;Beim Abfragen aller Spalten erhalten Sie den erwarteten Fehler aufgrund fehlender Berechtigungen für charcol:
Nachricht 230, Ebene 14, Status 1, Zeile 367
Die SELECT-Berechtigung wurde für die Spalte „charcol“ des Objekts „V1“, Datenbank „TSQLV5“, Schema „dbo“ verweigert.Keycol und intcol explizit abfragen:
SELECT keycol, intcol FROM dbo.V1;Sie erhalten die folgende Ausgabe:
keycol intcol---------- -----------1 02 0Es scheint, als wäre alles in Ordnung, da Sie SELECT * nicht in der inneren Abfrage der Ansicht verwendet haben, obwohl Sie die Metadaten der Ansicht nicht aktualisiert haben. Dennoch kann es eine gute Praxis sein, die Metadaten der Ansicht zu aktualisieren, nachdem DDL Änderungen an referenzierten Objekten und Spalten vorgenommen hat, um auf der sicheren Seite zu sein.
Kehren Sie an dieser Stelle zu Ihrem ursprünglichen Benutzer zurück, indem Sie den folgenden Code ausführen:
Zurück;SCHEMABINDUNG
Mit dem View-Attribut SCHEMABINDING können Sie sich viele der oben genannten Probleme ersparen. Einer der Schlüssel zur Vermeidung der Probleme, die Sie zuvor gesehen haben, besteht darin, SELECT * nicht in der inneren Abfrage der Ansicht zu verwenden. Aber es gibt auch das Problem struktureller Änderungen an abhängigen Objekten, wie das Löschen von referenzierten Spalten, die immer noch zu Fehlern beim Abfragen der Ansicht führen können. Wenn Sie das Ansichtsattribut SCHEMABINDING verwenden, dürfen Sie SELECT * nicht in der inneren Abfrage verwenden. Darüber hinaus lehnt SQL Server Versuche ab, relevante DDL-Änderungen auf abhängige Objekte und Spalten anzuwenden. Mit relevant meine ich Änderungen wie das Löschen einer referenzierten Tabelle oder Spalte. Das Hinzufügen einer Spalte zu einer referenzierten Tabelle ist offensichtlich kein Problem, daher verhindert SCHEMABINDING eine solche Änderung nicht.
Um dies zu demonstrieren, verwenden Sie den folgenden Code, um die Tabelle und die Ansicht mit SCHEMABINDING in der Ansichtsdefinition neu zu erstellen:
DROP VIEW IF EXISTS dbo.V1;DROP TABLE IF EXISTS dbo.T1;GO CREATE TABLE dbo.T1( keycol INT NOT NULL IDENTITY CONSTRAINT PK_T1 PRIMARY KEY, intcol INT NOT NULL, charcol VARCHAR(10) NOT NULL); INSERT INTO dbo.T1(intcol, charcol) VALUES (10, 'A'), (20, 'B');GO CREATE OR ALTER VIEW dbo.V1 WITH SCHEMABINDINGAS SELECT * FROM dbo.T1;GOSie erhalten eine Fehlermeldung:
Nachricht 1054, Ebene 15, Status 6, Prozedur V1, Zeile 5 [Batch-Startzeile 387]
Syntax '*' ist in schemagebundenen Objekten nicht zulässig.Wenn Sie SCHEMABINDING verwenden, dürfen Sie SELECT * nicht im inneren Tabellenausdruck der Ansicht verwenden.
Versuchen Sie erneut, die Ansicht zu erstellen, diesmal nur mit einer expliziten Spaltenliste:
CREATE OR ALTER VIEW dbo.V1 WITH SCHEMABINDINGAS SELECT keycol, intcol, charcol FROM dbo.T1;GODiesmal wird die Ansicht erfolgreich erstellt.
Gewähren Sie user1 Berechtigungen für keycol und intcol:
GRANT SELECT ON dbo.V1(keycol, intcol) TO user1;Versuchen Sie als Nächstes, strukturelle Änderungen auf die Tabelle anzuwenden. Fügen Sie zuerst ein paar Spalten hinzu:
ALTER TABLE dbo.T1 ADD datecol DATE NOT NULL DEFAULT('99991231'), binarycol VARBINARY(3) NOT NULL DEFAULT(0x112233);Das Hinzufügen von Spalten ist kein Problem, da sie nicht Teil vorhandener schemagebundener Ansichten sein können, sodass dieser Code erfolgreich abgeschlossen wird.
Versuchen Sie, die Spalte intcol:
zu löschenALTER TABLE dbo.T1 DROP COLUMN intcol;Sie erhalten die folgende Fehlermeldung:
Msg 5074, Level 16, State 1, Line 418
Das Objekt 'V1' ist abhängig von Spalte 'intcol'.Nachricht 4922, Ebene 16, Status 9, Zeile 418
ALTER TABLE DROP COLUMN intcol fehlgeschlagen, da ein oder mehrere Objekte auf diese Spalte zugreifen.Das Löschen oder Ändern von referenzierten Spalten ist nicht zulässig, wenn schemagebundene Objekte vorhanden sind.
Wenn Sie immer noch intcol löschen müssen, müssen Sie zuerst die schemagebundene referenzierende Ansicht löschen, die Änderung anwenden und dann die Ansicht neu erstellen und Berechtigungen neu zuweisen, etwa so:
DROP VIEW IF EXISTS dbo.V1;GO ALTER TABLE dbo.T1 DROP COLUMN intcol;GO CREATE OR ALTER VIEW dbo.V1 WITH SCHEMABINDINGAS SELECT keycol, charcol, datecol, binarycol FROM dbo.T1;GO GRANT SELECT ON dbo. V1(Schlüsselspalte, Datumspalte, Binärspalte) TO user1;GOAn dieser Stelle muss die Ansichtsdefinition natürlich nicht aktualisiert werden, da Sie sie neu erstellt haben.
Nachdem Sie mit dem Testen fertig sind, führen Sie den folgenden Code zur Bereinigung aus:
ANZEIGE LÖSCHEN, WENN VORHANDEN dbo.V1;TABELLE LÖSCHEN, WENN VORHANDEN dbo.T1;BENUTZER LÖSCHEN, WENN VORHANDEN Benutzer1;Zusammenfassung
Die Verwendung von SELECT * im inneren Tabellenausdruck der Ansicht ist eine sehr schlechte Idee. Nachdem strukturelle Änderungen auf referenzierte Objekte angewendet wurden, könnten Sie falsche Spaltennamen erhalten und Benutzern sogar den Zugriff auf Daten ermöglichen, auf die sie keinen Zugriff haben sollten. Es ist eine wichtige Praxis, die referenzierten Spaltennamen explizit aufzulisten.
Durch die Verwendung von SCHEMABINDING in der Ansichtsdefinition werden Sie gezwungen, Spaltennamen explizit aufzulisten, und relevante strukturelle Änderungen an abhängigen Objekten werden von SQL Server abgelehnt. Daher scheint es immer eine gute Idee zu sein, Ansichten mit SCHEMBINDING zu erstellen. Es gibt jedoch einen Vorbehalt bei dieser Option. Wie Sie gesehen haben, wird das Anwenden struktureller Änderungen auf referenzierte Objekte bei Verwendung von SCHEMBINDING zu einem längeren und aufwändigeren Prozess. Dies kann insbesondere in Systemen ein Problem darstellen, die eine sehr hohe Verfügbarkeit aufweisen müssen. Stellen Sie sich vor, Sie müssen eine als VARCHAR(50) definierte Spalte in VARCHAR(60) ändern. Das ist keine zulässige Änderung, wenn eine mit SCHEMABINDING definierte Ansicht auf diese Spalte verweist. Die Auswirkungen des Löschens einer Reihe von referenzierenden Ansichten, die von anderen Ansichten referenziert werden könnten usw., könnten für das System problematisch sein. Kurz gesagt, es ist für Unternehmen nicht immer so einfach, einfach eine Richtlinie zu verabschieden, die besagt, dass SCHEMABINDING in allen Objekten verwendet werden sollte, die es unterstützen. Es sollte jedoch einfacher sein, eine Richtlinie zu übernehmen, um SELECT * in den inneren Abfragen von Ansichten nicht zu verwenden.
In Bezug auf Ansichten gibt es noch viel mehr zu entdecken. Fortsetzung nächsten Monat…