BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są...

46
BAZY DANYCH Podstawowe wiadomości o Transact-SQL Dodatek do instrukcji laboratoryjnej dla studiów niestacjonarnych I stopnia Opr. A. Rams

Transcript of BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są...

Page 1: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

BAZY DANYCH

Podstawowe wiadomości o Transact-SQL

Dodatek do instrukcji laboratoryjnej dla studiów niestacjonarnych I stopnia Opr. A. Rams

Page 2: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

2

BAZY DANYCH ..................................................................................................................................................................... 1 1. Typy danych ........................................................................................................................................................... 3 2. Język definicji danych (DDL - Data Definition Language) ................................................................................... 4

2.1. Tworzenie tabeli..................................................................................................................................................... 4 2.2. Tablice tymczasowe ............................................................................................................................................... 6 2.3. Zmiana struktury tabeli ......................................................................................................................................... 8 2.4. Usuwanie tabeli .................................................................................................................................................... 10 2.5. Tworzenie widoku ............................................................................................................................................... 10 2.6. Tworzenie indeksu ............................................................................................................................................... 12

3. Język operowania danymi (DML - Data Manipulation Language) .................................................................... 14

3.1. Pobranie istniejących danych (SELECT)............................................................................................................. 14

3.1.1. Klauzula WITH. Wyrażenie tablicowe. ........................................................................................................ 14 3.1.2. Podzapytania (subquery) .............................................................................................................................. 15 3.1.3. Wyrażenie SELECT ..................................................................................................................................... 20 3.1.4. Wyrażenie CASE.......................................................................................................................................... 21 3.1.5. Klauzula INTO ............................................................................................................................................. 22 3.1.6. Funkcje agregujące ....................................................................................................................................... 22 3.1.7. Klauzula FROM ........................................................................................................................................... 23 3.1.8. Klauzula WHERE ........................................................................................................................................ 24 3.1.9. Klauzula GROUP BY ................................................................................................................................... 25 3.1.10. Klauzula ORDER BY ................................................................................................................................... 25 3.1.11. Klauzula COMPUTE .................................................................................................................................... 26 3.1.12. Operator JOIN .............................................................................................................................................. 26 3.1.13. Klauzule UNION, INTERSECT i EXCEPT ................................................................................................ 27

3.2. Dodawanie wierszy do tabeli (INSERT) ............................................................................................................. 28 3.3. Modyfikacja wierszy w tabeli (UPDATE)............................................................................................................ 29 3.4. Usuwanie wierszy z tabeli (DELETE) ................................................................................................................. 30

4. Elementy składni języka T-SQL ........................................................................................................................... 32

4.1. Powołanie zmiennej lokalnej (DECLARE) .......................................................................................................... 32 4.2. Tworzenie procedur składowych (CREATE PROCEDURE) ............................................................................... 32 4.3. Uruchomienie kodu (EXECUTE) ......................................................................................................................... 34 4.4. Sterowanie programem ....................................................................................................................................... 34

4.4.1. Deklaracja bloku (BEGIN...END) ................................................................................................................ 34 4.4.2. Instrukcja warunkowa (IF...ELSE) ............................................................................................................... 35 4.4.3. Instrukcja pętli (WHILE).............................................................................................................................. 35 4.4.4. Instrukcja oczekiwania (WAITFOR) ........................................................................................................... 35

4.5. Kursory ................................................................................................................................................................. 36

4.5.1. Definiowanie (DECLARE CURSOR) ......................................................................................................... 36 4.5.2. Pobieranie danych (FETCH) ........................................................................................................................ 37

4.6. Wyzwalacze (triggery) ......................................................................................................................................... 37

4.6.1. Wyzwalacze DML ........................................................................................................................................ 37 4.6.2. Wyzwalacze DDL ........................................................................................................................................ 38 4.6.3. Wyzwalacze logowania ................................................................................................................................ 39

4.7. Funkcje wbudowane ............................................................................................................................................ 39 4.8. Transakcje............................................................................................................................................................. 40

4.8.1. Poziomy izolacji transakcji w SQL-92 ......................................................................................................... 40 4.8.2. Polecenia związane z transakcjami ............................................................................................................... 41 4.8.3. Transakcje automatyczne ............................................................................................................................. 43 4.8.4. Transakcje sprecyzowane (explicite) ............................................................................................................ 44 4.8.5. Transakcje domyślne (implicite) .................................................................................................................. 45

Page 3: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

3

1. Typy danych W wyrażeniach CREATE TABLE lub ALTER TABLE należy podać dla każdej kolumny postać danych (typ), w jakiej dane będą przechowywane. W wykorzystywanym przez MS SQL Server języku Transact SQL typy danych zgrupowane są w następujących kategoriach:

Dane numeryczne - dokładne (bigint, bit, decimal, int, money, numeric, smallint, smallmoney, tinyint)

Dane numeryczne - przybliżone (float, real)

Data i czas (date, datetime, datetime2, datetimeoffset, smalldatetime, time)

Ciągi znaków (char, text, varchar)

Ciągi znaków Unicode (nchar, ntext, nvarchar)

Ciągi binarne (binary, image, varbinary)

Inne (cursor, hierarchyid, sql_variant, table, timestamp, uniqueidentyfier, xml)

Przykładowe formaty danych: Typ danych Zakres Ilość bajtów

BIGINT -263 (-9 223 372 036 854,775 808) do 263-1 (9 223 372 036 854 775 807)

8

INTEGER -231 (-2 147 483 648) do 231-1 (2 147 483 647) 4

SMALLINT -215 (-32 768) do 215-1 (32 767) 2

TINYINT 0 do 28-1 (255) 1

MONEY -922 337 203 685 477,5808 do 922 337 203 685 477,5807 8

SMALLMONEY - 214 748,3648 do 214 748,3647 4

DECIMAL, NUMERIC

dec[(m[, n])]. m - łączna ilość cyfr (1 ≤ m ≤ 38), n - cyfry po przecinku, 0 ≤ n ≤ m (n = 9, 19, 28, 38).

5, 9, 13, 17

FLOAT -1.79×10+308 do -2.23×10-308 , 0, 2.23×10-308 do 1.79×10+308 float[(n)], n - ilość bitów mantysy, 1 ≤ n ≤ 53 (n = 24 lub 53)

4 lub 8

REAL -3.40E+38 do -1.18E-38 oraz 1.18E-38 do 3.40E+38 4

CHARACTER char[(n)]. 1 ≤ n ≤ 8000 n

NVARCHAR nvarchar[(n | max)]. 1 ≤ n ≤ 4000, max → length ≤ 231-3 bajtów length + 2

W Transact-SQL użytkownik może definiować swoje własne typy na podstawie typów istniejących i usuwać je. Służą do tego polecenia CREATE TYPE i DROP TYPE.

Przykłady Utwórzmy 12-znakowy typ MAC, oparty na typie CHARACTER, nie dopuszczający wartości NULL: CREATE TYPE MAC

FROM CHAR(12) NOT NULL;

GO

CREATE TABLE Tab1 (

ID INT IDENTITY PRIMARY KEY,

mac1 MAC);

Utwórzmy typ tablicowy PRSN (typu tablicowego nie można go używać w definiowaniu kolumn!), wymuszający długość ciągu znaków w pierwszej kolumnie:

CREATE TYPE PRSN AS TABLE (

PESEL CHAR(11),

Name VARCHAR(15) NOT NULL,

CHECK (LEN(PESEL) = 11));

GO

DECLARE @next_t AS PRSN;

INSERT @next_t

SELECT 89032004091,'Adamski';

SELECT * FROM @next_t;

GO

Page 4: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

4

2. Język definicji danych (DDL - Data Definition Language)

2.1. Tworzenie tabeli Do tworzenia nowej (zwykłej lub tymczasowej) tablicy służy polecenie CREATE TABLE: SKŁADNIA

CREATE TABLE

[database_name.[schema_name].|schema_name.]table_name

({<column_definition>|<computed_column_definition>

|<column_set_definition> }

[<table_constraint>] [,...n])

[ON {partition_scheme_name (partition_column_name)|filegroup

|"default" } ]

[{TEXTIMAGE_ON {filegroup|"default"}]

[FILESTREAM_ON {partition_scheme_name|filegroup|"default"} ]

[WITH (<table_option> [,...n ] )]

[ ; ]

Przy pomocy wyrażenia CREATE TABLE wprowadzamy nazwę tablicy oraz definiujemy jedną lub więcej kolumn. Nazwy kolumn (do 128 znaków) muszą być unikalne w ramach tablicy. Nazwa tablicy (maksymalnie 128 znaków) może być uzupełniona nazwą schematu do którego tablica należy oraz nazwą bazy danych. Kolumny mogą być zwykłe lub wyliczane. Kolumna wyliczana jest to kolumna wirtualna, nie przechowywana w tabeli (chyba że oznaczymy ją jako PERSISTED), której wartość obliczana jest na podstawie wyrażenia wykorzystującego inne kolumny z danej tabeli. Definicja każdej kolumny musi zawierać jej nazwę oraz typ danych. Można również wprowadzić opis pomocniczy kolumny: SKŁADNIA

<column_definition> ::= column_name <data_type>

[FILESTREAM ]

[COLLATE collation_name ]

[NULL | NOT NULL ]

[

[CONSTRAINT constraint_name ] DEFAULT constant_expression]

| [IDENTITY [ (seed ,increment) ] [ NOT FOR REPLICATION]

]

[ROWGUIDCOL ] [ <column_constraint> [,...n ]]

[SPARSE ]

<computed_column_definition> ::= column_name AS computed_column_expression

[ PERSISTED [ NOT NULL ] ]

[

[ CONSTRAINT constraint_name ]

{ PRIMARY KEY | UNIQUE }

[ CLUSTERED | NONCLUSTERED ]

[

WITH FILLFACTOR = fillfactor

| WITH (<index_option> [,...n ])

]

| [ FOREIGN KEY ]

REFERENCES referenced_table_name [(ref_column) ]

[ ON DELETE { NO ACTION | CASCADE } ]

[ ON UPDATE { NO ACTION } ]

[ NOT FOR REPLICATION ]

| CHECK [ NOT FOR REPLICATION ] (logical_expression)

[ ON {partition_scheme_name (partition_column_name)

|filegroup|"default"} ]

]

Aby wymusić wprowadzanie danych do kolumny używamy zwrotu NOT NULL. Wartość domyślną dla kolumny można wprowadzić za pomocą zwrotu DEFAULT constant_expression. Kolumna zawierająca dane numeryczne dokładne może mieć wprowadzane automatycznie unikalne, narastające wartości, jeżeli użyte zostanie: IDENTITY [(seed, increment)]. Ewentualna klauzula NOT FOR REPLICATION powoduje, że przy powielaniu tabeli reguły inkrementacji nie zostaną użyte.

Page 5: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

5

Każda z kolumn może również mieć zdefiniowane ograniczenia: SKŁADNIA

<column_constraint> ::= [ CONSTRAINT constraint_name ]

{

{ PRIMARY KEY | UNIQUE }

[CLUSTERED | NONCLUSTERED]

[

WITH FILLFACTOR = fillfactor

| WITH ( < index_option > [ , ...n ] )

]

[ON { partition_scheme_name (partition_column_name)

| filegroup | "default" } ]

| [FOREIGN KEY ]

REFERENCES [schema_name . ] referenced_table_name [(ref_column )]

[ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT }]

[ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT }]

[NOT FOR REPLICATION]

| CHECK [NOT FOR REPLICATION] (logical_expression )

}

Kolumna może być oznaczona jako klucz główny (PRIMARY KEY) lub o niepowtarzających się wartościach (UNIQUE). Może być kluczem obcym ([FOREIGN KEY] REFERENCES), którego wartości muszą występować we wskazanej unikalnej kolumnie innej tabeli. W tym przypadku można zdefiniować działania jakie powinny być wykonane w przypadku modyfikacji (ON UPDATE) lub usunięcia (ON DELETE) wartości klucza w tabeli odniesienia. Dla kolumn wyliczanych istnieje dodatkowo możliwość oznakowania (PERSISTED) jako przechowywanej w tabeli. Wartość takiej kolumny obliczana jest każdorazowo przy wystąpieniu zmian składników wyrażenia. Ponadto można zdefiniować ograniczenia dla całej tabeli. SKŁADNIA

< table_constraint > ::= [CONSTRAINT constraint_name]

{

{ PRIMARY KEY | UNIQUE }

[CLUSTERED | NONCLUSTERED]

(column [ASC | DESC] [,...n ] )

[

WITH FILLFACTOR = fillfactor |WITH ( <index_option> [, ...n] )

]

[ ON { partition_scheme_name (partition_column_name)

| filegroup | "default" } ]

| FOREIGN KEY

( column [ ,...n ] )

REFERENCES referenced_table_name [ (ref_column [ ,...n ] )]

[ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT }]

[ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT }]

[NOT FOR REPLICATION]

| CHECK [NOT FOR REPLICATION] (logical_expression )

}

Pozwalają one na określanie niepowtarzających się wartości w zestawach kolumn (UNIQUE), definiowanie złożonych kluczy głównych (PRIMARY KEY) oraz złożonych kluczy obcych (FOREIGN KEY). Jako klucz obcy może być również użyta kolumna z tej samej tabeli (powstaje tzw. samo-odniesienie).

Przykład Utwórzmy tabelę Teachers, posiadającą kolumny TNo, TName, Title, City oraz SupNo: CREATE TABLE Teachers (

TNo CHAR(3) NOT NULL PRIMARY KEY,

TName VARCHAR(30),

Title VARCHAR (10),

City VARCHAR (30),

SupNo CHAR (3) FOREIGN KEY REFERENCES Teachers(TNo));

GO

Page 6: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

6

2.2. Tablice tymczasowe MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa takiej tablicy może zawierać do 116 znaków i powinna rozpoczynać się od znaku #. Taka tablica tymczasowa widoczna jest wyłącznie w ramach bieżącej sesji. Istnieje również odmiana globalna tablic tymczasowych, które są widoczne we wszystkich sesjach. Ich nazwa powinna rozpoczynać się od znaków ##. Polecenie tworzenia tablicy tymczasowej obsługuje definicje wszystkich ograniczeń za wyjątkiem FOREIGN KEY. Gdyby polecenie CREATE TABLE takie ograniczenie zawierało, to zostanie wygenerowane ostrzeżenie i definicja FOREIGN KEY zostanie pominięta. Tablica będzie utworzona bez tego ograniczenia. Tablice tymczasowe nie mogą również występować w klauzuli REFERENCES innych tablic. Jeśli w danej procedurze tworzone jest kilka tablic tymczasowych, to muszą się one różnić nazwami. Tablice tymczasowe mogą być generowane również wewnątrz procedur - w takim przypadku są one automatycznie usuwane po zakończeniu działania procedury. Zasięg widoczności takiej tablicy tymczasowej obejmuje wyłącznie daną procedurę i ewentualne jej podprocedury.

Przykłady

Tworzenie tablicy tymczasowej w procedurze CREATE PROCEDURE Test

AS

CREATE TABLE #t (x INT PRIMARY KEY);

INSERT INTO #t VALUES (9);

SELECT TestCol = X FROM #t;

GO

EXEC Test

GO

Wynik: (1 row(s) affected) TestCol

1 9

Obszar działania tablicy tymczasowej CREATE PROCEDURE Test2

AS

CREATE TABLE #t (x INT PRIMARY KEY);

INSERT INTO #t VALUES (2);

SELECT TestCol2 = X FROM #t;

GO

CREATE PROCEDURE Test1

AS

CREATE TABLE #t (x INT PRIMARY KEY);

INSERT INTO #t VALUES (1);

SELECT TestCol1 = X FROM #t;

EXEC Test2

GO

CREATE TABLE #t (x INT PRIMARY KEY);

INSERT INTO #t VALUES (9);

GO

EXEC Test1

SELECT TestCol = X FROM #t;

GO

Wynik: (1 row(s) affected) TestCol1

1 1

Page 7: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

7

