Database
 sql >> Baza danych >  >> RDS >> Database

Podstawy wyrażeń tabelowych, Część 10 – Widoki, SELECT * i zmiany DDL

W ramach serii o wyrażeniach tabelowych w zeszłym miesiącu zacząłem opisywać widoki. W szczególności zacząłem opisywać logiczne aspekty widoków i porównałem ich projekt z projektami tabel pochodnych i CTE. W tym miesiącu zamierzam kontynuować opisywanie logicznych aspektów widoków, skupiając swoją uwagę na zmianach SELECT * i DDL.

Kod, którego użyję w tym artykule, można wykonać w dowolnej bazie danych, ale w moich demonstracjach będę używał TSQLV5 — tej samej przykładowej bazy danych, której używałem w poprzednich artykułach. Skrypt tworzący i wypełniający TSQLV5 można znaleźć tutaj, a jego diagram ER znajduje się tutaj.

Użycie SELECT * w wewnętrznym zapytaniu widoku to zły pomysł

W końcowej części artykułu z zeszłego miesiąca zadałem pytanie jako materiał do przemyśleń. Wyjaśniłem, że wcześniej w serii opowiedziałem się za użyciem SELECT * w wewnętrznych wyrażeniach tabel używanych z tabelami pochodnymi i CTE. Zobacz część 3 serii, aby uzyskać szczegółowe informacje, jeśli chcesz odświeżyć swoją pamięć. Następnie poprosiłem cię, abyś zastanowił się, czy ta sama rekomendacja będzie nadal obowiązywać dla wewnętrznego wyrażenia tabeli używanego do definiowania widoku. Być może tytuł tej sekcji był już spoilerem, ale przyznam rację nietoperzowi, że z widokami to w rzeczywistości bardzo zły pomysł.

Zacznę od widoków, które nie są zdefiniowane za pomocą atrybutu SCHEMABINDING, który zapobiega istotnym zmianom DDL w obiektach zależnych, a następnie wyjaśnię, jak rzeczy się zmieniają, gdy używasz tego atrybutu.

Przejdę od razu do przykładu, ponieważ będzie to najłatwiejszy sposób przedstawienia mojej argumentacji.

Użyj poniższego kodu, aby utworzyć tabelę o nazwie dbo.T1 i widok o nazwie dbo.V1 w oparciu o zapytanie z SELECT * względem tabeli:

UŻYJ TSQLV5; 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); WSTAW W dbo.T1(intcol, charcol) WARTOŚCI (10, 'A'), (20, 'B');GO UTWÓRZ LUB ZMIEŃ WIDOK dbo.V1AS WYBIERZ * Z dbo.T1;GO

Zauważ, że tabela zawiera obecnie kolumny keycol, intcol i charcol.

Użyj następującego kodu, aby wysłać zapytanie do widoku:

WYBIERZ * Z dbo.V1;

Otrzymasz następujące dane wyjściowe:

keycol wewn. charcol----------- ----------- ----------1 10 A2 20 B

Nie ma tu nic specjalnego.

Podczas tworzenia widoku SQL Server rejestruje informacje o metadanych w wielu obiektach wykazu. Rejestruje pewne ogólne informacje, które można przeszukiwać przez sys.views, definicję widoku, które można przeszukiwać przez sys.sql_modules, informacje o kolumnach, które można przeszukiwać przez sys.columns, a więcej informacji jest dostępnych za pośrednictwem innych obiektów. W naszej dyskusji istotne jest również to, że SQL Server pozwala kontrolować uprawnienia dostępu w odniesieniu do widoków. To, przed czym chcę cię ostrzec, używając SELECT * w wewnętrznym wyrażeniu tabeli widoku, to to, co może się stać, gdy zmiany DDL zostaną zastosowane do bazowych obiektów zależnych.

Użyj poniższego kodu, aby utworzyć użytkownika o nazwie user1 i przyznać mu uprawnienia do wybierania kolumn keycol i intcol z widoku, ale nie charcol:

