Dodanie kolumny z domyślną wartością
Rozszerzanie istniejącej tabeli
Przypuszczam, że każdy system informatyczny z czasem się rozrasta. Nie dałbym sobie ręki uciąć, ale kurczące się systemy w praktyce nie występują. Rozrost zaczyna się najczęściej od bazy danych, w której powstają dodatkowe tabele i tytułowe dodatkowe kolumny. Gdy pojawia się dodatkowa kolumna, pojawia się problem z istniejącymi już rekordami. Co wstawić w takie nowe pole? Odpowiedź nie jest jednoznaczna i nie ma jednej metody postępowania. Standard SQL definiuje coś takiego jak kolumny z domyślną wartością i nimi się dzisiaj zajmę. Temat niby prosty, ale warto poznać kilka możliwości i zobaczyć, gdzie czyha na nas licho, gdzie utopiec, a gdzie inne strzygi. Diabeł tkwi w szczegółach.
Popatrzmy zatem na pierwotną wersję tabeli:
(
Id int,
Column1 int
)
--Przykładowa wartość
INSERT INTO dbo.DefaultColumn
VALUES (1,1)
Tabela zawiera jeden wiersz z danymi, ale w praktyce tych wierszy będzie znacznie więcej. Tak przygotowani możemy przystąpić do dodawania domyślnych kolumn.
Nowa domyślna kolumna
Przyjrzyjmy się dwóm przykładowym instrukcjom dodającym po jednej kolumnie domyślnej. Należy zwrócić uwagę na to, że jedna z nich jest NULL, a druga NOT NULL.
ALTER TABLE dbo.DefaultColumn
ADD Column2 int DEFAULT 2
--Dla typu NOT NULL istniejące wiersze są modyfikowane
ALTER TABLE dbo.DefaultColumn
ADD Column3 int NOT NULL DEFAULT 3
Różnica jest drobna, ale może mieć daleko idące konsekwencje. Każdy istniejący rekord, do którego dodajemy kolumnę NOT NULL jest uzupełniany domyślną wartością. Jeżeli kolumna może przyjąć NULL, będzie tam NULL.
Popatrzmy na zawartość tabeli po wykonaniu dwóch pokazanych wyżej instrukcji:
Id | Column1 | Column2 | Column3 |
---|---|---|---|
1 | 1 | NULL | 3 |
Pokazane instrukcje działają, ale są zapisem skróconym. Co może być z nimi nie tak?
Maszynowe nazwy kolumn domyślnych
Każda definicja kolumny domyślnej związana jest z odpowiadającym mu więzem integralności. Jeżeli sami nie podamy nazwy, zostanie ona utworzona automatycznie. Ten sam skrypt puszczony na dwóch różnych komputerach wygeneruje zatem dwie różne nazwy! Jeżeli ten sam wzorzec bazy wykorzystywany jest w wielu miejscach, lepiej żeby wszystko było jednakowe. Jeżeli już jest za późno, mozna skorzystać z odpowiedniego skryptu, który pokazałem we wpisie Jak usunąć wartość domyślną z kolumny w tabeli. Jeżeli nie jest za późno, lepiej nadać więzom swojskie nazwy. Przyjrzyjmy się pokazanemu poniżej skryptowi:
ADD Column4 int
CONSTRAINT DF_DefaultColumn_Column4 DEFAULT 4
ALTER TABLE dbo.DefaultColumn
ADD Column5 int NOT NULL
CONSTRAINT DF_DefaultColumn_Column5 DEFAULT 5
Skrypt nie jest znacząco dłuższy, ale przynajmniej nazwy są jednolite. Przyjrzyjmy się teraz nazwom nadanym wszystkim czterem więzom integralności:
WHERE parent_object_id=OBJECT_ID('dbo.DefaultColumn')
Wynik może być inny na innych komputerach, ale chodzi głównie o "dekorowanie nazw".
name |
---|
DF__DefaultCo__Colum__3B40CD36 |
DF__DefaultCo__Colum__3C34F16F |
DF_DefaultColumn_Column4 |
DF_DefaultColumn_Column5 |
Wstawianie nowych wierszy
Na początku użyłem skróconej formy wstawiania nowych wierszy. Ta skrócona forma zakłada fizyczną kolejność kolumn i w taki właśnie sposób wstawia wymienione w nawiasie wartości. Dodanie kolumn domyślnych wszystko komplikuje:
--Column name or number of supplied values does not match table definition.
INSERT INTO dbo.DefaultColumn
VALUES (1,1)
Mamy więcej kolumn, więc należałoby je teraz wymienić. Ale czy nie dlatego dodaliśmy kolumny z domyślnymi wartościami, żeby tego wymieniania uniknąć? Istnieje kilka technik wstawiania takich kolumn. Po pierwsze, można skorzystać ze standardowej formy wstawiania danych:
INSERT INTO dbo.DefaultColumn(Id, Column1)
VALUES (6,6)
INSERT INTO dbo.DefaultColumn(Id, Column1, Column4)
VALUES (7,7,7)
Czy oznacza to, że forma skrócona nie działa? Działa, ale w wielu przypadkach nie jest już tak bardzo skrócona. Wartości domyślne należy w takim przypadku zamienić na słowo kluczowe DEFAULT.
--Wartości domyślne reprezentowane są przez DEFAULT
INSERT INTO dbo.DefaultColumn
VALUES(8,8,DEFAULT,8,DEFAULT,8)
Po wykonaniu wszystkich operacji tabela powinna zawierać następujące wartości:
Id | Column1 | Column2 | Column3 | Column4 | Column5 |
---|---|---|---|---|---|
1 | 1 | NULL | 3 | NULL | 5 |
6 | 6 | 2 | 3 | 4 | 5 |
7 | 7 | 2 | 3 | 7 | 5 |
8 | 8 | 2 | 8 | 4 | 8 |
Jeszcze ciekawiej dzieje się wtedy, gdy jedna z kolumn oznaczona jest atrybutem IDENTITY - to także kolumna w pewnym sensie domyślna.
Domyślne IDENTITY
Przyjrzyjmy się jeszcze jednej zagadkowej tabeli, mocno uproszczonej, z jedną kolumną IDENTITY:
(
ID int IDENTITY
)
--Msg 8101, Level 16, State 1, Line 1
--An explicit value for the identity column in table 'dbo.DefaultIdentity' can only be specified when a column list is used and IDENTITY_INSERT is ON.
--INSERT INTO dbo.DefaultIdentity VALUES (DEFAULT)
--Msg 102, Level 15, State 1, Line 1
--Incorrect syntax near ')'.
--INSERT INTO dbo.DefaultIdentity VALUES ()
Jak do takiego cuda wstawić rekord? Od razu umieściłem dwie instrukcje, które nie działają, a które pojawiają się w głowach większości pytanych. Takie zadanie jest okazją do przedstawienia jeszcze jednej wersji operacji INSERT. Popatrzmy na kolejny przykład:
Pójdę dalej i dodam jeszcze jedną kolumnę:
ADD EntryDate datetime NOT NULL
CONSTRAINT DF_DefaultIdentity_EntryDate DEFAULT GETDATE()
Tym razem, aby wstawić wszystkie domyślne wartości, mamy więcej opcji:
INSERT INTO dbo.DefaultIdentity DEFAULT VALUES
--Domyślna wartość daty, IDENTITY jest pomijane
INSERT INTO dbo.DefaultIdentity VALUES (DEFAULT)
Obie operacje powinny się zakończyć sukcesem, a tabela powinna zawierać konkretne dane (naturalnie daty mogą być inne):
ID | EntryDate |
---|---|
1 | 2013-07-02 18:45:57.547 |
2 | 2013-07-02 18:46:00.633 |
3 | 2013-07-02 18:46:00.637 |
Podsumowanie
Przypuszczam, że pokazane powyżej przykłady obejmują większość przypadków, z którymi można się zetknąć podczas pracy z wartościami domyślnymi, w tym z automatycznie uzupełnianymi wartościami kolumny IDENTITY (więcej o IDENTITY można przeczytać we wpisie Identity jako identyfikator). Gdyby pojawiły się jakieś problemy z kolumnami domyślnymi, zachęcam do dzielenia się nimi w komentarzach.
Kategoria:IdentitySQL Server
Brak komentarzy - bądź pierwszy