(1 row(s) affected) TestCol2

1 2

(1 row(s) affected) TestCol

1 9

Lokalna tablica tymczasowa utworzona wewnątrz procedury składowej lub wyzwalacza może mieć nazwę identyczną z tablicą tymczasową utworzoną przed wywołaniem procedury pod warunkiem, że struktura tabeli i nazwy kolumn będą również identyczne. To samo dotyczy tworzenia tablic tymczasowych w procedurach zagnieżdżonych. W wywołaniu funkcji wbudowanych, przy odwoływaniu się do tablicy tymczasowej, należy jej nazwę poprzedzić nazwą bazy danych.

Przykłady W drugim przypadku nie użyto rozszerzenia nazwy, co skutkowało negatywnym wynikiem poszukiwania obiektu. CREATE TABLE #t (x INT PRIMARY KEY);

INSERT INTO #t VALUES (1);

GO

SELECT Id = OBJECT_ID('tempdb..#t','U');

GO

SELECT Id = OBJECT_ID('#t','U');

GO

Wynik: (1 row(s) affected)

Id

1 805577908

(1 row(s) affected) Id

1 NULL

Innym sposobem tworzenia lokalnych tablic tymczasowych jest użycie zmiennej typu table ( zob. przykład).

Zmienne lokalne posiadają nazwy rozpoczynające się od znaku @. Podstawową różnicą jest to, że zmienne lokalne nie są zapisywane w logach transakcyjnych, zatem nie reagują na polecenia rollback.

Przykład

Porównanie tablicy tymczasowej i zmiennej typu table CREATE TABLE #T (s VARCHAR(128))

DECLARE @T TABLE (s VARCHAR(128))

INSERT INTO #T SELECT 'old value #'

INSERT INTO @T SELECT 'old value @'

BEGIN TRANSACTION

UPDATE #T SET s='new value #'

UPDATE @T SET s='new value @'

ROLLBACK TRANSACTION

SELECT * FROM #T

SELECT * FROM @T

Page 8: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

8

Wynik: (1 row(s) affected) (1 row(s) affected) (1 row(s) affected) (1 row(s) affected) (1 row(s) affected) s

1 old value #

(1 row(s) affected) s

1 new value @

2.3. Zmiana struktury tabeli Polecenie ALTER TABLE umożliwia dodanie nowej kolumny, modyfikację bądź usunięcie kolumny istniejącej. SKŁADNIA

ALTER TABLE [database_name . [schema_name ] . | schema_name . ] table_name

{

ALTER COLUMN column_name

{

[type_schema_name. ] type_name [( { precision [,scale]

| MAX | xml_schema_collection } ) ]

[COLLATE collation_name]

[NULL | NOT NULL ] [SPARSE ]

| {ADD | DROP }

{ ROWGUIDCOL | PERSISTED | NOT FOR REPLICATION | SPARSE }

}

| [WITH { CHECK | NOCHECK }]

| ADD

{

<column_definition>

| <computed_column_definition>

| <table_constraint>

| <column_set_definition>

} [,...n]

| DROP

{

[CONSTRAINT] constraint_name

[WITH ( <drop_clustered_constraint_option> [,...n] )]

| COLUMN column_name

} [,...n ]

| [WITH { CHECK | NOCHECK }] { CHECK | NOCHECK } CONSTRAINT

{ ALL | constraint_name [,...n] }

| { ENABLE | DISABLE } TRIGGER

{ ALL | trigger_name [,...n] }

| { ENABLE | DISABLE } CHANGE_TRACKING

[WITH ( TRACK_COLUMNS_UPDATED = { ON | OFF } )]

| SWITCH [PARTITION source_partition_number_expression]

TO target_table

[PARTITION target_partition_number_expression]

| SET ( FILESTREAM_ON = { partition_scheme_name | filegroup |

"default" | "NULL" } )

| REBUILD

[ [PARTITION = ALL]

[WITH ( <rebuild_option> [,...n] )]

| [PARTITION = partition_number

[WITH ( <single_partition_rebuild_option> [,...n] )]

]

]

| (<table_option>)

}

[ ; ]

Page 9: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

9

Polecenie ALTER COLUMN nie ma zastosowania do kolumn zawierających typ danych timestamp, kolumn wyliczanych, kolumn użytych w indeksach, chyba że nie zmienia się typu, nowy rozmiar jest nie mniejszy od starego a indeks nie jest kluczem głównym.

Przykłady

Dodawanie nowej kolumny CREATE TABLE dbo.TEST (column_a INT) ;

GO

ALTER TABLE dbo.TEST ADD column_b VARCHAR(20) NULL ;

GO

EXEC sp_help TEST; -- Dokumentacja tabeli TEST

GO

DROP TABLE dbo.TEST;

GO

Usuwanie kolumny CREATE TABLE dbo.TEST (column_a INT, column_b VARCHAR(20) NULL) ;

GO

ALTER TABLE dbo.TEST DROP COLUMN column_b ;

GO

DROP TABLE dbo.TEST;

GO

Zmiana typu danych w kolumnie CREATE TABLE dbo.TEST (column_a INT ) ;

GO

INSERT INTO dbo.TEST (column_a) VALUES (10) ;

GO

ALTER TABLE dbo.TEST ALTER COLUMN column_a DECIMAL (5, 2) ;

GO

DROP TABLE dbo.TEST;

Dodawanie kolumny z ograniczeniami CREATE TABLE dbo.TEST (column_a INT) ;

GO

ALTER TABLE dbo.TEST ADD column_b VARCHAR(20) NULL

CONSTRAINT TEST_unique UNIQUE ;

GO

EXEC sp_help TEST;

GO

DROP TABLE dbo.TEST;

GO

Dodanie ograniczenia CHECK dla istniejącej kolumny Użyto klauzuli WITH NO CHECK, aby nie sprawdzać już istniejących danych. CREATE TABLE dbo.TEST ( column_a INT) ;

GO

INSERT INTO dbo.TEST VALUES (-1) ;

GO

ALTER TABLE dbo.TEST WITH NOCHECK

ADD CONSTRAINT TEST_check CHECK (column_a > 1) ;

GO

EXEC sp_help TEST ;

GO

DROP TABLE dbo.TEST;

GO

Page 10: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

10

Dodanie ograniczenia DEFAULT dla istniejącej kolumny W przykładzie zostają wprowadzone dane do pierwszej kolumny, pozostałe będą zawierały NULL. Po wprowadzeniu ograniczenia DEFAULT dla drugiej kolumny wprowadzamy nowy wiersz (tylko wartość w pierwszej kolumnie) i sprawdzamy wynik poleceniem SELECT. CREATE TABLE dbo.TEST ( column_a INT, column_b INT) ;

GO

INSERT INTO dbo.TEST (column_a)VALUES ( 7 ) ;

GO

ALTER TABLE dbo.TEST

ADD CONSTRAINT col_b_def

DEFAULT 50 FOR column_b ;

GO

INSERT INTO dbo.TEST (column_a) VALUES ( 10 ) ;

GO

SELECT * FROM dbo.TEST;

GO

DROP TABLE dbo.TEST;

GO

2.4. Usuwanie tabeli Polecenie DROP TABLE usuwa tabelę i wszystkie zawarte w niej dane z bazy danych, wszystkie zdefiniowane na niej indeksy oraz wszystkie związane z nią uprawnienia dostępu. SKŁADNIA

DROP TABLE [database_name . [ schema_name ] . | schema_name . ]

table_name [,...n] [ ; ]

Nie można usunąć tabeli wskazanej jako odniesienie w kluczu obcym w innej tabeli. Najpierw należy usunąć tamtą tabelę lub ograniczenie FOREIGN KEY. Usunięcie wszystkich danych z tabeli nie powoduje usunięcia tabeli. Wymaga posiadania uprawnienia CONTROL na tabeli lub ALTER na schemacie do którego tabela należy.

Przykład W poniższym przykładzie zostaje utworzona tymczasowa tablica (tablice tymczasowe umieszczane są w bazie tempdb), testowane jest jej istnienie a następnie tablica zostaje usunięta. Do testowania użyto funkcji OBJECT_ID, której argumentami są nazwa obiektu i jego typ (U – tablica użytkownika, V – widok). Funkcja zwraca NULL, gdy nie znajdzie obiektu. CREATE TABLE #temptable (col1 INT);

GO

INSERT INTO #temptable

VALUES (10);

GO

SELECT * FROM #temptable;

GO

IF OBJECT_ID(N'tempdb..#temptable', N'U') IS NOT NULL

DROP TABLE #temptable;

GO

--Test the drop.

SELECT * FROM #temptable;

2.5. Tworzenie widoku Polecenie CREATE VIEW tworzy wirtualną tablicę, której zawartość jest definiowana przez zapytanie. Może być używane dla:

wprowadzenia osobistych form przedstawienia danych dla poszczególnych użytkowników zabezpieczenia przed bezpośrednim dostępem użytkowników do tablic bazy danych zapewnienia wstecznej kompatybilności bazy przez emulację tablic, których struktura uległa zmianie

SKŁADNIA

CREATE VIEW [schema_name . ] view_name [(column [,...n] )]

[WITH <view_attribute> [,...n]]

AS SELECT_statement

[WITH CHECK OPTION] [ ; ]

Page 11: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

11

<view_attribute> ::=

{

[ENCRYPTION]

[SCHEMABINDING]

[VIEW_METADATA] }

Nazwa widoku musi być unikalna w zbiorze nazw istniejących tablic i widoków. Wyrażenie SELECT definiuje widok. Może ono wykorzystywać więcej niż jedną tablicę oraz inne widoki. Może zawierać wiele poleceń SELECT rozdzielonych przez UNION lub UNION ALL. Nie może zawierać następujących elementów:

klauzul COMPUTE lub COMPUTE BY, klauzuli ORDER BY, chyba że w liście wyboru polecenia SELECT występuje również klauzula TOP, słowa kluczowego INTO klauzuli OPTION odniesienia do tabeli tymczasowej lub zmiennej typu tablicowego.

Wyrażenie WITH CHECK OPTION wymusza aktualizację wyświetlanych danych przez widok. Zmiana danych bezpośrednio w tablicach użytych w widoku nie jest weryfikowana wyrażeniem SELECT widoku. Dane w tablicach użytych w widoku mogą być modyfikowane poprzez widok pod warunkiem że:

wszelkie modyfikacje: UPDATE, INSERT i DELETE muszą się odnosić do kolumn jednej tablicy modyfikowane kolumny odnoszą się bezpośrednio do kolumn tablic. Nie mogą one być wynikiem operacji

takich jak: o funkcje agregacji AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR i VARP, o wyrażenia używające innych kolumn o operacje zbiorowe jak UNION, UNION ALL, EXCEPT i INTERSECT

modyfikowane kolumny nie są objęte działaniem GROUP BY, HAVING lub DISTINCT klauzula TOP nie jest użyta gdziekolwiek w wyrażeniu SELECT widoku wraz z klauzulą WITH CHECK

OPTION. Usuwanie widoku wykonywane jest za pomocą polecenia DROP VIEW.

Przykłady

Proste użycie CREATE VIEW W przykładzie wykorzystano dane z przykładowej bazy danych AdventureWorks2008R2 dołączonej do MS SQL Server 2008. Dane pochodzą z tablic HumanResources.Employee oraz Person.Person. Widok daje dostęp do wybranych danych pracowników. IF OBJECT_ID ('hiredate_view', 'V') IS NOT NULL

DROP VIEW hiredate_view ;

GO

CREATE VIEW hiredate_view AS

SELECT p.FirstName, p.LastName, e.BusinessEntityID, e.HireDate

FROM HumanResources.Employee e

JOIN Person.Person AS p ON e.BusinessEntityID = p.BusinessEntityID ;

GO

Użycie klauzuli WITH CHECK OPTION Próba wprowadzenia w polu City wartości innej niż Seattle spowoduje błąd. IF OBJECT_ID ('dbo.SeattleOnly', 'V') IS NOT NULL

DROP VIEW dbo.SeattleOnly ;

GO

CREATE VIEW dbo.SeattleOnly AS

SELECT p.LastName, p.FirstName, e.JobTitle, a.City, sp.StateProvinceCode

FROM HumanResources.Employee e

INNER JOIN Person.Person p ON p.BusinessEntityID = e.BusinessEntityID

INNER JOIN Person.BusinessEntityAddress bea

ON bea.BusinessEntityID = e.BusinessEntityID

INNER JOIN Person.Address a ON a.AddressID = bea.AddressID

INNER JOIN Person.StateProvince sp ON sp.StateProvinceID = a.StateProvinceID

WHERE a.City = 'Seattle'

WITH CHECK OPTION ;

GO

Page 12: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

12

Użycie funkcji wbudowanych IF OBJECT_ID ('Sales.SalesPersonPerform', 'V') IS NOT NULL

DROP VIEW Sales.SalesPersonPerform ;

GO

CREATE VIEW Sales.SalesPersonPerform

AS

SELECT TOP (100) SalesPersonID, SUM(TotalDue) AS TotalSales

FROM Sales.SalesOrderHeader

WHERE OrderDate > CONVERT(DATETIME,'20001231',101)

GROUP BY SalesPersonID;

GO

2.6. Tworzenie indeksu Do utworzenia nowego indeksu na jednej lub kilku kolumnach tabeli służy polecenie CREATE INDEX. SKŁADNIA

CREATE [UNIQUE] [CLUSTERED | NONCLUSTERED] INDEX index_name

ON <object> (column [ASC | DESC] [,...n] )

[INCLUDE (column_name [,...n] ) ]

[WHERE <filter_predicate> ]

[WITH ( <relational_index_option> [,...n] ) ]

[ON { partition_scheme_name (column_name)

| filegroup_name

| default

}

]

[FILESTREAM_ON

{ filestream_filegroup_name | partition_scheme_name | "NULL" }]

[ ; ]

<object> ::=

{

[database_name. [schema_name] . | schema_name.] table_or_view_name

}

Nazwa indeksu jest unikalna dla danej tabeli lub widoku. Indeks niepowtarzalny (UNIQUE) może być utworzony jedynie w przypadku, gdy dane w tabeli na to pozwolą, w przypadku przeciwnym sygnalizowany będzie błąd. Indeks posiadający cechę CLUSTERED narzuca fizyczną kolejność rekordów w tablicy. Tablica (lub widok) może mieć tylko jeden indeks z taką cechą - wszelkie inne indeksy nie są związane z fizyczną kolejnością rekordów. Właściwości utworzonego indeksu ustala się za pomocą opcji. SKŁADNIA

<relational_index_option> ::=

{

PAD_INDEX = { ON | OFF }

| FILLFACTOR =fillfactor

| SORT_IN_TEMPDB = { ON | OFF }

| IGNORE_DUP_KEY = { ON | OFF }

| STATISTICS_NORECOMPUTE = { ON | OFF }

| DROP_EXISTING = { ON | OFF }

| ONLINE = { ON | OFF }

| ALLOW_ROW_LOCKS = { ON | OFF }

| ALLOW_PAGE_LOCKS = { ON | OFF }

| MAXDOP = MAX_degree_of_parallelism

| DATA_COMPRESSION = { NONE | ROW | PAGE}

[ON PARTITIONS ( {<partition_number_expression> | <range>} [, ...n])]

}

Do usunięcia indeksu służy polecenie DROP INDEX.

Page 13: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

13

Przykłady

Utworzenie prostego indeksu Poniższe polecenia spowodują utworzenie indeksu na kolumnie BisinessEntityID w tablicy Purchasing.ProductVendor. IF EXISTS (SELECT name FROM sys.indexes

WHERE name = N'IX_ProductVendor_VendorID')

DROP INDEX IX_ProductVendor_VendorID ON Purchasing.ProductVendor;

GO

CREATE INDEX IX_ProductVendor_VendorID

ON Purchasing.ProductVendor (BusinessEntityID);

GO

Utworzenie indeksu złożonego Tworzymy indeks na kolumnach SalesQuota i SalesYDT w tablicy Sales.SalesPerson. IF EXISTS (SELECT name FROM sys.indexes

WHERE name = N'IX_SalesPerson_SalesQuota_SalesYTD')