DROP USER IF EXISTS użytkownik1; CREATE USER user1 BEZ LOGOWANIA; PRZYZNAJ WYBÓR NA dbo.V1(keycol, intcol) TO user1;

W tym miejscu przyjrzyjmy się niektórym z zarejestrowanych metadanych związanych z naszym poglądem. Użyj następującego kodu, aby zwrócić wpis reprezentujący widok z sys.views:

 SELECT SCHEMA_NAME (schema_id) AS nazwa schematu, nazwa, object_id, type_descFROM sys.viewsWHERE object_id =OBJECT_ID (N'dbo.V1');

Ten kod generuje następujące dane wyjściowe:

nazwa schematu identyfikator_obiektu type_desc----------- ----- ----------- ----------dbo V1 130099504 WIDOK

Użyj następującego kodu, aby pobrać definicję widoku z sys.modules:

WYBIERZ definicję Z sys.sql_modulesWHERE object_id =OBJECT_ID (N'dbo.V1');

Inną opcją jest użycie funkcji OBJECT_DEFINITION w następujący sposób:

WYBIERZ OBJECT_DEFINITION(ID_OBIEKTU(N'dbo.V1'));

Otrzymasz następujące dane wyjściowe:

UTWÓRZ WIDOK dbo.V1AS WYBIERZ * Z dbo.T1;

Użyj następującego kodu, aby wysłać zapytanie do definicji kolumn widoku z sys.columns:

 SELECT nazwa AS nazwa_kolumny, id_kolumny, TYPE_NAME (identyfikator_typu_systemu) AS typ_danychFROM sys.columnsWHERE object_id =OBJECT_ID (N'dbo.V1');

Zgodnie z oczekiwaniami otrzymujesz informacje o trzech kolumnach widoku keycol, intcol i charcol:

nazwa_kolumny id_kolumny typ_danych--------------- ----------- ----------keycol 1 intintcol 2 intcharcol 3 varchar

Obserwuj identyfikatory kolumn (pozycje porządkowe), które są powiązane z kolumnami.

Podobne informacje można uzyskać, wysyłając zapytanie do standardowego widoku schematu informacji INFORMATION_SCHEMA.COLUMNS, na przykład:

SELECT COLUMN_NAME, ORDINAL_POSITION, DATA_TYPEFROM INFORMATION_SCHEMA.COLUMNSWHERE TABLE_SCHEMA =N'dbo' AND TABLE_NAME =N'V1';

Aby uzyskać informacje o zależnościach widoku (obiektach, do których się odnosi), możesz wykonać zapytanie sys.dm_sql_referenced_entities, na przykład:

 SELECT OBJECT_NAME (referencyjny_id) AS referenced_object, referenced_minor_id, COL_NAME (referencyjny_id, referenced_minor_id) AS nazwa_kolumnyFROM sys.dm_sql_referenced_entities (N'dbo.V1', N'OBJECT');

Zależność znajdziesz w tabeli T1 i jej trzech kolumnach:

referencyjny_obiekt referenced_minor_id nazwa_kolumny----------------- ------------------- ------- ---- T1 0 NULLT1 1 keycolT1 2 intcolT1 3 charcol

Jak można się domyślić, wartość reference_minor_id dla kolumn to identyfikator kolumny, który widziałeś wcześniej.

Jeśli chcesz uzyskać uprawnienia użytkownika 1 względem V1, możesz wykonać zapytanie sys.database_permissions, na przykład:

 SELECT OBJECT_NAME (major_id) AS referenced_object, minor_id, COL_NAME (major_id, minor_id) AS nazwa_kolumny, permission_nameFROM sys.database_permissionsWHERE major_id =OBJECT_ID(N'dbo.V1') AND grantee_principal_ID'(N) =USER_ID1 pre> 

Ten kod generuje następujące dane wyjściowe, potwierdzające, że rzeczywiście użytkownik 1 ma uprawnienia wyboru tylko względem keycol i intcol, ale nie względem charcol:

odnośny_obiekt minor_id nazwa_kolumny nazwa_uprawnienia----------------- ------------ -- --------------V1 1 klucz SELECTV1 2 wewn SELECT

