Denali CTP 1 – co nowego nie tylko dla deweloperów – cz. 3

Udostępnij na: Facebook

Autor: Damian Widera, Łukasz Grala

Opublikowano: 2010-12-28

Deweloperskich nowości ciąg dalszy

Prezentujemy kolejną porcję informacji dotyczących nowości dostępnych w SQL Server „Denali” CTP1. Tym razem pokazane zostaną sposoby korzystania z sekwencji.

Sekwencje

Sekwencje są bardzo dobrze znane deweloperom i administratorom, którzy mieli lub mają do czynienia z silnikiem Oracle. Niestety, Oracle nie posiada znanego z SQL Server mechanizmu autonumeracji wierszy w tabelach, opartego na @@IDENTITY. Jedyną znaną nam drogą zapewniającą autonumerowanie wierszy jest wlaśnie wykorzystanie sekwencji.

Autonumerowanie wierszy  w Oracle

W SQL Server sprawa z autonumeracją wierszy jest w miarę prosta. Jedną z metod jest zadeklarowanie przy danej kolumnie, że będzie ona przechowywała informacje o autogenerowanym numerze wiersza – patrz przykład poniżej:

CREATE TABLE [USER] (         [U_ID] [int] IDENTITY (1, 1) NOT NULL,         [FNAME] [varchar] (100) NOT NULL,         [LNAME] [varchar] (100) NOT NULL ) GO ALTER TABLE [USER] WITH NOCHECK ADD         CONSTRAINT [PK_USER] PRIMARY KEY CLUSTERED         (                [U_ID]         ) GO

Nie wspominamy oczywiście o potencjalnych pułapkach związanych z używaniem tak zdefiniowanego mechanizmu autonumerowania wierszy.

W silniku Oracle, jak już wspomniano, nie można użyć tej metody. Zamiast tego należy wykonać trzy kroki:

  • zadeklarować tabelę,
  • utworzyć sekwencję,
  • sterować wykonywaniem sekwencji, np. w wyzwalaczu.

Poniżej zamieszczamy kod, który opisuje powyższe trzy kroki.

CREATE TABLE [USER] (         [U_ID] [int] IDENTITY (1, 1) NOT NULL,         [FNAME] [varchar] (100) NOT NULL,         [LNAME] [varchar] (100) NOT NULL ) GO   ALTER TABLE [USER] WITH NOCHECK ADD         CONSTRAINT [PK_USER] PRIMARY KEY CLUSTERED         (                [U_ID]         ) GO CREATE SEQUENCE SEQ_USER_ID         MINVALUE 1         MAXVALUE 999999999999999999         START WITH 1         INCREMENT BY 1         NOCACHE ;   CREATE OR REPLACE TRIGGER TRG_USER_INSERT  BEFORE INSERT ON USER  FOR EACH ROW  BEGIN IF :new.U_ID IS NULL THEN  SELECT SEQ_USER_ID.nextvalINTO :new.U_ID FROM DUAL;  END IF;  END;  /  COMMIT;

Użycie sekwencji w SQL Server

SQL Server Denali pozwala na użycie sekwencji w bazie danych, nie usuwając poprzedniego mechanizmu autonumeracji. Ogólnie sekwencja może być przedstawiona jako licznik, który jest zwiększany bądź zmniejszany o zadaną liczbę. Sekwencja może być użyta w wielu tabelach, ponieważ jej widoczność jest na poziomie bazy danych, w której została utworzona.

Najprostsza definicja sekwencji wygląda następująco:

CREATE SEQUENCE Domyslna ;

Sekwencja ta rozpocznie nadawanie numerów od liczby -2147483648, a zakończy na 2147483647 z iteracją o 1. Podane wartości są odpowiednio minimalną i maksymalną wartością dla typu integer.

Zazwyczaj jednak sekwencje mają jako swój punkt początkowy liczbę 0 i inkrementowane są o 1. Jest to przypadek odpowiadający użyciu @@IDENTITY w tabeli:

CREATE SEQUENCE Zwiekszam_o_1

    START WITH 1

    INCREMENT BY 1 ;

GO

Nic nie stoi na przeszkodzie, aby sekwencja zawierała tylko liczby mniejsze od zera. Na poniższym przykładzie pokazano definicję sekwencji, która jako punkt początkowy ma wartość 0 i będzie zmniejszana o 1 po każdym wywołaniu.

CREATE SEQUENCE Zmniejszam_o_1

    START WITH 0

    INCREMENT BY -1 ;

GO

Można zdefiniować sekwencję inaczej, manipulując wartością, o jaką zostanie zwiększony lub zmniejszony licznik po wywołaniu sekwencji. Poniżej zaprezentowano przykład sekwencji, w której numerowanie rozpocznie się od liczby 1 i będzie rosło o 10:

CREATE SEQUENCE Zwiekszam_o_10

    START WITH 1

    INCREMENT BY 10 ;

GO

Sekwencje domyślnie posiadają typ danych integer i na nim przeprowadzają operację liczenia. Można jednak wybrać inny typ danych dla utworzenia sekwencji. Na przykładzie poniżej pokazano, jak zadeklarować sekwencję o typie danych smallint:

CREATE SEQUENCE SmallIntSequence

    AS smallint ;

Do tworzenie sekwencji można użyć takich typów danych, jak:

  • smallint
  • decimal
  • numeric (skala = 0)
  • tinyint
  • int
  • bigint

Próba użycia innego typu danych zakończy się wyświetleniem komunikatu błędu:

CREATE SEQUENCE VarcharSequence     AS varchar; ----- Msg 2724, Level 16, State 1, Line 1 Parameter or variable '' has an invalid data type. Msg 11702, Level 16, State 1, Line 1 The sequence object 'VarcharSequence' must be of data type int, bigint, smallint, tinyint, or decimal or numeric with a scale of 0, or any user-defined data type that is based on one of the above integer data types.

Zbudujmy zatem sekwencję FullSequence, która będzie zawierała pełną definicję, zgodną z Books Online. Definicja posiada kilka parametrów, które omówiono poniżej:

CREATE SEQUENCE FullSequence     AS decimal(3,0)     START WITH 90     INCREMENT BY 5     MINVALUE 60 MAXVALUE 105     CYCLE     CACHE 3  ;

Sekwencja FullSequence posiada następujące cechy:

  • jest typu danych decimal o precyzji 3,
  • punktem startowym sekwencji, od którego zostanie rozpoczęte liczenie, jest 90,
  • sekwencja będzie zwiększana o 5,
  • maksymalna wartość, do której zostanie zwiększona sekwencja, będzie równa 150, bo wynika to z parametru Maxvalue,
  • po przekroczeniu wartości maksymalnej rozpocznie się liczenie od wartości MinValue, która wynosi 60,
  • decyzję o ponownym liczeniu przechowuje parametr Cycle. Ustawienie go na wartość 0 (false) powoduje, że sekwencja wykona się tylko raz,
  • parametr Cache określa, ile wygenerowanych liczb trzymanych będzie w pamięci. Zwiększa to szybkość działania sekwencji, ale powoduje ryzyko utraty większej ilości wygenerowanych numerów w przypadku np. restartu serwera.

Po zadeklarowaniu sekwencji pozostaje ją tylko użyć. Do użycia sekwencji służy polecenie SELECT NEXT VALUE FOR, które pokazano poniżej:

SELECT NEXT VALUE FOR FullSequence;

Sekwencje posiadają jeden dynamiczny widok zarządczy, w którym przechowywane są wszystkie informacje konfiguracyjne o danej sekwencji, a także aktualna wartość licznika:

SELECT * FROM sys.sequences

WHERE name = 'Domyslna' ;