DROP INDEX IX_SalesPerson_SalesQuota_SalesYTD ON Sales.SalesPerson ;

GO

CREATE NONCLUSTERED INDEX IX_SalesPerson_SalesQuota_SalesYTD

ON Sales.SalesPerson (SalesQuota, SalesYTD);

GO

Utworzenie indeksu unikalnego Ten indeks wymusi niepowtarzalność danych w kolumnie Name w tablicy Production.UnitMeasure. IF EXISTS (SELECT name FROM sys.indexes

WHERE name = N'AK_UnitMeasure_Name')

DROP INDEX AK_UnitMeasure_Name ON Production.UnitMeasure;

GO

CREATE UNIQUE INDEX AK_UnitMeasure_Name

ON Production.UnitMeasure(Name);

GO

Użycie klauzuli DROP_EXISTING do usunięcia i przebudowy indeksu CREATE NONCLUSTERED INDEX IX_WorkOrder_ProductID

ON Production.WorkOrder(ProductID)

WITH (DROP_EXISTING = ON);

GO

Page 14: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

14

3. Język operowania danymi (DML - Data Manipulation Language)

3.1. Pobranie istniejących danych (SELECT) Do wyboru odpowiedniego zestawu danych z tabeli lub widoku służy polecenie SELECT. Pełna postać tego polecenia jest skomplikowana, w ogólnym zarysie ma postać:

[ WITH <common_table_expression>]

SELECT SELECT_list [ INTO new_table ]

[ FROM table_source ] [ WHERE search_condition ]

[ GROUP BY group_by_expression ]

[ HAVING search_condition ]

[ ORDER BY order_expression [ ASC | DESC ] ]

Wybór danych odbywa się za pomocą zapytania. Do łączenia wyników zapytań w jeden zbiór mogą być użyte operatory UNION, EXCEPT oraz INTERSECT. Specyfikacja pojedynczego zapytania może zawierać klauzule INTO, FROM, WHERE, GROUP BY oraz HAVING. SKŁADNIA

<SELECT statement> ::=

[WITH <common_table_expression> [,...n]]

<query_expression>

[ORDER BY {order_by_expression|column_position [ASC|DESC]} [,...n] ]

[ COMPUTE

{{AVG|COUNT|MAX|MIN|SUM} (expression)} [ ,...n ] [BY expression [,...n]]

]

[ <FOR Clause>]

[ OPTION ( <query_hint> [ ,...n ] ) ]

<query_expression> ::=

{<query_specification> | (<query_expression>)}

[{UNION [ALL]|EXCEPT|INTERSECT}

<query_specification>|(<query_expression>)[,...n]

]

<query_specification> ::=

SELECT [ALL|DISTINCT] [TOP (expression) [PERCENT] [WITH TIES]]

< SELECT_list >

[INTO new_table ]

[FROM {<table_source>} [,...n]]

[WHERE <search_condition>]

[<GROUP BY>]

[HAVING <search_condition>]

3.1.1. Klauzula WITH. Wyrażenie tablicowe. Wprowadza nazwę i formę tymczasowego zestawu danych (CTE - common table expression), definiowanych w prostym zapytaniu SELECT, INSERT, UPDATE, MERGE lub DELETE. SKŁADNIA

[WITH <common_table_expression> [,...n]]

<common_table_expression>::=

expression_name [(column_name [,...n])]

AS

(<CTE_query_definition>)

Po CTE może wystąpić proste wyrażenie SELECT, INSERT, UPDATE, MERGE lub DELETE, z którego pochodzą niektóre (lub wszystkie) kolumny CTE. CTE może być również użyte w definicji widoku, jako część wyrażenia SELECT.

Mnogie definicje CTE mogą być budowane (nierekursywnie) za pomocą operatorów UNION ALL, UNION, INTERSECT lub EXCEPT.

CTE może używać odniesień do innych CTE zdefiniowanych uprzednio w tej samej klauzuli WITH. Dopuszczalna jest tylko pojedyncza klauzula WITH (nie jest dopuszczalne ich zagnieżdżanie) Wewnątrz CTE_query_definition nie są dopuszczalne klauzule:

Page 15: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

15

o COMPUTE lub COMPUTE BY o ORDER BY (chyba że wraz z klauzulą TOP) o INTO o OPTION o FOR XML o FOR BROWSE

Jeśli wyrażenie CTE jest użyte w skrypcie, poprzednie polecenie musi być zakończone średnikiem. Zapytania używające CTE mogą wystąpić w definicjach kursorów. Jeśli w klauzuli FROM zostanie nadany alias CTE, ten alias musi być używany we wszystkich innych

odniesieniach do CTE.

Przykład

Utworzenie prostego CTE Poniższe polecenia spowodują wyświetlenie zestawienia zamówień dla każdego sprzedawcy: -- Definicja nazwy CTE i listy kolumn.

WITH Sales_CTE (SalesPersonID, SalesOrderID, SalesYear) AS

-- Definicja zapytania dla CTE.

(

SELECT SalesPersonID, SalesOrderID, YEAR(OrderDate) AS SalesYear

FROM Sales.SalesOrderHeader

WHERE SalesPersonID IS NOT NULL

)

-- Zewnętrzne zapytanie działające na zdefiniowanym CTE.

SELECT SalesPersonID, COUNT(SalesOrderID) AS TotalSales, SalesYear

FROM Sales_CTE

GROUP BY SalesYear, SalesPersonID

ORDER BY SalesPersonID, SalesYear;

GO

3.1.2. Podzapytania (subquery) Podzapytanie jest to zapytanie zagnieżdżone wewnątrz polecenia SELECT, INSERT, UPDATE lub DELETE, albo wewnątrz innego podzapytania. Podzapytanie może wystąpić wszędzie, gdzie dozwolone jest wystąpienie wyrażenia, jeśli zwraca pojedynczą wartość. W przykładzie poniżej mamy podzapytanie w postaci wyrażenia kolumnowego, któremu nadano nazwę MaxUnitPrice wewnątrz polecenia SELECT. Polecenie SELECT zwraca wartości SalesOrderID i OrderDate zatablicy SalesOrderHeader oraz uzyskaną przez podzapytanie wartość MAX(UnitPrice) z tablicy SalesOrderDetail, dla tych rekordów, dla których wartość pola SalesOrderID w tej tablicy zgodna jest z wartością pola SalesOrderID z tablicy SalesOrderHeader: SELECT Ord.SalesOrderID, Ord.OrderDate, (

SELECT MAX(OrdDet.UnitPrice)

FROM Sales.SalesOrderDetail AS OrdDet

WHERE Ord.SalesOrderID = OrdDet.SalesOrderID

) AS MAXUnitPrice

FROM.Sales.SalesOrderHeader AS Ord

Podzapytanie jest też nazywane zapytaniem wewnętrznym, podczas gdy polecenie zawierające je nazywane jest zapytaniem zewnętrznym. Podzapytanie zwracające pojedynczą wartość może być użyte w miejscu, gdzie dozwolone jest wyrażenie: SELECT Name, ListPrice,

(SELECT AVG(ListPrice) FROM Production.Product) AS Average,

ListPrice - (SELECT AVG(ListPrice) FROM Production.Product)

AS Difference

FROM Production.Product

WHERE ProductSubcategoryID = 1;

Wiele wyrażeń Transact-SQL zawierających podzapytania może być alternatywnie sformułowane jako złączenia. Niektóre mogą być realizowane wyłącznie za pomocą podzapytań. Czasami, gdy musi być sprawdzane istnienie, złączenie daje lepszą jakość. W przeciwnym przypadku zagnieżdżone podzapytanie musi być przetwarzane dla każdego wyniku zapytania zewnętrznego aby wyeliminować duplikaty. Poniższy przykład pokazuje dwie wersje polecenia SELECT: -- SELECT statement built using a subquery.

SELECT Name

Page 16: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

16

FROM AdventureWorks2008R2.Production.Product

WHERE ListPrice =

(SELECT ListPrice

FROM AdventureWorks2008R2.Production.Product

WHERE Name = 'Chainring Bolts' );

-- SELECT statement built using a join that returns the same result set.

SELECT Prd1.Name

FROM AdventureWorks2008R2.Production.Product AS Prd1

JOIN AdventureWorks2008R2.Production.Product AS Prd2

ON (Prd1.ListPrice = Prd2.ListPrice)

WHERE Prd2. Name = 'Chainring Bolts';

Podzapytania mogą być zagnieżdżane. Maksymalny poziom zagnieżdżenia równy jest 32. -- Nested subqueries.

SELECT LastName, FirstName

FROM Person.Person

WHERE BusinessEntityID IN

(SELECT BusinessEntityID

FROM HumanResources.Employee

WHERE BusinessEntityID IN

(SELECT BusinessEntityID

FROM Sales.SalesPerson))

Podzapytanie zagnieżdżone w zewnętrznym poleceniu SELECT zawiera następujące elementy: Wyrażenie SELECT zawierające listę kolumn. Klauzulę FROM określającą jedną lub więcej tabel lub widoków. Opcjonalnie klauzulę WHERE. Opcjonalnie klauzulę GROUP BY. Opcjonalnie klauzulę HAVING.

Podzapytanie jest zawsze zawarte w nawiasach. Nie może ono zawierać klauzul COMPUTE ani FOR BROWSE, ale może zawierać klauzulę ORDER BY, jeżeli występuje również klauzula TOP. Jeżeli jakaś tablica występuje wyłącznie w podzapytaniu, to jej kolumny nie mogą pojawić się w wyniku zapytania zewnętrznego. Typowe wyrażenia zawierające podzapytania:

WHERE <wyrażenie> [NOT] IN (<podzapytanie>) WHERE <wyrażene><operator porównania> [ANY|ALL] (<podzapytanie>) WHERE [NOT] EXISTS (<podzapytanie>)

W niektórych wyrażeniach Transact-SQL podzapytanie jest przetwarzane jak niezależne zapytanie, a jego wyniki są przekazywane do zapytania zewnętrznego. Są trzy podstawowe typy podzapytań:

Działające na listach - poprzedzone przez IN lub te, w których poprzedzający operator porównania jest zmodyfikowany przez ANY bądź ALL.

Zwracające pojedynczą wartość - poprzedzone niemodyfikowanym operatorem porównania. Testy istnienia - poprzedzone przez EXISTS.

3.1.2.1. Ograniczenia użycia podzapytań Podzapytanie podlega następującym ograniczeniom:

Lista wyboru podzapytania poprzedzonego operatorem porównania może zawierać tylko jedno wyrażenie lub nazwę kolumny (w odróżnieniu od EXISTS oraz IN, które działają odpowiednio na SELECT * lub SELECT <lista>).

Jeżeli klauzula WHERE zapytania zewnętrznego zawiera nazwę kolumny, musi być ona dostępna (złączeniowo-zgodna) z kolumną z listy podzapytania.

W listach podzapytań nie mogą być użyte kolumny typu ntext, text ani image. Podzapytania poprzedzone przez niemodyfikowany operator porównania (jeżeli nie występuje po nim ANY

lub ALL) nie mogą zawierać klauzul GROUP BY ani HAVING (bo muszą zwracać pojedynczą wartość). Słowo kluczowe DISTINCT nie może występować w podzapytaniach zawierających GROUP BY. Klauzule COMPUTE i INTO nie są dozwolone. ORDER BY może wystąpić jedynie w parze z TOP. Widoki utworzone z wykorzystaniem podzapytań są nieaktualizowalne. W liście wyboru podzapytania poprzedzonego przez EXISTS występuje * zamiast nazwy pojedynczej

kolumny. Warunki dla takiego podzapytania są identyczne jak dla standardowej listy wyboru, ponieważ wykonuje ono test istnienia i zwraca wartość TRUE lub FALSE zamiast danych.

Page 17: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

17

3.1.2.2. Kwalifikowanie nazw kolumn w podzapytaniach W poniższym przykładzie kolumna CustomerID w klauzuli WHERE zapytania zewnętrznego jest niejawnie kwalifikowana przez nazwę tablicy w klauzuli FROM tego zapytania, tj. Sales.Store. Kolumna CustomerID w liście wyboru podzapytania jest kwalifikowana przez tabelę Sales.Customer, występującą w klauzuli FROM podzapytania. Gdyby ta kolumna nie występowała w tabeli, byłaby niejawnie kwalifikowana przez tabelę z klauzuli FROM polecenia zewnętrznego. SELECT Name

FROM Sales.Store

WHERE CustomerID NOT IN

(SELECT CustomerID

FROM Sales.Customer

WHERE TerritoryID = 5)

Zawsze istnieje możliwość zadeklarowania tabeli, aby zastąpić niejawne założenie jawną kwalifikacją.

3.1.2.3. Podzapytania z aliasami Wiele poleceń w których podzapytanie i zapytanie zewnętrzne odnoszą sie do tej samej tabeli mogą być zastąpione samozłączeniami (self-join). Przykładowo można znaleźć adresy pracowników z określonego stanu za pomocą podzapytania:

SELECT StateProvinceID, AddressID

FROM Person.Address

WHERE AddressID IN

(SELECT AddressID

FROM Person.Address

WHERE StateProvinceID = 39)

Można też użyć złączenia:

SELECT e1.StateProvinceID, e1.AddressID

FROM Person.Address AS e1

INNER JOIN Person.Address AS e2

ON e1.AddressID = e2.AddressID AND e2.StateProvinceID = 39;

Tu aliasy tablic są wymagane, ponieważ tablica łączona z samą sobą występuje w dwu różnych rolach. Aliasów można również użyć dla uzyskania czytelniejszego zapisu w podzapytaniach które odwołują się do tej samej tabeli w zapytaniu wewnętrznym i zewnętrznym.

SELECT e1.StateProvinceID, e1.AddressID

FROM Person.Address AS e1

WHERE e1.AddressID IN

(SELECT e2.AddressID

FROM Person.Address AS e2

WHERE e2.StateProvinceID = 39)

3.1.2.4. Podzapytania z IN (lub NOT IN) Wynikiem podzapytania poprzedzonego przez IN (lub NOT IN) jest lista zawierająca zero lub więcej wartości, które mogą być użyte przez zapytanie zewnętrzne.

SELECT Name

FROM Production.Product

WHERE ProductSubcategoryID IN

(SELECT ProductSubcategoryID

FROM Production.ProductSubcategory

WHERE Name = 'Wheels');

Zapytanie powyższe działa w dwóch etapach. Najpierw w tabeli Production.ProductSubcategory poszukuje numeru identyfikacyjnego dla podkategorii o nazwie 'Wheel'. Następnie używa tego numeru do wybrania z tabeli Production.Product nazw produktów należących do tej podkategorii. Jedyna różnica w użyciu złączenia zamiast podzapytania jest ta, że w wyniku można pokazać więcej niż jedną kolumnę z więcej niż jednej tablicy.

SELECT p.Name, s.Name AS N'Subcategory'

FROM Production.Product p

INNER JOIN Production.ProductSubcategory s

ON p.ProductSubcategoryID = s.ProductSubcategoryID AND s.Name = 'Wheels';

Zapytanie poniżej znajduje nazwy wszystkich klientów, którzy mają dobry status kredytowania, u których zamówiono co najmniej 20 elementów i których średni czas dostawy jest mniejszy niż 16 dni.

Page 18: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

18

SELECT Name

FROM Purchasing.Vendor

WHERE CreditRating = 1

AND BusinessEntityID IN

(SELECT BusinessEntityID

FROM Purchasing.ProductVendor

WHERE MinOrderQty >= 20 AND AverageLeadTime < 16);

Zapytanie wewnętrzne jest realizowane zwracając identyfikatory klientów, którzy spełniają warunki. Następnie realizowane jest zapytanie zewnętrzne. To samo zapytanie przy użyciu złączenia:

SELECT DISTINCT Name

FROM Purchasing.Vendor v

INNER JOIN Purchasing.ProductVendor p