Ponownie, wartość minor_id jest identyfikatorem kolumny, który widziałeś wcześniej. Nasz użytkownik, user1, ma uprawnienia do kolumn, których identyfikatory to 1 i 2.

Następnie uruchom następujący kod, aby podszyć się pod użytkownika 1 i spróbować wysłać zapytanie do wszystkich kolumn V1:

WYKONAJ JAKO UŻYTKOWNIK =N'użytk1'; WYBIERZ * Z dbo.V1;

Jak można się spodziewać, pojawia się błąd uprawnień z powodu braku uprawnień do zapytania charcol:

Msg 230, Level 14, State 1, Line 141
Odmowa uprawnienia SELECT w kolumnie 'charcol' obiektu 'V1', baza danych 'TSQLV5', schemat 'dbo'.

Spróbuj odpytywać tylko keycol i intcol:

SELECT keycol, intcol FROM dbo.V1;

Tym razem zapytanie działa pomyślnie, generując następujące dane wyjściowe:

keycol intcol----------- -----------1 102 20

Jak dotąd żadnych niespodzianek.

Uruchom następujący kod, aby powrócić do pierwotnego użytkownika:

WRÓĆ;

Teraz zastosujmy kilka zmian strukturalnych w tabeli bazowej dbo.T1. Uruchom następujący kod, aby najpierw dodać dwie kolumny o nazwach datecol i binarycol, a następnie usunąć kolumnę intcol:

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 nie odrzucił zmian strukturalnych w kolumnach, do których odwołuje się widok, ponieważ widok nie został utworzony z atrybutem SCHEMABINDING. Teraz do połowu. W tym momencie SQL Server nie odświeżył jeszcze informacji o metadanych widoku w różnych obiektach katalogu.

Użyj następującego kodu, aby wysłać zapytanie do widoku, nadal z pierwotnym użytkownikiem (jeszcze nie z użytkownikiem1):

WYBIERZ * Z dbo.V1;

Otrzymasz następujące dane wyjściowe:

keycol intcol charcol----------- ---------- ----------1 A 9999-12-312 B 9999-12-31 

Zauważ, że intcol faktycznie zwraca zawartość charcol, a charcol zwraca zawartość datecol. Pamiętaj, że w tabeli nie ma już danych wewnętrznych, ale jest datecol. Ponadto nie odzyskasz nowej kolumny binarycol.

Aby spróbować dowiedzieć się, co się dzieje, użyj następującego kodu do zapytania o metadane kolumn widoku:

 SELECT nazwa AS nazwa_kolumny, id_kolumny, TYPE_NAME (identyfikator_typu_systemu) AS typ_danychFROM sys.columnsWHERE object_id =OBJECT_ID (N'dbo.V1');

Ten kod generuje następujące dane wyjściowe:

nazwa_kolumny id_kolumny typ_danych--------------- ----------- ----------keycol 1 intintcol 2 intcharcol 3 varchar

Jak widać, metadane widoku nadal nie są odświeżane. Możesz zobaczyć intcol jako kolumnę o identyfikatorze 2, a charcol jako kolumnę o identyfikatorze 3. W praktyce intcol już nie istnieje, charcol ma być kolumną 2, a datecol ma być kolumną 3.

Sprawdźmy, czy nastąpiła jakaś zmiana w informacjach o uprawnieniach:

 SELECT OBJECT_NAME (major_id) AS referenced_object, minor_id, COL_NAME (major_id, minor_id) AS nazwa_kolumny, permission_nameFROM sys.database_permissionsWHERE major_id =OBJECT_ID(N'dbo.V1') AND grantee_principal_ID'(N) =USER_ID1 pre> 

Otrzymasz następujące dane wyjściowe:

odnośny_obiekt minor_id nazwa_kolumny nazwa_uprawnienia----------------- ------------ -- --------------V1 1 klucz SELECTV1 2 wewn SELECT

