Widok utworzony w MS SQL Server nie pokazuje poprawnych rezultatów

Istnieje wiele artykułów i sygnałów, aby nie używać “SELECT *” w kodzie produkcyjnym. Z łatwością można znaleźć wiele z nich w internecie jak np. ten: here Okazuje się jednak, że autorzy niemal zawsze zapominają o jednym ważnym czynniku, który może spowodować, że  za używanie “SELECT *” zapłacimy najwyższą cenę, a mianowicie otrzymamy niewłaściwe rezultaty. Co gorsza serwer nie zwróci żadnego komunikatu błędu, ostrzeżenia o błędzie lub nieprawidłowości. Zobaczmy przykład.

Na początku stwórzmy prostą tabelę i wstawmy do niech przykładowe dane.

USE TestingDb;

GO

CREATE TABLE tab1
( 
      id INT IDENTITY(1,1)
      , StudentName NVARCHAR(25)
)

GO

INSERT INTO tab1 (StudentName) VALUES ('Paul')
INSERT INTO tab1 (StudentName) VALUES ('John')
INSERT INTO tab1 (StudentName) VALUES ('Susan')

Teraz utwórzmy widok do tej tabeli używając “SELECT *”

CREATE VIEW v_tab1 AS
(
    SELECT * FROM tab1
)

Zobaczmy rezultaty:

SELECT * FROM tab1
SELECT * FROM v_tab1

Jak widać nie ma z tym żadnego problemu, a wyniki zapytania pokazują prawidłowe dane.
1

Dodajmy nowe danie i zobaczmy co się stanie.

INSERT INTO tab1 (StudentName) VALUES ('Andrew')

Tym razem zarówno widok jak i zapytanie na oryginalnej tabeli zwracają dokładnie to samo.
2

Póki co wszystko działa bardzo dobrze, ale zróbmy coś ciekawszego. Dodajmy do tabeli na której stworzyliśmy widok nową kolumnę.

ALTER TABLE tab1 ADD age INT

Po ponownym wykonaniu zapytania wynik jest następujący:
3

Jak widać rezultaty zapytań opartych na tabeli i na widoku są różne, natomiast widok po prostu nie pokazał nowej kolumny. Zróbmy jednak jeszcze coś więcej.

UPDATE tab1 SET [age] = 18

Po aktualizacji kolumny wynik widoku nadal jest niepoprawny.
4

Okazuje się jednak, że konsekwencje naszych działań są o wiele poważniejsze. O ile teraz po prostu nie widzimy wszystkich danych to te, które już się pojawiły są poprawne. Zobaczmy co się jednak stanie kiedy usuniemy kolumnę, która teraz się pokazuje i istniała przed utworzeniem widoku.

ALTER TABLE tab1 DROP COLUMN studentname

Wyniki są następujące:
7

SQL Server zwrócił dane z zupełnie innej kolumny. Jak widać widok działa poprawnie – to znaczy wykonuje się – i nie zwraca żadnego komunikatu natomiast dane są kompletnie niepoprawne. W produkcyjnym kodzie może to oczywiście spowodować wiele problemów począwszy od nieprawidłowych danych na raporcie, aż do przerwy w działaniu aplikacji, która korzysta z takiego widoku. Rozwiązanie jest proste – nigdy nie używaj “SELECT *”. Oczywiście istnieje kilka sytuacji kiedy “SELECT *” można użyć – zwłaszcza podczas prac developerskich – natomiast jest to zła praktyka i należy się jej wystrzegać.

Warto również wspomnieć o tym, że istnieje mechanizm, który pozwala naprawić ten błąd – wystarczy użyć procedury składowanej sp_refreshview:

EXEC sp_refreshview 'v_tab1'

Po jej wykonaniu widok został odświeżony, a otrzymywane rezultaty będą poprawne. Nie jest to jednak wytłumaczenie na wykorzystywanie niesławnego “SELECT *”, a jedynie możliwość naprawy już istniejących rozwiązań.

Slawomir Drzymala
Follow me on

5 Comments

  1. Pierwszy raz widzę takie dziwne zachowanie się widoku. To że nie wyświetla wszystkich dodanych kolumn, oraz że potrafi pokazać błędne dane, jest dla mnie wręcz szokujące.

    • A jednak zdarza się 🙂 Między innymi dlatego “nie używaj SELECT *” pojawia się praktycznie na każdej prezentacji dotyczącej dobrych praktyk.

  2. Oj, często spotykam się z tak utworzonymi widokami. Taka “oszczędność czasu” lubi uprzykrzać życie po aktualizacji systemu ERP 🙂 gdy zmianie ulega struktura tabeli.

Leave a Reply