ON v.BusinessEntityID = p.BusinessEntityID

WHERE CreditRating = 1

AND MinOrderQty >= 20

AND AverageLeadTime < 16;

Złączenie zawsze może być zastąpione podzapytaniem. Podzapytanie często (choć nie zawsze) można zastąpić złączeniem, ponieważ złączenia są symetryczne a podzapytania niekoniecznie. Poniższe zapytanie poszukuje nazw produktów nie będących gotowymi rowerami.

SELECT Name

FROM Production.Product

WHERE ProductSubcategoryID NOT IN

(SELECT ProductSubcategoryID

FROM Production.ProductSubcategory

WHERE Name = 'Mountain Bikes'

OR Name = 'Road Bikes'

OR Name = 'Touring Bikes');

Powyższe zapytanie nie może być zastąpione złączeniem, gdyż analogiczne nierównozłączenie posiada inne znaczenie.

3.1.2.5. Podzapytania z operatorami porównania Podzapytanie może być poprzedzone przez jeden z operatorów porównania: =, <>, >, >=, <, !>, !< lub <=. Takie podzapytanie musi zwracać pojedynczą wartość, nie możemy więc użyć GROUP BY ani HAVING, chyba że znając dane wiemy, że wynik będzie pojedynczą wartością (np. grupowanie wg klucza głównego i warunek HAVING wybierający konkretną wartość tego klucza). Podzapytania te często zawierają funkcje agregujące. SELECT Name

FROM Production.Product

WHERE ListPrice >

(SELECT AVG (ListPrice)

FROM Production.Product);

3.1.2.6. Operatory porównania modyfikowane przez ANY, SOME lub ALL Operator porównania poprzedzający podzapytanie może być modyfikowany przez słowa kluczowe ALL lub ANY (ISO używa SOME jako ekwiwalentu ANY). Takie podzapytanie może zwracać zero lub więcej wartości i posiadać klauzulę GROUP BY i HAVING. Może być zastąpione przez podzapytanie z EXISTS. Przykładowo > ALL oznacza, że poszukiwana wartość musi być większa od dowolnej ze zwracanych wartości, natomiast > ANY oznacza, że poszukiwana wartość musi być większa przynajmniej od jednej ze zwracanych wartości. SELECT Name

FROM Production.Product

WHERE ListPrice >= ANY

(SELECT MAX (ListPrice)

FROM Production.Product

GROUP BY ProductSubcategoryID) ;

Operator = ANY jest równoważny do IN, operator <>ALL jest równoważny do NOT IN.

3.1.2.7. Podzapytania z [NOT] EXISTS Przeprowadzają one test istnienia. Klauzula WHERE zapytania zewnętrznego testuje, czy podzapytanie zwróciło jakieś wiersze. Wyrażenie [NOT] EXISTS (<podzapytanie>) zwraca wartość TRUE lub FALSE.

Page 19: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

19

Poniższe zapytanie poszukuje nazw wszystkich produktów z podkategorii Wheels: SELECT Name

FROM Production.Product

WHERE EXISTS

(SELECT *

FROM Production.ProductSubcategory

WHERE ProductSubcategoryID =

Production.Product.ProductSubcategoryID

AND Name = 'Wheels');

Różnice w porównaniu z innymi podzapytaniami: Słowo kluczowe EXISTS nie jest poprzedzone nazwą kolumny, stałą ani innym wyrażeniem Lista wyboru w podzapytaniu niemal zawsze zawiera *. Nie ma potrzeby wypisywać nazw kolumn,

ponieważ testowane jest jedynie czy są jakieś wiersze spełniające warunek. Często można użyć IN lub operatora porównania modyfikowanego przez ANY lub ALL dla uzyskania takich samych efektów. Przykładowo poprzednie zapytanie może być zastąpione przez: SELECT Name

FROM Production.Product

WHERE ProductSubcategoryID IN

(SELECT ProductSubcategoryID

FROM Production.ProductSubcategory

WHERE Name = 'Wheels');

3.1.2.8. Podzapytania skorelowane W zapytaniach zawierających podzapytania skorelowane, zapytanie wewnętrzne jest realizowane oddzielnie dla każdego wiersza z zapytania zewnętrznego. SELECT DISTINCT c.LastName, c.FirstName, e.BusinessEntityID

FROM Person.Person AS c JOIN HumanResources.Employee AS e

ON e.BusinessEntityID = c.BusinessEntityID

WHERE 5000.00 IN

(SELECT Bonus

FROM Sales.SalesPerson sp

WHERE e.BusinessEntityID = sp.BusinessEntityID) ;

GO

Zapytanie wewnętrzne może się odnosić do tej samej tabeli w dwu rolach. W tym przypadku konieczne jest użycie aliasów. SELECT DISTINCT pv1.ProductID, pv1.BusinessEntityID

FROM Purchasing.ProductVendor pv1

WHERE ProductID IN

(SELECT pv2.ProductID

FROM Purchasing.ProductVendor pv2

WHERE pv1.BusinessEntityID <> pv2.BusinessEntityID)

ORDER BY pv1.BusinessEntityID

Podzapytania skorelowanego, poprzedzonego operatorem porównania użyjemy dla wyszukania pozycji zamówień, w których ilość jest poniżej średniej dla danego produktu: SELECT ProductID, OrderQty

FROM Sales.SalesOrderDetail s1

WHERE s1.OrderQty <

(SELECT AVG (s2.OrderQty)

FROM Sales.SalesOrderDetail s2

WHERE s2.ProductID = s1.ProductID);

Zapytanie zewnętrzne wybiera kolejno wiersze z tablicy pozycji (s1). Dla każdego z nich podzapytanie oblicza średnią ilość dla danego produktu i jeżeli ilość w s1 jest mniejsza od tej średniej, to rekord zostaje dołączony do wyniku. Podzapytanie może być również użyte w klauzuli HAVING zapytania zewnętrznego. W poniższym przykładzie poszukujemy modeli produktów, których maksymalna cena przekracza dwukrotnie średnią dla modelu. SELECT p1.ProductModelID

FROM Production.Product p1

GROUP BY p1.ProductModelID

HAVING MAX(p1.ListPrice) >= ALL

(SELECT 2 * AVG(p2.ListPrice)

FROM Production.Product p2

WHERE p1.ProductModelID = p2.ProductModelID) ;

Page 20: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

20

GO

W tym przypadku podzapytanie jest wykonywane jednokrotnie dla każdej grupy zdefiniowanej w zapytaniu zewnętrznym.

3.1.3. Wyrażenie SELECT Określa kolumny zwracane przez zapytanie. SKŁADNIA

SELECT [ALL | DISTINCT] [TOP (expression) [PERCENT] [WITH TIES]]

<SELECT_list>

<SELECT_list> ::=

{

*

| {table_name | view_name | table_alias}.*

| {

[{table_name | view_name | table_alias}.]

{column_name | $IDENTITY | $ROWGUID}

| udt_column_name [{ . | :: } {{property_name | field_name}

| method_name (argument [,...n])}]

| expression

[[AS] column_alias]

}

| column_alias =expression

} [,...n]

ALL oznacza, że w wyniku mogą wystąpić identyczne wiersze (wartość domyślna), podczas gdy DISTINCT oznacza wybrania jedynie unikalnych wierszy. Klauzula TOP określa jaka część wyniku (ilość wierszy numerycznie lub procentowo) będzie zwrócona przez zapytanie.

Przykłady

Użycie SELECT do pobrania kolumn i wierszy Pobranie wszystkich kolumn i wierszy (nie ma klauzuli WHERE) SELECT *

FROM Production.Product

ORDER BY Name ASC;

Pobranie wybranych kolumn i wszystkich wierszy, użycie aliasu dla tablicy SELECT p.Name, p.ProductNumber, p.ListPrice AS Price

FROM Production.Product AS p

ORDER BY Name ASC;

GO

Pobranie wybranych kolumn i wierszy. SELECT Name, ProductNumber, ListPrice AS Price

FROM Production.Product

WHERE ProductLine = 'R'

AND DaysToManufacture < 4

ORDER BY Name ASC;

GO

Użycie SELECT z nagłówkami kolumn i wyliczeniami Wyświetlenie całkowitej sprzedaży i upustów dla każdego produktu. SELECT p.Name AS ProductName,

NonDiscountSales = (OrderQty * UnitPrice),

Discounts = ((OrderQty * UnitPrice) * UnitPriceDiscount)

FROM Production.Product AS p

INNER JOIN Sales.SalesOrderDetail AS sod

ON p.ProductID = sod.ProductID

ORDER BY ProductName DESC;

GO

Wyświetlenie całkowitego zysku dla każdego produktu. SELECT 'Total income is', ((OrderQty * UnitPrice) * (1.0 - UnitPriceDiscount)),

Page 21: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

21

' for ', p.Name AS ProductName

FROM Production.Product AS p

INNER JOIN Sales.SalesOrderDetail AS sod

ON p.ProductID = sod.ProductID

ORDER BY ProductName ASC;

GO

Użycie DISTINCT w poleceniu SELECT SELECT DISTINCT JobTitle

FROM HumanResources.Employee

ORDER BY JobTitle;

3.1.4. Wyrażenie CASE Wyrażenie CASE może być użyte wewnątrz dowolnego polecenia lub klauzuli dopuszczającej wyrażenie. Można więc wystąpić w poleceniach SELECT, UPDATE, DELETE oraz SET i klauzulach takich jak select list, IN, WHERE, ORDER BY i HAVING. Wyrażenie CASE ma dwie formy:

prosta – porównanie wyrażenia wejściowego z zestawem wartości, aby określić wynik. Jeżeli żadna z wartości when_expression nie jest równa input_expression, to wynikiem jest else_result_expression (lub NULL).

logiczna – wykonanie szeregu wyrażeń logicznych dla określenia wyniku. Jeżeli żadne z wyrażeń nie zwraca wartości TRUE, to to wynikiem jest else_result_expression (lub NULL).

SKŁADNIA

Proste wyrażenie CASE:

CASE input_expression

WHEN when_expression THEN result_expression [ ...n ]

[ ELSE else_result_expression ]

END

Logiczne wyrażenie CASE:

CASE

WHEN Boolean_expression THEN result_expression [ ...n ]

[ ELSE else_result_expression ]

END

Przykład Proste wyrażenie CASE dopuszcza jedynie test równości:

SELECT ProductNumber, Category =

CASE ProductLine

WHEN 'R' THEN 'Road'

WHEN 'M' THEN 'Mountain'

WHEN 'T' THEN 'Touring'

WHEN 'S' THEN 'Other sale items'

ELSE 'Not for sale'

END,

Name

FROM Production.Product

ORDER BY ProductNumber;

GO

W wyrażeniu CASE logicznym możemy innych operacji: SELECT ProductNumber, Name, 'Price Range' =

CASE

WHEN ListPrice = 0 THEN 'Mfg item - not for resale'

WHEN ListPrice < 50 THEN 'Under $50'

WHEN ListPrice >= 50 and ListPrice < 250 THEN 'Under $250'

WHEN ListPrice >= 250 and ListPrice < 1000 THEN 'Under $1000'

ELSE 'Over $1000'

END

FROM Production.Product

ORDER BY ProductNumber ;

GO

Page 22: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

22

3.1.5. Klauzula INTO Umieszcza wynik zapytania w nowej tablicy. Jeżeli w zapytaniu wystąpi kolumna posiadająca atrybut IDENTITY, do atrybut ten jest dziedziczony, chyba że wyrażenie SELECT zawiera złączenie, klauzulę GROUP BY lub funkcje agregacji albo dana kolumna wchodzi w skład wyrażenia. SKŁADNIA [INTO new_table]

Przykład

Tworzenie tablicy tymczasowej przy pomocy SELECT .. INTO IF OBJECT_ID (N'#Bicycles',N'U') IS NOT NULL

DROP TABLE #Bicycles;

GO

SELECT *

INTO #Bicycles

FROM AdventureWorks2008R2.Production.Product

WHERE ProductNumber LIKE 'BK%';

GO

Tworzenie tablicy na podstawie wielu źródeł SELECT c.FirstName, c.LastName, e.JobTitle, a.AddressLine1, a.City,

sp.Name AS [State/Province], a.PostalCode

INTO dbo.EmployeeAddresses

FROM Person.Person AS c

JOIN HumanResources.Employee AS e

ON e.BusinessEntityID = c.BusinessEntityID

JOIN Person.BusinessEntityAddress AS bea

ON e.BusinessEntityID = bea.BusinessEntityID

JOIN Person.Address AS a

ON bea.AddressID = a.AddressID

JOIN Person.StateProvince AS sp

ON sp.StateProvinceID = a.StateProvinceID;

GO

3.1.6. Funkcje agregujące Funkcje agregujące wykonują obliczenia na zbiorze danych i zwracają pojedynczą wartość. Za wyjątkiem COUNT, funkcje agregujące pomijają wartości NULL. Wszystkie funkcje agregujące są deterministyczne, tzn. zwracają tę samą wartość za każdym razem, kiedy zostaną uruchomione z tym samym zbiorem danych wejściowych. Funkcje agregujące mogą wystąpić jako wyrażenia jedynie w:

liście wyboru polecenia SELECT, klauzuli COMPUTE lub COMPUTE BY, klauzuli HAVING.

Transact-SQL udostępnia następujące funkcje agregujące, występujące w standardzie SQL: AVG - obliczanie wartości średniej zbioru wartości liczbowych, COUNT - zliczanie liczby elementów, MAX - zwraca wartość maksymalną zbioru, MIN - zwraca wartość minimalną zbioru, SUM - oblicza sumę wartości elementów zbioru liczbowego,

oraz szereg innych funkcji agregujących, jak np.: STDEV - oblicza standardową dewiację w zbiorze wartości liczbowych, VAR - oblicza wariancję w zbiorze wartości liczbowych.

Przykład Wyliczenie sum cen i kosztów dla wybranych produktów, zgrupowanych wg koloru SELECT Color, SUM(ListPrice), SUM(StandardCost)

FROM Production.Product

WHERE Color IS NOT NULL

Page 23: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

23

AND ListPrice != 0.00

AND Name LIKE 'Mountain%'

GROUP BY Color

ORDER BY Color;

GO

3.1.7. Klauzula FROM Określa tablice, widoki, tablice pochodne i złączenia wykorzystywane w wyrażeniach DELETE, SELECT i UPDATE. Wyrażenie SELECT musi zawierać klauzulę FROM, chyba że na liście wyboru znajdują się wyłącznie stałe, zmienne i wyrażenia arytmetyczne (nie ma nazw kolumn). SKŁADNIA

[FROM {<table_source>} [,...n]]

<table_source> ::=

{

table_or_view_name [[AS] table_alias] [<tablesample_clause>]

[WITH (< table_hint > [,...n])]

| rowset_function [[AS] table_alias]

[(bulk_column_alias [,...n])]

| user_defined_function [[AS] table_alias]]

| OPENXML <openxml_clause>

| derived_table [AS] table_alias [(column_alias [,...n])]

| <joined_table>

| <pivoted_table>

| <unpivoted_table>

| @variable [[AS] table_alias]

| @variable.function_call (expression [,...n]) [[AS] table_alias]

[(column_alias [,...n])]

}

<tablesample_clause> ::=

TABLESAMPLE [SYSTEM] (sample_number [PERCENT | ROWS])

[REPEATABLE (repeat_seed)]

<joined_table> ::=

{

<table_source> <join_type> <table_source> ON <search_condition>

| <table_source> CROSS JOIN <table_source>

| left_table_source {CROSS | OUTER} APPLY right_table_source

| [ ( ] <joined_table> [ ) ]

}

<join_type> ::=

[{INNER | {{LEFT | RIGHT | FULL} [OUTER]}} [<join_hint>]] JOIN

<pivoted_table> ::=

table_source PIVOT <pivot_clause> [AS] table_alias

<pivot_clause> ::=

(aggregate_function(value_column [,...n])

FOR pivot_column IN (<column_list>)

)

<unpivoted_table> ::=