Informacje o uprawnieniach pokazują, że użytkownik1 ma uprawnienia do kolumn 1 i 2 w widoku. Jednak mimo że metadane uważają, że kolumna 2 nazywa się intcol, w praktyce jest mapowana na charcol w T1. To niebezpieczne, ponieważ użytkownik 1 nie powinien mieć dostępu do charcol. Co jeśli w rzeczywistości ta kolumna zawiera poufne informacje, takie jak hasła.

Podszyjmy się ponownie pod użytkownika 1 i zapytajmy wszystkie kolumny widoku:

WYKONAJ JAKO UŻYTKOWNIK ='użytkownik1'; WYBIERZ * Z dbo.V1;

Pojawia się błąd uprawnień mówiący, że nie masz dostępu do charcol:

Msg 230, Level 14, State 1, Line 211
Odmówiono uprawnienia SELECT w kolumnie 'charcol' obiektu 'V1', baza danych 'TSQLV5', schemat 'dbo'.

Zobacz jednak, co się stanie, gdy wyraźnie poprosisz o keycol i intcol:

SELECT keycol, intcol FROM dbo.V1;

Otrzymasz następujące dane wyjściowe:

keycol intcol----------- ----------1 A2 B

To zapytanie się powiedzie, tylko zwraca zawartość charcol pod intcol. Nasz użytkownik, user1, nie powinien mieć dostępu do tych informacji. Ups!

W tym momencie powróć do pierwotnego użytkownika, uruchamiając następujący kod:

WRÓĆ;

Odśwież moduł SQL

Widać wyraźnie, że użycie SELECT * w wewnętrznym wyrażeniu tabeli widoku to zły pomysł. Ale to nie tylko to. Ogólnie rzecz biorąc, dobrym pomysłem jest odświeżenie metadanych widoku po każdej zmianie DDL w odniesieniu do obiektów i kolumn. Możesz to zrobić za pomocą sp_refreshview lub bardziej ogólnego sp_refreshmodule, na przykład:

EXEC sys.sp_refreshsqlmodule N'dbo.V1';

Zapytaj widok ponownie, teraz, gdy jego metadane zostały odświeżone:

WYBIERZ * Z dbo.V1;

Tym razem otrzymujesz oczekiwany wynik:

keycol charcol datecol binarycol--------------- ---------- ---------- ---------1 A 9999 -12-31 0x1122332 B 9999-12-31 0x112233

Kolumna charcol ma prawidłową nazwę i pokazuje poprawne dane; nie widzisz intcol, a widzisz nowe kolumny datecol i binarycol.

Zapytaj o metadane kolumn widoku:

 SELECT nazwa AS nazwa_kolumny, id_kolumny, TYPE_NAME (identyfikator_typu_systemu) AS typ_danychFROM sys.columnsWHERE object_id =OBJECT_ID (N'dbo.V1');

Dane wyjściowe pokazują teraz prawidłowe informacje o metadanych kolumn:

nazwa_kolumny id_kolumny typ_danych------------ ----------- ----------keycol 1 intcharcol 2 varchardatecol 3 databinarycol 4 varbinary

Zapytaj o uprawnienia użytkownika1 względem widoku:

 SELECT OBJECT_NAME (major_id) AS referenced_object, minor_id, COL_NAME (major_id, minor_id) AS nazwa_kolumny, permission_nameFROM sys.database_permissionsWHERE major_id =OBJECT_ID(N'dbo.V1') AND grantee_principal_ID'(N) =USER_ID1 pre> 

Otrzymasz następujące dane wyjściowe:

odnośny_obiekt minor_id nazwa_kolumny nazwa_uprawnienia----------------- ------------ -- --------------V1 1 kolor klawiszy WYBIERZ

Informacje o uprawnieniach są teraz poprawne. Nasz użytkownik, user1, ma uprawnienia tylko do wybierania keycol, a informacje o uprawnieniach dla Intcol zostały usunięte.

Aby upewnić się, że wszystko jest w porządku, przetestujmy to, podszywając się pod użytkownika 1 i wysyłając zapytanie do widoku:

WYKONAJ JAKO UŻYTKOWNIK ='użytkownik1'; WYBIERZ * Z dbo.V1;