table_source UNPIVOT <unpivot_clause> [AS] table_alias

<unpivot_clause> ::=(value_column FOR pivot_column IN (<column_list>))

<column_list> ::=column_name [,...n]

Przykład

Prosta klauzula FROM SELECT TerritoryID, Name

FROM Sales.SalesTerritory

ORDER BY TerritoryID

Page 24: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

24

Użycie złączeń w klauzuli FROM Źródłem będzie iloczyn tablic (CROSS JOIN): SELECT e.BusinessEntityID, d.Name AS Department

FROM HumanResources.Employee AS e

CROSS JOIN HumanResources.Department AS d

ORDER BY e.BusinessEntityID, d.Name ;

Dzięki użyciu złączenie FULL (OUTER) JOIN zapytanie zwróci wiersze zawierające nazwę produktu i numer zamówienia, dla których jest jednakowy identyfikator produktu w tablicach SalesOrderDetail i Product. Ponadto zamieszczone będą numery zamówień, w których identyfikator produktu nie występuje w tablicy Product oraz produkty, których identyfikatory nie występują w tablicy zamówień. -- Słowo kluczowe OUTER jest tu opcjonalne.

SELECT p.Name, sod.SalesOrderID

FROM Production.Product AS p

FULL OUTER JOIN Sales.SalesOrderDetail AS sod

ON p.ProductID = sod.ProductID

WHERE p.ProductID IS NULL OR sod.ProductID IS NULL

ORDER BY p.Name ;

To zapytanie zwróci wszystkie wiersze z tablicy Product i te wiersze z tablicy SalesOrderDetail, w których zgodne są identyfikatory produktu. SELECT p.Name, sod.SalesOrderID

FROM Production.Product AS p

LEFT OUTER JOIN Sales.SalesOrderDetail AS sod

ON p.ProductID = sod.ProductID

ORDER BY p.Name ;

-- Alternatywnie można to zapisać:

SELECT p.Name, sod.SalesOrderID

FROM Sales.SalesOrderDetail AS sod

RIGHT OUTER JOIN Production.Product AS p

ON p.ProductID = sod.ProductID

ORDER BY p.Name ;

W wyniku tego zapytania uzyskamy wyłącznie te produkty, które były zamówione. -- Domyślnie, SQL Server wykonuje INNER JOIN nawet gdy tylko samo słowo

-- kluczowe JOIN zostało użyte

SELECT p.Name, sod.SalesOrderID

FROM Production.Product AS p

INNER JOIN Sales.SalesOrderDetail AS sod

ON p.ProductID = sod.ProductID

ORDER BY p.Name ;

3.1.8. Klauzula WHERE Klauzula WHERE określa warunki które muszą spełniać wiersze zwracane przez polecenia DELETE, MERGE, SELECT lub UPDATE. SKŁADNIA

[WHERE <search_condition>]

Klauzula WHERE składa się z jednego lub więcej (nie ma ograniczeń) warunków wyboru połączonych operatorami logicznymi AND, OR i NOT. SKŁADNIA

<search_condition> ::=

{[NOT] <predicate> | (<search_condition>)}

[{AND | OR} [NOT] {<predicate> | ( <search_condition>)}] [,...n]

<predicate> ::=

{expression {= | <> | != | > | >= | !> | < | <= | !<} expression

| string_expression [NOT] LIKE string_expression [ESCAPE 'escape_character']

| expression [ NOT ] BETWEEN expression AND expression

| expression IS [ NOT ] NULL

| CONTAINS ({column | *} ,'<contains_search_condition>')

| FREETEXT ({column | *} ,'freetext_string')

| expression [NOT] IN (subquery | expression [,...n])

| expression {= | <> | != | > | >= | !> | < | <= | !<} {ALL | SOME | ANY}

(subquery)

| EXISTS (subquery)}

Page 25: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

25

Operator LIKE wykorzystuje znaki specjalne: % - dowolny ciąg 0 lub więcej znaków _ - dowolny pojedynczy znak [.-.] - dowolny pojedynczy znak z danego zakresu (np. [0-9] oznacza dowolną cyfrę) [^.-.] - dowolny znak spoza danego zakresu.

Znak zdefiniowany jako ESCAPE niweluje specjalne znaczenie tych znaków.

Przykład

Użycie WHERE z LIKE i ESCAPE W poniższym przykładzie poszukiwany będzie ciąg znaków green_: SELECT * FROM Production.ProductPhoto

WHERE LargePhotoFileName LIKE '%greena_%' ESCAPE 'a' ;

3.1.9. Klauzula GROUP BY Klauzula ta grupuje wybrany zbiór wierszy wg jednej lub większej ilości kolumn lub wyrażeń. Dla każdej grupy zwracany jest jeden wiersz. Funkcje agregacji w liście wyboru polecenia SELECT dostarczają informacji na temat każdej z grup, a nie pojedynczych wierszy. SKŁADNIA GROUP BY <column_expression> [,...n]

Przykłady

Proste użycie GROUP BY SELECT SalesOrderID, SUM(LineTotal) AS SubTotal

FROM Sales.SalesOrderDetail AS sod

GROUP BY SalesOrderID

ORDER BY SalesOrderID;

Użycie GROUP BY z wieloma tablicami SELECT a.City, COUNT(bea.AddressID) AS EmployeeCount

FROM Person.BusinessEntityAddress AS bea

INNER JOIN Person.Address AS a

ON bea.AddressID = a.AddressID

GROUP BY a.City

ORDER BY a.City;

Użycie GROUP BY z wyrażeniem SELECT DATEPART(yyyy,OrderDate) AS N'Year', SUM(TotalDue) AS N'Total Order Amount'

FROM Sales.SalesOrderHeader

GROUP BY DATEPART(yyyy,OrderDate)

ORDER BY DATEPART(yyyy,OrderDate);

Użycie GROUP BY z klauzulą HAVING W poleceniach SELECT z grupowaniem można użyć klauzuli HAVING dla określenia które z wierszy w każdej z grup będą brane pod uwagę. Jeżeli w poleceniu SELECT klauzula GROUP BY nie występuje, to HAVING zachowuje się dokładnie jak WHERE. W klauzuli HAVING nie mogą być używane pola typu text, image ani ntext.

SELECT SalesOrderID, SUM(LineTotal) AS SubTotal

FROM Sales.SalesOrderDetail

GROUP BY SalesOrderID

HAVING SUM(LineTotal) > 100000.00

ORDER BY SalesOrderID ;

3.1.10. Klauzula ORDER BY Określa sposób uporządkowania elementów w kolumnach zwróconych przez polecenie SELECT. Klauzula ta ma ograniczone zastosowanie w przypadku widoków, podzapytań, tablic pochodnych.

Page 26: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

26

SKŁADNIA [ ORDER BY

{

order_by_expression [ COLLATE collation_name ] [ ASC | DESC ]

} [ ,...n ]

]

COLLATE określa specyficzny sposób sortowania danych tekstowych (np. uwzględniający znaki diakrytyczne języków). Wartości NULL są traktowane jako najmniejsze.

Przykład Uporządkowanie malejące numerycznej zawartości kolumny ProductID. SELECT ProductID, Name FROM Production.Product

WHERE Name LIKE 'Lock Washer%'

ORDER BY ProductID DESC;

Pominięcie słowa DESC wywoła porządkowanie domyślne (narastające).

3.1.11. Klauzula COMPUTE Służy do generowania podsumowania z użyciem wybranej funkcji agregującej, na zakończenie danych wynikowych. Ta klauzula będzie wycofana. SKŁADNIA [ COMPUTE

{ { AVG | COUNT | MAX | MIN | STDEV | STDEVP | VAR | VARP | SUM }

( expression ) } [ ,...n ]

[ BY expression [ ,...n ] ]

]

Wyrażenie BY (występujące wyłącznie wraz z ORDER BY) generuje sumy częściowe.

Przykłady

Użycie COMPUTE dla uzyskania podsumowań W wyrażeniu SELECT użyto prostej klauzuli COMPUTE dla uzyskania sumy ogólnej dla kolumn SubTotal i TotalDue: SELECT CustomerID, OrderDate, SubTotal, TotalDue

FROM Sales.SalesOrderHeader

WHERE SalesPersonID = 35

ORDER BY OrderDate

COMPUTE SUM(SubTotal), SUM(TotalDue);

Użycie COMPUTE BY dla uzyskania podsumowań z sumami częściowymi W wyrażeniu SELECT użyto prostej COMPUTE dla uzyskania sumy ogólnej dla kolumn SubTotal i TotalDue i podsumowań dla poszczególnych wartości w SalesPersonID: SELECT SalesPersonID, CustomerID, OrderDate, SubTotal, TotalDue

FROM Sales.SalesOrderHeader

ORDER BY SalesPersonID, OrderDate

COMPUTE SUM(SubTotal), SUM(TotalDue) BY SalesPersonID;

3.1.12. Operator JOIN Operator JOIN definiuje sposób połączenia dwu tabel w zapytaniu przez:

Wyszczególnienie kolumn z każdej z tabel, które mają być użyte dla złączenia. Typowy warunek złączenia określa klucz obcy z jednej z tabel i skojarzony z nim klucz z drugiej tabeli.

Określenie operatora (np. = lub <>), który będzie zastosowany do porównania wartości w kolumnach. Dostępne są następujące typy operatora:

INNER JOIN, zwracane są wszystkie dopasowane pary wierszy z obu tabel. INNER jest wartością domyślną. FULL OUTER JOIN, oprócz wierszy dopasowanych zwracane są wszystkie pozostałe wiersze z obu tabel,

uzupełnione wartościami NULL. LEFT OUTER JOIN, oprócz wierszy dopasowanych zwracane są wszystkie pozostałe wiersze z lewej tabeli,

uzupełnione wartościami NULL. RIGHT OUTER JOIN, oprócz wierszy dopasowanych zwracane są wszystkie pozostałe wiersze z prawej

tabeli, uzupełnione wartościami NULL.

Page 27: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

27

CROSS JOIN, zwraca produkt kartezjański obu tabel SKŁADNIA <first_table> <join_type> <second_table> ON <join_condition>

|<first_table> CROSS JOIN <second_table>

|<first_table> {CROSS|OUTER} APPLY <second_table>

<join_type>::=

[{ INNER|{{LEFT|RIGHT|FULL}[ OUTER]}}[ <join_hint>]] JOIN

3.1.13. Klauzule UNION, INTERSECT i EXCEPT UNION łączy wyniki dwóch lub więcej zapytań w pojedynczy zestaw wierszy, które należały do poszczególnych zapytań. Klauzula UNION usuwa powtarzające się wiersze z wyniku, chyba że dodano słowo kluczowe ALL. EXCEPT zwraca unikalne wartości z wyników zapytania po lewej stronie, których nie ma w wynikach zapytania z prawej strony. INTERSECT zwraca unikalne wartości występujące jednocześnie w wynikach obu zapytań. Muszą przy tym być zachowane następujące warunki:

Ilość i kolejność kolumn musi być taka sama we wszystkich zapytaniach Typy danych w odpowiednich kolumnach muszą być kompatybilne.

SKŁADNIA

{<query_specification>|(<query_expression>)}

UNION [ALL] <query_specification>|(<query_expression>)

[UNION [ALL] <query_specification>|(<query_expression>) [,...n]]

{<query_specification>|(<query_expression>)}

{EXCEPT|INTERSECT}{<query_specification>|(<query_expression>)}

Jeśli w wyrażeniu zostały użyte obok siebie operatory UNION, EXCEPT I INTERSECT, to kolejność wykonywania jest następująca:

1. wyrażenia w nawiasach 2. operacja INTERSECT 3. operacje UNION i EXCEPT w kolejności od lewej do prawej

Przykłady

Proste użycie UNION W następującym przykładzie dane wynikowe składają się z zawartości kolumn ProductModelID i Name wziętych z tablic ProductModel oraz Gloves: IF OBJECT_ID ('dbo.Gloves', 'U') IS NOT NULL

DROP TABLE dbo.Gloves;

GO

-- Create Gloves table.

SELECT ProductModelID, Name

INTO dbo.Gloves

FROM Production.ProductModel

WHERE ProductModelID IN (3, 4);

GO

-- Here is the simple union.

SELECT ProductModelID, Name

FROM Production.ProductModel

WHERE ProductModelID NOT IN (3, 4)

UNION

SELECT ProductModelID, Name

FROM dbo.Gloves

ORDER BY Name;

GO

Użycie EXCEPT I INTERSECT W pierwszym zapytaniu pobieramy wszystkie elementy kolumny ProductID z tablicy Production.Product. SELECT ProductID

Page 28: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

28

FROM Production.Product ;

--Result: 504 Rows

Następnie wybieramy tylko te elementy, których ID występują w tablicy Production.WorkOrder: SELECT ProductID

FROM Production.Product

INTERSECT

SELECT ProductID

FROM Production.WorkOrder ;

--Result: 238 Rows (produkty, na które s¹ zlecenia produkcji)

Następnie te elementy, których nie ma w tablicy WorkOrders: SELECT ProductID

FROM Production.Product

EXCEPT

SELECT ProductID

FROM Production.WorkOrder ;

--Result: 266 Rows (produkty, na które nie ma zleceñ produkcji)

A w końcu te zlecania produkcyjne, w których ID nie występuje w tablicy produktów: SELECT ProductID

FROM Production.WorkOrder

EXCEPT

SELECT ProductID

FROM Production.Product ;

--Result: 0 Rows (zlecenia produkcji bez produktów)

3.2. Dodawanie wierszy do tabeli (INSERT) Do wprowadzenia nowych wierszy w tabeli służy polecenie SELECT. SKŁADNIA [ WITH <common_table_expression> [ ,...n ] ]

INSERT

{

[ TOP ( expression ) [ PERCENT ] ]

[ INTO ] { <object> | rowset_function_limited

[ WITH ( <Table_Hint_Limited> [ ...n ] ) ] }

{

[ ( column_list ) ]

[ <OUTPUT Clause> ]

{ VALUES ( { DEFAULT | NULL | expression } [ ,...n ] ) [ ,...n ]

| derived_table

| execute_statement

| <dml_table_source>

| DEFAULT VALUES

}

}

}

[ ; ]

gdzie: <object> ::=

{

[ server_name . database_name . schema_name .

| database_name .[ schema_name ] .

| schema_name .

]

table_or_view_name

}

DBMS automatycznie wprowadza wartości w kolumnach: posiadających właściwość IDENTITY posiadających zdefiniowaną wartość DEFAULT mają typ danych datastamp dopuszczających wartość NULL o wartości obliczanej na podstawie wyrażenia.

Page 29: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

29

Przykłady

Wstawianie pojedynczego wiersza W poniższym przykładzie wprowadzamy wiersz do tablicy Production.UnitMeasure, posiadającej kolumny UnitMeasureCode, Name oraz ModifiedDate. INSERT INTO Production.UnitMeasure

VALUES (N'FT', N'Feet', '20080414');

Wstawianie wielu wierszy (MS SQL Server 2008) INSERT INTO Production.UnitMeasure

VALUES (N'FT2', N'Square Feet ', '20080923'),

(N'Y', N'Yards', '20080923'),

(N'Y3', N'Cubic Yards', '20080923');

Wstawianie w zmienionej kolejności kolumn INSERT INTO Production.UnitMeasure (Name, UnitMeasureCode, ModifiedDate)

VALUES (N'Square Yards', N'Y2', GETDATE());

Wstawianie danych z innej tabeli INSERT INTO RetiredEmployee (Name, EmployeeID)

SELECT (Name, SalesmanID) FROM Salesmen

WHERE Salesmen.DateOfBirth < '19450101';

3.3. Modyfikacja wierszy w tabeli (UPDATE) Do modyfikacji wierszy w tabeli służy polecenie UPDATE. SKŁADNIA [ WITH <common_table_expression> [...n]]

UPDATE

[ TOP (expression) [PERCENT]]

{ { table_alias | <object> | rowset_function_limited

[WITH (<Table_Hint_Limited> [...n])]

}

|@table_variable

}

SET

{column_name = {expression|DEFAULT|NULL}

|{udt_column_name.{{property_name=expression

|field_name = expression}

|method_name (argument[,...n])

}

}

|column_name {.WRITE (expression, @Offset, @Length)}

|@variable = expression

|@variable = column = expression

|column_name {+=|-=|*=|/=|%=|&=|^=| |=} expression

|@variable {+=|-=|*=|/=|%=|&=|^=| |=} expression

|@variable = column {+=|-=|*=|/=|%=|&=|^=| |=} expression

} [,...n]

[<OUTPUT Clause> ]

[FROM {<table_source>} [,...n]]

[WHERE {<search_condition>

|{[CURRENT OF

{{[GLOBAL] cursor_name}

|cursor_variable_name

}

]

}

}

Page 30: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

30

]

[OPTION (<query_hint> [,...n])]

[ ; ]

Przykłady Zmiana wartości we wszystkich wierszach w pojedynczej kolumnie: UPDATE Person.Address

SET ModifiedDate = GETDATE();

Jednoczesna zmiana wielu kolumn UPDATE Sales.SalesPerson

SET Bonus = 6000, CommissionPct = .10, SalesQuota = NULL;

GO

Wybranie wierszy do modyfikacji za pomocą klauzuli WHERE: UPDATE Production.Product

SET Color = N'Metallic Red'

WHERE Name LIKE N'Road-250%' AND Color = N'Red';

-- Sprawdzenie czy cokolwiek zmodyfikowano

IF @@ROWCOUNT = 0

PRINT 'Nie zmodyfikowano żadnego wiersza w tabeli'

GO

Wybranie pierwszych 10 wierszy za pomocą TOP UPDATE TOP (10) HumanResources.Employee

SET VacationHours = VacationHours * 1.25 ;

GO

Użycie podzapytania Wybranie pierwszych 10 wierszy za pomocą podzapytania porządkującego: UPDATE HumanResources.Employee

SET VacationHours = VacationHours + 8

FROM (SELECT TOP 10 BusinessEntityID FROM HumanResources.Employee

ORDER BY HireDate ASC) AS th

WHERE HumanResources.Employee.BusinessEntityID = th.BusinessEntityID;

GO

Użycie podzapytania w klauzuli SET UPDATE Sales.SalesPerson

SET SalesYTD = SalesYTD +

(SELECT SUM(so.SubTotal)

FROM Sales.SalesOrderHeader AS so

WHERE so.OrderDate = (SELECT MAX(OrderDate)

FROM Sales.SalesOrderHeader AS so2

WHERE so2.SalesPersonID = so.SalesPersonID)

AND Sales.SalesPerson.BusinessEntityID = so.SalesPersonID

GROUP BY so.SalesPersonID);

GO

Użycie wartości domyślnej UPDATE Production.Location

SET CostRate = DEFAULT

WHERE CostRate > 20.00;

3.4. Usuwanie wierszy z tabeli (DELETE) Do usuwania wierszy z tabeli służy polecenie DELETE. SKŁADNIA [WITH <common_table_expression> [,...n]]

DELETE

[TOP (expression) [PERCENT]]

[FROM]

{<object>|rowset_function_limited

[WITH (<table_hint_limited> [...n])]

}

Page 31: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

31

[<OUTPUT Clause> ]

[FROM <table_source> [,...n]]

[WHERE {<search_condition>

|{[CURRENT OF

{{[GLOBAL] cursor_name}|cursor_variable_name}]}}

]

[OPTION (<Query Hint> [,...n])]

[ ; ]

Przykłady

Usunięcie wszystkich wierszy DELETE FROM Sales.SalesPersonQuotaHistory;

Usunięcie wybranych wierszy DELETE FROM Production.ProductCostHistory

WHERE StandardCost > 1000.00;

Użycie podzapytania Klasyczne wykorzystanie podzapytania: DELETE FROM Sales.SalesPersonQuotaHistory

WHERE BusinessEntityID IN

(SELECT BusinessEntityID

FROM Sales.SalesPerson

WHERE SalesYTD > 2500000.00);

GO

Wykorzystanie możliwości Transact-SQL w miejsce podzapytania: DELETE FROM Sales.SalesPersonQuotaHistory

FROM Sales.SalesPersonQuotaHistory AS spqh

INNER JOIN Sales.SalesPerson AS sp

ON spqh.BusinessEntityID = sp.BusinessEntityID

WHERE sp.SalesYTD > 2500000.00;

GO

Page 32: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

32

4. Elementy składni języka T-SQL

4.1. Powołanie zmiennej lokalnej (DECLARE) Zmienne są deklarowane w skryptach bądź procedurach za pomocą polecenia DECLARE. Wartości zmiennym nadają polecenia SET oraz SELECT. Po utworzeniu wszystkim zmiennym nadawana jest wartość NULL, chyba że w poleceniu DECLARE zostały one zainicjowane. Zmienna lokalna istnieje tylko wewnątrz funkcji lub bloku w którym była zadeklarowana. SKŁADNIA DECLARE

{

{{@local_variable [AS] data_type}|[ = value]}

|{@cursor_variable_name CURSOR}} [,...n]

|{ @table_variable_name [AS] <table_type_definition>

|<user-defined table type>}

Nazwa zmiennej lokalnej musi się zaczynać od znaku @. Typ danych może być dowolny, za wyjątkiem text, ntext oraz image.

Przykład

Użycie DECLARE DECLARE @find VARCHAR(30);

SET @find = 'Man%';

/* Można także zapisać (w MS SQL Server 2008):

DECLARE @find VARCHAR(30) = 'Man%';

*/

SELECT p.LastName, p.FirstName, ph.PhoneNumber

FROM Person.Person p

JOIN Person.PersonPhone ph

ON p.BusinessEntityID = ph.BusinessEntityID

WHERE LastName LIKE @find;

Zadeklarowanie lokalnej tablicy DECLARE @MyTableVar table(

EmpID INT NOT NULL,

OldVacationHours INT,

NewVacationHours INT,

ModifiedDate DATETIME);

Nadanie wartości poleceniem SELECT DECLARE @var1 NVARCHAR(30);

SELECT @var1 = 'Generic Name';

SELECT @var1 = Name

FROM Sales.Store

WHERE CustomerID = 1000 ;

SELECT @var1 AS 'Company Name';

4.2. Tworzenie procedur składowych (CREATE PROCEDURE) Z obsługą procedur związane są polecenia:

CREATE PROCEDURE ALTER PROCEDURE DROP PROCEDURE

Procedury zawierają kod, który może być uruchamiany za pomocą polecenia EXECUTE. SKŁADNIA CREATE { PROC | PROCEDURE } [schema_name.] procedure_name [ ; number ]

[ { @parameter [ type_schema_name. ] data_type }

[ VARYING ] [ = default ] [ OUT | OUTPUT ]

Page 33: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

33

] [ ,...n ]

[ WITH <procedure_option> [ ,...n ] ]

[ FOR REPLICATION ]

AS { <sql_statement> [;][ ...n ] | <method_specifier> }

[;]

Przykład

Procedura z argumentami wejściowymi IF OBJECT_ID ( 'HumanResources.uspGetEmpl', 'P' ) IS NOT NULL

DROP PROCEDURE HumanResources.uspGetEmpl;

GO

CREATE PROCEDURE HumanResources.uspGetEmpl

@LastName NVARCHAR(50),

@FirstName NVARCHAR(50)

AS

SET NOCOUNT ON;

SELECT FirstName,LastName,Department

FROM HumanResources.vEmployeeDepartmentHistory

WHERE FirstName = @FirstName AND LastName = @LastName;

GO

Uruchomienie tej procedury: EXECUTE HumanResources.uspGetEmpl N'Ackerman', N'Pilar';

lub EXECUTE HumanResources.uspGetEmpl @FirstName = N'Pilar', @LastName = N'Ackerman';

Procedura z argumentami wyjściowymi IF OBJECT_ID ( 'Production.uspGetList', 'P' ) IS NOT NULL

DROP PROCEDURE Production.uspGetList;

GO

CREATE PROCEDURE Production.uspGetList @Product VARCHAR(40)

, @MaxPrice money

, @ComparePrice money OUTPUT

, @ListPrice money OUT

AS

SET NOCOUNT ON;

SELECT p.[Name] AS Product, p.ListPrice AS 'List Price'

FROM Production.Product AS p

JOIN Production.ProductSubcategory AS s

ON p.ProductSubcategoryID = s.ProductSubcategoryID

WHERE s.[Name] LIKE @Product AND p.ListPrice < @ MaxPrice;

-- Populate the output variable @ListPprice.

SET @ListPrice = (SELECT MAX(p.ListPrice)

FROM Production.Product AS p

JOIN Production.ProductSubcategory AS s

ON p.ProductSubcategoryID = s.ProductSubcategoryID

WHERE s.[Name] LIKE @Product AND p.ListPrice < @ MaxPrice);

-- Populate the output variable @ComparePrice.

SET @ComparePrice = @ MaxPrice;

GO

Wywołanie tej procedury: DECLARE @ComparePrice money, @Cost money

EXECUTE Production.uspGetList '%Bikes%', 700,

@ComparePrice OUT,

@Cost OUTPUT

IF @Cost <= @ComparePrice

BEGIN

PRINT 'These products can be purchased for less than $' +

RTRIM(CAST(@ComparePrice AS VARCHAR(20)))+'.'

END

Page 34: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

34

ELSE

PRINT 'The prices for all products in this category exceed $' +

RTRIM(CAST(@ComparePrice AS VARCHAR(20)))+'.'

4.3. Uruchomienie kodu (EXECUTE) Polecenie to wykonuje rozkaz, kod zapisany w skrypcie, funkcję lub procedurę składową.. SKŁADNIA

Uruchomienie procedury składowej lub funkcji [{EXEC|EXECUTE}]

{

[@return_status = ]

{module_name [;number]|@module_name_var}

[[@parameter =] {value|@variable [OUTPUT]|[DEFAULT]}

] [,...n]

[WITH RECOMPILE ]

}

[ ; ]

Uruchomienie kodu w postaci ciągu znaków {EXEC|EXECUTE}

({@string_variable|[N]'tsql_string'} [+ ...n])

[AS {LOGIN|USER} = ' name ']

[ ; ]

Przesłanie polecenia do serwera {EXEC|EXECUTE }

({@string_variable|[N]'command_string [?]'} [ + ...n]

[{, {value|@variable [OUTPUT]}}[ ...n]]

)

[AS {LOGIN|USER} = ' name ' ]

[AT linked_server_name]

[ ; ]

4.4. Sterowanie programem

4.4.1. Deklaracja bloku (BEGIN...END) Blok programu zawarty między wyrażeniami BEGIN i END grupuje polecenia: SKŁADNIA BEGIN

{

sql_statement|statement_block

}

END

Bloki Begin...END mogą być zagnieżdżone.

Przykład BEGIN TRANSACTION;

GO

IF @@TRANCOUNT = 0

BEGIN

SELECT FirstName, MiddleName

FROM Person.Person WHERE LastName = 'Adams';

ROLLBACK TRANSACTION;

PRINT N'Rolling back the transaction two times would cause an error.';

END;

ROLLBACK TRANSACTION;

PRINT N'Rolled back the transaction.';

GO

Page 35: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

35

4.4.2. Instrukcja warunkowa (IF...ELSE) Instrukcja wykonywana jest przy spełnieniu warunku: SKŁADNIA IF Boolean_expression

{ sql_statement | statement_block }

[ ELSE

{ sql_statement | statement_block } ]

4.4.3. Instrukcja pętli (WHILE) Instrukcja powtarzana jest przy spełnieniu warunku: SKŁADNIA WHILE Boolean_expression

{ sql_statement | statement_block | BREAK | CONTINUE }

Polecenie BREAK powoduje przerwanie pracy pętli. Polecenie CONTINUE powoduje przejście na początek pętli i kontynuację obliczeń. Jeżeli w programie umieścimy etykiety, to możliwe jest także użycie polecenia skoku GOTO.

Przykład WHILE (SELECT AVG(ListPrice) FROM Production.Product) < $300

BEGIN

UPDATE Production.Product

SET ListPrice = ListPrice * 2

SELECT MAX(ListPrice) FROM Production.Product

IF (SELECT MAX(ListPrice) FROM Production.Product) > $500

BREAK

ELSE

CONTINUE

END

PRINT 'Too much for the market to bear';

Pętla jest powtarzana aż do osiągnięcia średniej ceny = $300 lub do przekroczenia przez cenę najdroższego produktu wartości $500.

4.4.4. Instrukcja oczekiwania (WAITFOR) Blokuje wykonywanie instrukcji aż do określonego momentu czasu (WAITFOR TIME <czas>) lub o określony czas (WAITFOR DELAY <opóźnienie>). SKŁADNIA WAITFOR

{

DELAY 'time_to_pass'

| TIME 'time_to_execute'

| [ ( receive_statement ) | ( get_conversation_group_statement ) ]

[ , TIMEOUT timeout ]

}

Przykład Procedura wykorzystująca lokalną zmienną, zatrzymująca realizację programu na określony czas. IF OBJECT_ID('dbo.TimeDelay_hh_mm_ss','P') IS NOT NULL

DROP PROCEDURE dbo.TimeDelay_hh_mm_ss;

GO

CREATE PROCEDURE dbo.TimeDelay_hh_mm_ss

(

@DelayLength CHAR(8)= '00:00:00'

)

AS

DECLARE @ReturnInfo VARCHAR(255)

IF ISDATE('2000-01-01 ' + @DelayLength + '.000') = 0

BEGIN

SELECT @ReturnInfo = 'Invalid time ' + @DelayLength

+ ',hh:mm:ss, submitted.';

-- Ten PRINT tylko dla testów

Page 36: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

36

PRINT @ReturnInfo

RETURN(1)

END

BEGIN

WAITFOR DELAY @DelayLength

SELECT @ReturnInfo = 'A total time of ' + @DelayLength +

', hh:mm:ss, has elapsed! Your time is up.'

-- ten PRINT tylko dla testów

PRINT @ReturnInfo;

END;

GO

-- Wywołanie procedury dbo.TimeDelay_hh_mm_ss, opóźnienie 10 s.

EXEC TimeDelay_hh_mm_ss '00:00:10';

GO

4.5. Kursory Wynikiem poleceń MS SQL Server w ogólnym przypadku jest tablica, jednak czasem pojawia się potrzeba przetwarzania pojedynczych wierszy tablicy wynikowej. Może to być zrealizowane za pomocą kursora. Z kursorami związane są polecenia:

DECLARE CURSOR OPEN FETCH CLOSE DEALLOCATE

4.5.1. Definiowanie (DECLARE CURSOR) Kursor jest definiowany poleceniem DECLARE CURSOR. Dopuszczalne są dwie składnie: standardowa i rozszerzona, ich elementów nie można mieszać ze sobą. SKŁADNIA -- Składnia ISO

DECLARE cursor_name [ INSENSITIVE ] [ SCROLL ] CURSOR

FOR select_statement

[ FOR { READ ONLY | UPDATE [ OF column_name [ ,...n ] ] } ]

[;]

-- Rozszerzona składnia Transact-SQL

DECLARE cursor_name CURSOR [ LOCAL | GLOBAL ]

[ FORWARD_ONLY | SCROLL ]

[ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ]

[ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ]

[ TYPE_WARNING ]

FOR select_statement

[ FOR UPDATE [ OF column_name [ ,...n ] ] ]

[;]

Wprowadzenie typu kursora SCROLL, umożliwia stosowanie w FETCH wszystkich opcji dostępu, w przeciwnym przypadku dostępna jest wyłącznie opcja NEXT. Po klauzuli FOR umieszczone jest wyrażenie select_statement, które definiuje dane zwracane przez kursor. Kursor może wykorzystywać funkcję CURSOR_STATUS, która zwraca wartości: 1 gdy wynikiem jest co najmniej jeden wiersz, 0 gdy wynik jest pusty, -1 gdy kursor jest zamknięty, -3 gdy nie ma kursora o podanej nazwie.