Otrzymasz dwa błędy uprawnień z powodu braku uprawnień do datecol i binarycol:

Msg 230, Level 14, State 1, Line 281
Odmowa uprawnienia SELECT w kolumnie „datecol” obiektu „V1”, baza danych „TSQLV5”, schemat „dbo”.

Msg 230, Level 14, State 1, Line 281
Odmowa uprawnienia SELECT w kolumnie 'binarycol' obiektu 'V1', baza danych 'TSQLV5', schemat 'dbo'.

Spróbuj zapytać keycol i intcol:

SELECT keycol, intcol FROM dbo.V1;

Tym razem błąd poprawnie mówi, że nie ma kolumny o nazwie intcol:

Msg 207, poziom 16, stan 1, linia 279

Nieprawidłowa nazwa kolumny „intcol”.

Zapytanie tylko intcol:

WYBIERZ keycol FROM dbo.V1;

To zapytanie działa pomyślnie, generując następujące dane wyjściowe:

keycol-----------12

W tym momencie powróć do pierwotnego użytkownika, uruchamiając następujący kod:

WRÓĆ;

Czy wystarczy unikać SELECT * i używać wyraźnych nazw kolumn?

Jeśli zastosujesz się do praktyki, która mówi bez SELECT * w wewnętrznym wyrażeniu tabeli widoku, czy to wystarczy, aby uniknąć kłopotów? Cóż, zobaczmy…

Użyj poniższego kodu, aby odtworzyć tabelę i widok, tylko tym razem wyszczególnij kolumny jawnie w wewnętrznym zapytaniu widoku:

DROP VIEW IF EXISTS dbo.V1;DROP TABLE IF EXISTS dbo.T1;GO CREATE TABLE dbo.T1( keycol INT NOT NULL OGRANICZENIE TOŻSAMOŚCI 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 UTWÓRZ LUB ZMIEŃ WIDOK dbo.V1AS SELECT keycol, intcol, charcol FROM dbo.T1;GO

Zapytanie o widok:

WYBIERZ * Z dbo.V1;

Otrzymasz następujące dane wyjściowe:

keycol wewn. charcol----------- ----------- ----------1 10 A2 20 B

Ponownie przyznaj użytkownikowi 1 uprawnienia do wyboru keycol i intcol:

PRZYZNAJ WYBÓR NA dbo.V1(keycol, intcol) TO user1;

Następnie zastosuj te same zmiany strukturalne, co wcześniej:

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;

Zauważ, że SQL Server zaakceptował te zmiany, mimo że widok zawiera wyraźne odniesienie do intcol. Znowu dzieje się tak dlatego, że widok został utworzony bez opcji SCHEMABINDING.

Zapytanie o widok:

WYBIERZ * Z dbo.V1;

W tym momencie SQL Server generuje następujący błąd:

Msg 207, Level 16, State 1, Procedure V1, Line 5 [Batch Start Line 344]
Nieprawidłowa nazwa kolumny 'intcol'.

Msg 4413, poziom 16, stan 1, wiersz 345
Nie można użyć widoku lub funkcji „dbo.V1” z powodu błędów wiązania.

SQL Server próbował rozwiązać odwołanie do intcol w widoku i oczywiście nie powiodło się.

Ale co, jeśli twoim pierwotnym planem było porzucenie intcol, a później dodanie go z powrotem? Użyj następującego kodu, aby dodać go z powrotem, a następnie zapytaj o widok:

ALTER TABLE dbo.T1 ADD intcol INT NOT NULL DEFAULT(0); WYBIERZ * Z dbo.V1;

Ten kod generuje następujące dane wyjściowe:

keycol wewn. charcol----------- ----------- ----------1 0 A2 0 B

Wynik wydaje się poprawny.

Co powiesz na zapytanie o widok jako użytkownik1? Spróbujmy:

WYKONAJ JAKO UŻYTKOWNIK ='użytkownik1';WYBIERZ * Z dbo.V1;

Podczas odpytywania wszystkich kolumn otrzymujesz oczekiwany błąd z powodu braku uprawnień do charcol:

Msg 230, Level 14, State 1, Line 367
Odmowa uprawnienia SELECT w kolumnie 'charcol' obiektu 'V1', baza danych 'TSQLV5', schemat 'dbo'.

Zapytanie o keycol i intcol jawnie:

SELECT keycol, intcol FROM dbo.V1;

Otrzymasz następujące dane wyjściowe:

keycol intcol----------- -----------1 02 0

Wygląda na to, że wszystko jest w porządku dzięki temu, że nie użyłeś SELECT * w wewnętrznym zapytaniu widoku, mimo że nie odświeżyłeś metadanych widoku. Mimo to dobrą praktyką może być odświeżenie metadanych widoku po zmianach DDL w obiektach i kolumnach, do których istnieją odniesienia, aby zachować bezpieczną stronę.

W tym momencie powróć do pierwotnego użytkownika, uruchamiając następujący kod:

WRÓĆ;

POŁĄCZENIE SCHEMATÓW

Używając atrybutu widoku SCHEMABINDING możesz zaoszczędzić sobie wielu wspomnianych wcześniej kłopotów. Jednym z kluczy do uniknięcia kłopotów, które widziałeś wcześniej, jest nieużywanie SELECT * w wewnętrznym zapytaniu widoku. Ale jest też problem zmian strukturalnych względem obiektów zależnych, takich jak usuwanie kolumn, do których istnieją odwołania, które nadal mogą powodować błędy podczas wykonywania zapytań o widok. Używając atrybutu widoku SCHEMABINDING, nie będziesz mógł użyć SELECT * w zapytaniu wewnętrznym. Co więcej, SQL Server odrzuci próby zastosowania odpowiednich zmian DDL do zależnych obiektów i kolumn. W znaczeniu mam na myśli zmiany, takie jak upuszczenie tabeli lub kolumny, do której istnieje odwołanie. Dodanie kolumny do tabeli, do której się odwołuje, oczywiście nie stanowi problemu, więc POWIĄZANIE SCHEMATU nie zapobiega takiej zmianie.

Aby to zademonstrować, użyj następującego kodu, aby odtworzyć tabelę i widok, z SCHEMABINDING w definicji widoku:

DROP VIEW IF EXISTS dbo.V1;DROP TABLE IF EXISTS dbo.T1;GO CREATE TABLE dbo.T1( keycol INT NOT NULL OGRANICZENIE TOŻSAMOŚCI PK_T1 PRIMARY KEY, intcol INT NOT NULL, charcol VARCHAR(10) NOT NULL); WSTAW W dbo.T1(intcol, charcol) WARTOŚCI (10, 'A'), (20, 'B');GO UTWÓRZ LUB ZMIEŃ WIDOK dbo.V1 Z POWIĄZANIAMI SCHEMATÓW WYBIERZ * Z dbo.T1;GO

Pojawia się błąd:

Msg 1054, Poziom 15, Stan 6, Procedura V1, Wiersz 5 [Wsadowy wiersz początkowy 387]
Składnia '*' nie jest dozwolona w obiektach powiązanych ze schematem.

Używając SCHEMABINDING, nie możesz użyć SELECT * w wewnętrznym wyrażeniu tabeli widoku.

Spróbuj ponownie utworzyć widok, tylko tym razem z wyraźną listą kolumn:

UTWÓRZ LUB ZMIEŃ WIDOK dbo.V1 ZA POMOCĄ SCHEMATÓW WYBIERZ keycol, intcol, charcol FROM dbo.T1;GO

Tym razem widok został pomyślnie utworzony.

Przyznaj uprawnienia user1 dla keycol i intcol:

PRZYZNAJ WYBÓR NA dbo.V1(keycol, intcol) TO user1;

Następnie spróbuj zastosować zmiany strukturalne w tabeli. Najpierw dodaj kilka kolumn:

ALTER TABLE dbo.T1 ADD datecol DATE NOT NULL DEFAULT('99991231'), binarycol VARBINARY(3) NOT NULL DEFAULT(0x112233);

Dodanie kolumn nie stanowi problemu, ponieważ nie mogą one być częścią istniejących widoków powiązanych ze schematem, więc ten kod zakończy się pomyślnie.

Spróbuj usunąć intcol kolumny:

ALTER TABLE dbo.T1 DROP COLUMN intcol;

Pojawia się następujący błąd:

Msg 5074, poziom 16, stan 1, wiersz 418
Obiekt „V1” jest zależny od kolumny „intcol”.

Msg 4922, Level 16, State 9, Line 418
ALTER TABLE DROP COLUMN intcol nie powiodło się, ponieważ jeden lub więcej obiektów uzyskuje dostęp do tej kolumny.

Upuszczanie lub zmienianie kolumn, do których istnieją odwołania, jest niedozwolone, gdy istnieją obiekty powiązane ze schematem.

Jeśli nadal musisz usunąć intcol, musisz najpierw usunąć widok odniesienia powiązany ze schematem, zastosować zmianę, a następnie ponownie utworzyć widok i ponownie przypisać uprawnienia, w następujący sposób:

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(keycol, datecol, binarycol) TO użytkownik1;GO

Oczywiście w tym momencie nie ma potrzeby odświeżania definicji widoku, ponieważ utworzyłeś ją od nowa.

Teraz, gdy skończyłeś testowanie, uruchom następujący kod w celu oczyszczenia:

UPUŚĆ WIDOK JEŚLI ISTNIEJE dbo.V1;UPUŚĆ TABELĘ JEŚLI ISTNIEJE dbo.T1;UPUŚĆ UŻYTKOWNIKA JEŚLI ISTNIEJE użytkownik1;

Podsumowanie

Użycie SELECT * w wewnętrznym wyrażeniu tabeli widoku jest bardzo złym pomysłem. Po zastosowaniu zmian strukturalnych do obiektów, do których istnieją odniesienia, możesz uzyskać nieprawidłowe nazwy kolumn, a nawet zezwolić użytkownikom na dostęp do danych, do których nie powinni mieć dostępu. Ważną praktyką jest wyraźne wymienienie nazw kolumn, do których się odnoszą.

Używając SCHEMABINDING w definicji widoku, jesteś zmuszony do jawnego wymienienia nazw kolumn, a odpowiednie zmiany strukturalne w obiektach zależnych są odrzucane przez SQL Server. Dlatego może się wydawać, że tworzenie widoków za pomocą SCHEMBINDING jest zawsze dobrym pomysłem. Istnieje jednak zastrzeżenie z tą opcją. Jak widzieliście, stosowanie zmian strukturalnych do obiektów, do których istnieją odniesienia, gdy używane jest SCHEMBINDING, staje się dłuższym, bardziej skomplikowanym procesem. Może to stanowić problem zwłaszcza w systemach, które muszą mieć bardzo wysoką dostępność. Wyobraź sobie, że musisz zmienić kolumnę zdefiniowaną jako VARCHAR(50) na VARCHAR(60). Nie jest to dozwolona zmiana, jeśli istnieje widok zdefiniowany za pomocą SCHEMABINDING odwołującego się do tej kolumny. Konsekwencje porzucenia wielu widoków odwołujących się, do których mogłyby się odwoływać inne widoki itd., mogą być problematyczne dla systemu. Krótko mówiąc, nie zawsze jest tak trywialne, aby firmy po prostu przyjęły politykę, która mówi, że SCHEMABINDING powinien być używany we wszystkich obiektach, które to obsługują. Jednak przyjęcie zasady, aby nie używać SELECT * w wewnętrznych zapytaniach widoków, powinno być prostsze.

Jeśli chodzi o widoki, jest o wiele więcej do odkrycia. Kontynuacja w przyszłym miesiącu…


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Usuń posty i komentarze z Harmonogramu akcji

  2. Operatory SET w SQL

  3. Jak zamawiać alfabetycznie w SQL

  4. Jak podłączyć bazę danych do Pythona

  5. Normalizacja i wydajność w trybie wsadowym