Przykład Kursor pobiera kolejne wiersze wybranych kolumn tabeli Teachers. Przed użyciem kursor musi być uaktywniony poleceniem OPEN. Przewijanie może się odbywać tylko do przodu. DECLARE c_teacher CURSOR

FOR SELECT TNo, TName FROM Teachers;

OPEN c_teacher

FETCH NEXT FROM c_teacher;

Page 37: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

37

4.5.2. Pobieranie danych (FETCH) Polecenie FETCH używane jest do pobrania z tablicy pojedynczego wiersza wskazywanego kursorem. SKŁADNIA FETCH

[[NEXT |PRIOR |FIRST |LAST |ABSOLUTE{n|@nvar} |RELATIVE{n|@nvar} ]

FROM ]

{{[GLOBAL ]cursor_name} @cursor_variable_name }

[ INTO @variable_name [ ,...n ] ]

Poszczególne kolumny z pobranego przez kursor wiersza mogą być podstawione na zmienne występujące na liście występującej po klauzuli INTO. Przydatne może być użycie zmiennej systemowej @@FETCH_STATUS, która (globalnie) zawiera informację o ostatnio realizowanym poleceniu FETCH. Zmienna przyjmuje wartość 0, gdy operacja zakończyła się pomyślnie, -1 gdy operacja nie została wykonana lub -2, gdy nie ma wiersza do pobrania.

4.6. Wyzwalacze (triggery) Microsoft SQL Server udostępnia wyzwalacze DML, wykonywane zarówno po, jak i zamiast instrukcji INSERT, UPDATE lub DELETE. Można definiować wyzwalacze dla tabel oraz widoków, z tym, że w przypadku widoków można stosować tylko wyzwalacz INSTEAD OF. Od wersji SQL Server 2005 wprowadzono wyzwalacze DDL, które są wykonywane w reakcji na bardzo szeroki zakres zdarzeń, takich jak DROP TABLE, CREATE TABLE, ALTER TABLE i inne. Wprowadzono również specjalne wyzwalacze reagujące na takie zdarzenia jak łączenie bądź rozłączanie się użytkownika z bazą danych. Z wyzwalaczami związane są polecenia:

CREATE TRIGGER ALTER TRIGGER DROP TRIGGER ENABLE TRIGGER DISABLE TRIGGER

4.6.1. Wyzwalacze DML SKŁADNIA CREATE TRIGGER [ schema_name . ]trigger_name

ON { table | view }

[ WITH <dml_trigger_option> [ ,...n ] ]

{ FOR | AFTER | INSTEAD OF }

{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] }

[ NOT FOR REPLICATION ]

AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME <method specifier [ ; ] > }

Wyzwalacze nie mogą dotyczyć tabel tymczasowych. Definicja wyzwalacza przechowywana jest wraz z definicją tabeli (w zakładce Triggers). Typ FOR | AFTER oznacza realizację procedury wyzwalacza po zrealizowaniu wszystkich czynności związanych z wyzwalającym poleceniem, natomiast typ INSTEAD OF oznacza zastąpienie polecenia wyzwalającego przez procedurę wyzwalacza. Takie wyzwalacze mają dodatkowe ograniczenia w przypadku tabel powiązanych z warunkami ON DELETE lub ON UPDATE w kluczach obcych. Parametr dml_trigger_option w opcjonalnej klauzuli WITH może przyjmować wartości ENCRYPTION (gdy chcemy ukryć tekst procedury) i EXECUTE AS {CALLER|SELF|OWNER|<user_name>} (dające możliwość identyfikacji użytkownika dla kontroli uprawnień). Po słowie kluczowym AS występuje ciało procedury wyzwalacza: zestaw dowolnych poleceń transact-SQL lub odwołanie do zewnętrznej metody z .NET Framework. Jeśli chcemy sprawdzić, czy zdarzenie UPDATE dotyczyło danej kolumny, możemy użyć funkcji logicznej UPDATE(<kolumna>). W przypadku testowania większej ilości wprowadzonych zmian, wygodna może być funkcja COLUMNS_UPDATED, zwracająca binarnie informacje o zmienionych kolumnach (1 - była zmiana, 0 - nie).

Przykład Po wprowadzeniu zmian w kolumnie TITLE w tabeli Teachers pojawi się przypomnienie o potrzebie kontaktu z Dziekanatem: USE School2;

GO

IF OBJECT_ID ('remainder', 'TR') IS NOT NULL

DROP TRIGGER remainder;

GO

Page 38: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

38

CREATE TRIGGER remainder

ON Teachers

AFTER UPDATE

AS IF UPDATE('TITLE') RAISERROR ('Notify Dean''s Bureau', 16, 10);

GO

Wyzwalacze DML wykonują swoje działania korzystając z dostępu do logicznych (pojęciowych) tabel inserted i deleted, posiadających strukturę zgodną z tablicą dla której był definiowany wyzwalacz. Przykładowo, chcąc uzyskać listę usuniętych rekordów, należy wykonać polecenie SELECT * FROM Deleted; Dzięki wyzwalaczom DML można poszerzyć integralność referencyjną bazy danych, testować wystąpienie błędów i realizować akcje naprawcze, porównywać stany tabeli przed i po transakcji i odpowiednio zareagować na występujące różnice.

Przykład Przy wprowadzaniu nowego zamówienia sprawdzamy, czy klient nie jest w grupie dłużników. W tym celu porównujemy dane z wprowadzonego zamówienia (tablica Inserted połączona z PurchaseOrderHeader) z tablicą takich klientów (tablica Vendor z warunkiem CreditRanking = 5); USE AdventureWorks2008;

GO

IF OBJECT_ID ('LowCredit','TR') IS NOT NULL

DROP TRIGGER LowCredit;

GO

CREATE TRIGGER LowCredit ON PurchaseOrderHeader

AFTER INSERT

AS

IF EXISTS (SELECT *

FROM PurchaseOrderHeader p

JOIN Inserted AS i

ON p.PurchaseOrderID = i.PurchaseOrderID

JOIN Vendor AS v

ON v.BusinessEntityID = p.VendorID

WHERE v.CreditRating = 5

)

BEGIN

RAISERROR ('A vendor''s credit rating is too low.', 16, 1);

ROLLBACK TRANSACTION;

RETURN

END;

GO

4.6.2. Wyzwalacze DDL SKŁADNIA CREATE TRIGGER trigger_name

ON { ALL SERVER | DATABASE }

[ WITH <ddl_trigger_option> [ ,...n ] ]

{ FOR | AFTER } { event_type | event_group } [ ,...n ]

AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME < method specifier > [ ; ] }

Wyzwalacz DDL jest uruchamiany po wystąpieniu zdarzenia wywołującego (AFTER, nie ma opcji INSTEAD OF). Przykładowo wyzwalacz DDL może być uruchomiony przez zdarzenie ALTER SERVER CONFIGURATION lub np. gdy usuwana jest tablica za pomocą DROP TABLE. Nie są tworzone tabele inserted ani deleted. Informacja na temat zdarzenia i wywołanych zmian może być uzyskana za pomocą funkcji EVENTDATA, zwracającej strukturę XML zawierającą informację o czasie zdarzenia, identyfikatorze procesu połączenia oraz typie zdarzenia wywołującego wyzwalacz. Każdemu zdarzeniu DDL można przypisać wiele wyzwalaczy. Jest możliwe określenie który z nich ma być realizowany jako pierwszy bądź ostatni.

Page 39: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

39

4.6.3. Wyzwalacze logowania SKŁADNIA CREATE TRIGGER trigger_name

ON ALL SERVER

[ WITH <logon_trigger_option> [ ,...n ] ]

{ FOR| AFTER } LOGON

AS { sql_statement [ ; ] [ ,...n ] | EXTERNAL NAME < method specifier > [ ; ] }

Przykład Wyzwalacz logowania pozwala cofnąć (ROLLBACK) operację logowania np. przy ograniczeniu ilości logowań z wykorzystaniem tymczasowego hasła. USE master;

GO

CREATE LOGIN login_test WITH PASSWORD = '3KHJ6dhx(0xVYsdf' MUST_CHANGE,

CHECK_EXPIRATION = ON;

GO

GRANT VIEW SERVER STATE TO login_test;

GO

CREATE TRIGGER connection_limit_trigger

ON ALL SERVER WITH EXECUTE AS 'login_test'

FOR LOGON

AS

BEGIN

IF ORIGINAL_LOGIN()= 'login_test' AND

(SELECT COUNT(*) FROM sys.dm_exec_sessions

WHERE is_user_process = 1 AND

original_login_name = 'login_test') > 3

ROLLBACK;

END;

4.7. Funkcje wbudowane W Transact-SQL dostępne są następujące typy funkcji wbudowanych:

Rowset functions Aggregate functions (często używane z klauzulą GROUP BY polecenia SELECT):

o AVG o MIN o CHECKSUM_AGG o OVER Clause o COUNT o COUNT_BIG o STDEV o GROUPING o STDEVP o GROUPING_ID o SUM o MAX o VAR o VARP

Ranking functions Scalar functions, które można podzielić na kategorie:

o Configuration functions (zwracają informacje o aktualnej konfiguracji). o Cryptographic functions (obsługują kodowanie, dekodowanie oraz podpisy cyfrowe i ich

sprawdzanie. o Cursor functions (zwracają informacje o kursorach). o Data Type functions (zwracają informacje o wartości autoinkrementacji i innych typach danych). o Date and Time Data Types and Functions (wykonują operacje na danych daty i czasu i zwracają

dane w postaci ciągu znaków, liczby lub zmiennej typu daty i czasu). o Mathematical functions (wykonują obliczenia na podstawie argumentów wejściowych i zwracają

wartości numeryczne). o Metadata functions (zwracają informacje o bazie danych i jej obiektach).

Page 40: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

40

o ODBC Scalar functions. o Replication functions o Security functions (zwracają informacje o użytkownikach i rolach). o String functions (wykonują operacje na ciągach znaków (char, varchar) i zwracają ciągi znaków lub

wartości numeryczne). o System functions (wykonują operacje i zwracają informacje o wartościach, obiektach i ustawieniach

w SQL Server). o System Statistical functions (zwracają informacje statystyczne o systemie). o Text and Image functions (wykonują operacje na tekstach, obrazach lub kolumnach). o Trigger functions (zwracają informacje o wyzwalaczach).

Funkcje wbudowane mogą być deterministyczne (zawsze zwracające ten sam wynik przy tych samych argumentach wejściowych) bądź niedeterministyczne.

4.8. Transakcje Transakcja jest pojedynczym, niepodzielnym zadaniem wykonywanym na bazie danych. Jeżeli transakcja przebiegła pomyślnie, wszystkie modyfikacje danych przeprowadzone podczas jej trwania są zatwierdzone i trwale wprowadzone do bazy danych. Jeżeli podczas wykonywania transakcji wystąpi błąd i transakcja musi być przerwana lub wycofana, to wszelkie wprowadzone zmiany są usuwane. SQL Server wykorzystuje następujące typy transakcji: Transakcje zatwierdzane automatycznie (autocommit transactions) - każde indywidualne polecenie w języku

Transact-SQL jest transakcją. Transakcje sprecyzowane (explicit transactions) - każda transakcja rozpoczyna się od polecenia BEGIN

TRANSACTION i kończy poleceniem COMMIT lub ROLLBACK. Transakcje domyślne (implicit transactions) - nowa transakcja domyślnie rozpoczyna się po zakończeniu

poprzedniej transakcji, ale każda jest w sposób jawny zamykana poleceniem COMMIT lub ROLLBACK. Transakcje wsadowe (batch-scoped transactions) - występują w przypadku tzw. multiple active result sets

umożliwiając jednoczesne przetwarzanie kilku zadań wsadowych. W takim przypadku transakcja, która nie jest zamknięta przez COMMIT lub ROLLBACK wewnątrz wsadu, jest automatycznie wycofywana (ROLLBACK) po jego zakończeniu.

Transakcja, jako sekwencja operacji wykonywanych jako pojedyncze zadanie, musi posiadać cztery właściwości: niepodzielność, spójność, odrębność i trwałość (ACID - atomicity, consistency, isolation, durability). Atomicity albo wszystkie operacje w ramach transakcji są wykonane poprawnie, albo wszystkie zmiany

zostaną wycofane. Użytkownik nie musi się martwić o wyniki niedokończonych transakcji. Consistency po zakończeniu transakcji, baza danych musi się znajdować w stanie spójnym. Muszą być

zastosowane wszystkie zasady kontroli integralności danych. Wszystkie struktury wewnętrzne bazy, jak indeksy, listy muszą być zaktualizowane przy zakończeniu transakcji.

Isolation modyfikacje wprowadzone przez równolegle przeprowadzane transakcje muszą być od siebie odizolowane. Transakcja używa danych ze stanu, jaki był przed rozpoczęciem równoległej transakcji, albo stanu, który nastąpił po jej zakończeniu, nie używa stanów przejściowych. Nazywane jest to szeregowaniem transakcji (serializability) ponieważ skutkuje to wykonaniem ciągu transakcji na kolejnych stanach danych.

Durability kiedy transakcja jest ukończona, jej efekty są na trwale umieszczane w bazie danych. Modyfikacje powinny przetrwać nawet upadek systemu.

W celu zapewnienia tych warunków, DBMS powinien zapewnić możliwość: Blokowania (locking), dla zapewnienia odrębności transakcji. Notowania (logging), dla zapewnienia trwałości transakcji. Nawet jeśli sprzęt, system operacyjny lub DBMS

ulegną awarii, to dzięki dziennikom, po restarcie niezakończone transakcje ulegną automatycznemu wycofaniu do stanu sprzed awarii.

Zarządzania (transaction management), która wymusza niepodzielność i spójność transakcji. Po rozpoczęciu transakcji musi być ona zakończona pomyślnie, w przeciwnym przypadku DBMS ma wycofać wszystkie wprowadzone modyfikacje danych.

4.8.1. Poziomy izolacji transakcji w SQL-92 Chociaż szeregowanie transakcji daje pewność, że dane w bazie są aktualne przez cały czas, to wiele transakcji nie przez cały czas wymaga stosowania pełnej izolacji. Weźmy przykład: wielu autorów pracuje jednocześnie nad różnymi rozdziałami tej samej książki. Nowe rozdziały mogą być włączane do projektu w dowolnym momencie. Jednakże kiedy rozdział został już wykończony, autor nie może dokonywać żadnych zmian bez akceptacji wydawcy. W ten sposób wydawca może mieć pewność aktualności projektu książki, bez względu na dostarczanie nowych, niewykończonych rozdziałów. Wydawca ma dostęp zarówno do rozdziałów wykończonych, jak i do dosłanych ostatnio.

Page 41: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

41

Poziom, na jakim transakcja jest przygotowana do przyjmowania niespójnych danych jest określany jako poziom izolacji. Poziom izolacji określa do jakiego stopnia transakcja musi być izolowana od innych transakcji. Mniejszy poziom izolacji zwiększa możliwości jednoczesnego wykonywania transakcji kosztem poprawności danych. I przeciwnie – wysoki poziom izolacji zapewnia dużą poprawność danych ale negatywnie wpływa na możliwości równoczesnego przetwarzania. Poziom izolacji wymagany przez aplikację określa zastosowane przez SQL Server zachowanie blokujące. SQL-92 definiuje następujące poziomy izolacji, wszystkie dostępne w SQL Server.

Read uncommitted (poziom najniższy, w którym transakcje są izolowane tylko na tyle, aby zapewnić, że dane fizycznie niepoprawne nie będą czytane).

Read committed (domyślny poziom w SQL). Repeatable read (domyślny w MS SQL) Serializable (poziom najwyższy, w którym transakcje są w pełni odizolowane od siebie).

Poziom serializable przeprowadzania transakcji zapewnia, że wszystkie równolegle występujące, nakładające się na siebie transakcje zostaną uszeregowane. Pośrednie poziomy izolacji zapewniają różne sposoby reakcji na zjawiska izolacji.

Poziom izolacji Lost update Dirty read Nonrepeatable read

Phantom rows

Read uncommitted

No Yes Yes Yes

Read committed No No Yes Yes

Repeatable read No No No Yes

Serializable No No No No

Transakcja musi być izolowana na poziomie repeatable read lub wyższym aby zapobiec utracie zmian, które mogą nastąpić, kiedy dwie transakcje jednocześnie sięgają do tego samego rekordu danych a następnie zmieniają ten rekord bazując na wartościach oryginalnych. Jeżeli te dwie transakcje modyfikują dane za pomocą pojedynczego polecenia UPDATE i nie opierają się na uprzednio uzyskanych wartościach, już na poziomie izolacji read committed nie powinna nastąpić utrata wprowadzonych zmian (lost update). Izolacja odbywa się przez ustawianie blokady pojedynczych rekordów bazy danych na poziomie odczytu (read lock), zapisu (write lock) i blokady zakresu danych (range lock).

Poziom izolacji Range lock Read lock Write lock

Read uncommitted

No No No

Read committed No No Yes

Repeatable read No Yes Yes

Serializable Yes Yes Yes

4.8.2. Polecenia związane z transakcjami

SET TRANSACTION ISOLATION LEVEL

Ustalenie poziomu izolacji. MS SQL Server wprowadza dodatkowy sposób izolacji (snapshot), w którym dane czytane przez dowolne polecenie są transakcyjnie spójną wersją danych występujących przy starcie transakcji. Izolacja sposobem snapshot nie używa blokady rekordów ale ich wersjonowania. Może współpracować z poziomem izolacji read committed po ustawieniu opcji READ_COMMITTED_SNAPSHOT.

SKŁADNIA

SET TRANSACTION ISOLATION LEVEL

{ READ UNCOMMITTED

| READ COMMITTED

| REPEATABLE READ

| SNAPSHOT

| SERIALIZABLE

Page 42: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

42

}

[ ; ]

BEGIN TRANSACTION

Oznaczenie punktu startowego lokalnej transakcji. Licznik transakcji (@@TRANSCOUNT) jest zwiększany o 1. Na potrzeby transakcji zostają zablokowane różne zasoby bazy danych, w zależności od poziomu izolacji. W logu transakcyjnym notowane są jedynie te polecenia, które spowodowały modyfikację danych. Np. polecenie SELECT, użyte jedynie do wyświetlenia danych, może potrzebować blokady, ale nie musi być tam notowane. Klauzula WITH MARK służy do umieszczania nazwy transakcji i ewentualnych komentarzy w logu transakcyjnym.

SKŁADNIA

BEGIN {TRAN|TRANSACTION} [

{transaction_name|@tran_name_variable} [WITH MARK ['description']]

]

[ ; ]

COMMIT TRANSACTION

Oznaczenie punktu końcowego transakcji określonej lub domyślnej. Licznik transakcji (@@TRANSCOUNT) jest zmniejszany o 1. Jeśli się wyzeruje, to zmiany zostają utrwalone w bazie danych. Jeśli nie (transakcja zagnieżdżona), to transakcja pozostaje aktywna, a zasoby nie zostaną zwolnione. COMMIT [WORK] działa identycznie, ale nie dopuszcza nazwy transakcji.

SKŁADNIA

COMMIT {TRAN|TRANSACTION} [transaction_name|@tran_name_variable]

[ ; ]

ROLLBACK TRANSACTION

Wycofanie transakcji określonej lub domyślnej do początku lub do punktu przywracania wewnątrz transakcji. Jeśli został określony punkt powrotu, to licznik transakcji (@@TRANSCOUNT) pozostaje bez zmian. W przeciwnym przypadku licznik transakcji zostaje wyzerowany, a zasoby zostają zwolnione. Przy transakcjach zagnieżdżonych następuje powrót do początku transakcji zewnętrznej. Podobne jest działanie ROLLBACK [WORK], ale nie dopuszcza nazwy transakcji ani punktu przywracania.

SKŁADNIA

ROLLBACK {TRAN|TRANSACTION}

[transaction_name|@tran_name_variable|savepoint_name|@savepoint_variable]

[ ; ]

SAVE TRANSACTION

Polecenie to ma zastosowanie w procedurach składowych. Użytkownik może określić punkt przywracania (lub znacznik) wewnątrz transakcji, tzn. punkt do którego transakcja może być wycofana, jeżeli jej część zostanie odrzucona na skutek zaistniałych warunków (np. wystąpienia błędu). Zasoby wykorzystywane przez transakcję będą nadal blokowane. Dalsze działanie może polegać na kontynuacji transakcji, aż do osiągnięcia COMMIT TRANSACTION, lub do wycofania do początku transakcji.

SKŁADNIA

SAVE {TRAN|TRANSACTION} {savepoint_name|@savepoint_variable}

[ ; ]

Przykład Przykład użycia punktu przywracania dla wycofania modyfikacji wprowadzonych przez procedurę Example, jeżeli aktywna transakcja wystartowała przed jej uruchomieniem.

USE School2

GO

IF OBJECT_ID('Example','P') IS NOT NULL

DROP PROCEDURE Example;

GO

-- Definicja procedury musi być na początku wsadu

CREATE PROCEDURE Example

@InputTeacherId CHAR(3)

AS

DECLARE @TranCnt INT;

SET @TranCnt = @@TRANCOUNT;

-- @TranCnt = 0 - nie było aktywnej transakcji

Page 43: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

43

IF @TranCnt > 0

-- Była rozpoczęta transakcja, ustaw punkt powrotu

SAVE TRANSACTION SavePoint;

ELSE

-- Nie było transakcji - utwórz własną transakcję

BEGIN TRANSACTION;

BEGIN TRY

-- Blok wykonawczy procedury

INSERT INTO Teachers VALUES

('@@','Kowalski','Mgr inż.','Gdańsk','T4');

UPDATE Teachers

SET TNo = @InputTeacherId

WHERE TNo = '@@';

-- Jeśli nie było błędów i istnieje własna transakcja

IF @TranCnt = 0

-- Trzeba zatwierdzić własną transakcję

COMMIT TRANSACTION;

END TRY

BEGIN CATCH

-- Blok obsługi błędów

IF @TranCnt = 0

-- Transakcja własna - wycofać zmiany

ROLLBACK TRANSACTION

ELSE

-- Transakcja wystartowała przed procedurą, sprawdź jej stan

-- XACT_STATE() = 1 - transakcja może być zakończona

-- XACT_STATE() = 0 - nie ma aktywnej transakcji

-- XACT_STATE() =-1 - transakcja nie może być zakończona

IF XACT_STATE() <> -1

-- Transakcja jest ważna - cofnij do punktu powrotu

ROLLBACK TRANSACTION SavePoint;

-- Nie można było zakończyć - wyślij tylko komunikat o błędzie

DECLARE @ErrorMessage NVARCHAR(4000);

DECLARE @ErrorSeverity INT;

DECLARE @ErrorState INT;

SELECT @ErrorMessage = ERROR_MESSAGE();

SELECT @ErrorSeverity = ERROR_SEVERITY();

SELECT @ErrorState = ERROR_STATE();

RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);

END CATCH

GO

-- Wykonanie

USE School2

GO

DECLARE @Tid AS CHAR(3);

SELECT @Tid = 'T6';

BEGIN TRANSACTION

INSERT INTO Teachers VALUES

(@Tid,'Kowalski','BSc','Gdańsk','T3');

SELECT * FROM Teachers;

-- Wywołanie procedury Example z argumentem @Tid = 'T6'’

EXEC Example @Tid; -- Będzie błąd w UPDATE, bo T6 już istnieje

COMMIT TRANSACTION

SELECT * FROM Teachers; -- Rekord T6 wprowadzony

DELETE Teachers WHERE TNo = @Tid

GO

4.8.3. Transakcje automatyczne Jest to domyślny sposób zarządzania transakcjami w SQL-Server. Każde polecenie jest zatwierdzone (commited), jeśli zakończyło się powodzeniem, lub wycofane (rolled back), jeśli wystąpił jakiś błąd. Połączenie z serwerem domyślnie pracuje w trybie autocommit. Po wystąpieniu polecenia BEGIN TRANSACTION, następuje przełączenie do trybu explicit transaction. Powrót do trybu autocommit następuje po zakończeniu transakcji (COMMIT

Page 44: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

44

TRANSACTION lub ROLLBACK TRANSACTION) w trybie explicit. Przełączenie z autocommit do trybu implicit transation następuje po wystąpieniu polecenia SET IMPLICIT_TRANSACTIONS ON, a powrót do trybu autocommit po poleceniu SET IMPLICIT_TRANSACTIONS OFF. Jeśli w trybie autocommit wystąpi błąd kompilacji (compile error), to wycofywany jest cały wsad (do instrukcji GO), a nie pojedyncze polecenie SQL. Przy wystąpieniu błędu wykonania (runtime error) wycofywany jest jedynie wynik błędnego polecenia.

Przykłady Wystąpienie błędu kompilacji: IF OBJECT_ID ('TestBatch', 'U') IS NOT NULL

DROP TABLE TestBatch;

CREATE TABLE TestBatch (ID INT PRIMARY KEY, Data CHAR(3));

GO

INSERT INTO TestBatch VALUES (1, 'aaa');

INSERT INTO TestBatch VALUES (2, 'bbb');

INSERT INTO TestBatch VALUSE (3, 'ccc'); -- Błąd składni.

GO

SELECT * FROM TestBatch; -- Zwróci 0 wierszy.

GO

Wystąpienie błędu wykonania: IF OBJECT_ID ('TestBatch', 'U') IS NOT NULL

DROP TABLE TestBatch;

CREATE TABLE TestBatch (Kol1 INT PRIMARY KEY, Kol2 CHAR(3));

GO

INSERT INTO TestBatch VALUES (1, 'aaa');

INSERT INTO TestBatch VALUES (2, 'bbb');

INSERT INTO TestBatch VALUES (1, 'ccc'); -- Powtórzenie wartości klucza.

GO

SELECT * FROM TestBatch; -- Zwróci wiersz 1 i 2.

GO

DBMS w SQL-Server nie sprawdza nazw obiektów w trakcie kompilacji, zatem błąd w nazwie traktowany jest jako błąd wykonania: IF OBJECT_ID ('TestBatch', 'U') IS NOT NULL

DROP TABLE TestBatch;

CREATE TABLE TestBatch (Kol1 INT PRIMARY KEY, Kol2 CHAR(3));

GO

INSERT INTO TestBatch VALUES (1, 'aaa');

INSERT INTO TestBatch VALUES (2, 'bbb');

INSERT INTO TestBtch VALUES (3, 'ccc'); -- Błąd w nazwie tablicy

SELECT * FROM TestBatch; -- Zwróci wiersz 1 i 2.

GO

4.8.4. Transakcje sprecyzowane (explicite) Są to transakcje w sposób jawny zdefiniowane od początku do końca. Skrypty Transact_SQL wykorzystują w tym celu następujące polecenia: BEGIN TRANSACTION – używane do oznaczenia punktu startowego transakcji dla aktywnego połączenia. COMMIT TRANSACTION lub COMMIT WORK - używa się do pomyślnego zakończenia transakcji, jeżeli nie wystąpiły

żadne błędy. Wprowadzone zmiany zostają utrwalone w bazie danych. Zasoby używane przez transakcję zostają zwolnione.

ROLLBACK TRANSACTION lub ROLLBACK WORK - używa się do wycofania transakcji, w której wystąpiły błędy. Wszystkie dane zmodyfikowane podczas transakcji, powracają do stanu sprzed rozpoczęcia transakcji. Zasoby używane przez transakcję zostają zwolnione.

Przykłady Zadeklarowanie transakcji i nadanie jej nazwy "TeacherDelete" oraz potwierdzenie po pomyślnym wykonaniu. USE School2;

BEGIN TRANSACTION TeacherDelete

WITH MARK N'Deleting a Job Candidate';

GO

DELETE FROM Teachers

Page 45: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

45

WHERE TNo = 'T7';

GO

COMMIT TRANSACTION TeacherDelete;

GO

Zadeklarowanie transakcji z nazwą w postaci zmiennej, wprowadzenie dwóch wierszy a następnie wycofanie tej transakcji. IF OBJECT_ID('ExplicitTran', 'U') IS NOT NULL

DROP TABLE ExplicitTran;

CREATE TABLE ExplicitTran (

ID INT PRIMARY KEY IDENTITY,

Data CHAR(3) NOT NULL);

GO

DECLARE @TranName VARCHAR(20);

SELECT @TranName = 'MyTransaction';

BEGIN TRAN @TranName;

-- Rozpoczęcie trybu EXPLICITE

INSERT INTO ExplicitTran VALUES('aaa');

SAVE TRAN S1 -- Wstawienie punktu powrotu

INSERT INTO ExplicitTran VALUES('bbb');

SELECT * FROM ExplicitTran; -- Dwa wiersze: (1,aaa)(2,bbb)

ROLLBACK TRAN S1; -- Wycofanie transakcji do punktu S1

INSERT INTO ExplicitTran VALUES('BBB');

COMMIT WORK -- Zakończenie transakcji

-- Wznowienie trybu AUTOCOMMIT

INSERT INTO ExplicitTran VALUES('AAA');

SELECT * FROM ExplicitTran -- Trzy wiersze: (1,aaa)(3,BBB)(4,AAA)

DROP TABLE ExplicitTran

4.8.5. Transakcje domyślne (implicite) Wprowadzenie połączenia w tryb domniemanych transakcji odbywa się za pomocą polecenia: SET IMPLICIT_TRANSACTIONS ON lub przez funkcje i metody API bazy danych. Kiedy połączenie pracuje w tym trybie, nie jest wymagana oddzielna sygnalizacja rozpoczęcia nowej transakcji. DBMS automatycznie rozpoczyna nową transakcję po wykryciu jednego z poleceń:

ALTER TABLE CREATE DELETE DROP FETCH GRANT INSERT OPEN REVOKE SELECT TRUNCATE TABLE UPDATE

Transakcja jest kontynuowana aż do wystąpienia polecenia COMMIT lub ROLLBACK. Odwołanie tego trybu (przejście do transakcji automatycznych) odbywa się za pomocą polecenia: SET IMPLICIT_TRANSACTIONS OFF

Przykład SET QUOTED_IDENTIFIER OFF;

GO

SET NOCOUNT OFF;

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

SET IMPLICIT_TRANSACTIONS OFF;

GO

-- Tryb AUTOCOMMIT

USE School2

IF OBJECT_ID('ImplicitTran', 'U') IS NOT NULL

DROP TABLE ImplicitTran;

Page 46: BAZY DANYCH - pg.edu.pl · MS SQL Server pozwala na utworzenie tablic tymczasowych, które są automatycznie usuwane po zakończeniu ich używania bądź po zakończeniu sesji. Nazwa

46

CREATE TABLE ImplicitTran (

Id INT IDENTITY PRIMARY KEY,

Data CHAR(5) NOT NULL);

GO

-- Początek trybu IMPLICITE

SET IMPLICIT_TRANSACTIONS ON;

-- Pierwszą transakcję rozpoczyna INSERT

INSERT INTO ImplicitTran VALUES ('aaa');

INSERT INTO ImplicitTran VALUES ('bbb');

SELECT * FROM ImplicitTran;

ROLLBACK TRANSACTION -- Koniec transakcji

-- Drugą transakcję rozpoczyna SELECT

SELECT * FROM ImplicitTran;

INSERT INTO ImplicitTran VALUES ('BBB');

INSERT INTO ImplicitTran VALUES ('AAA');

COMMIT TRANSACTION -- Koniec transakcji (tu zbędny)

-- Koniec trybu IMPLICITE (i jednocześnie koniec transakcji)

SET IMPLICIT_TRANSACTIONS OFF;

-- Początek trybu AUTOCOMMIT – każde polecenie jest transakcją

SELECT * FROM ImplicitTran;

GO