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



Podobne dokumenty
Paweł Rajba

Systemy GIS Tworzenie zapytań w bazach danych

Podstawy języka T-SQL : Microsoft SQL Server 2016 i Azure SQL Database / Itzik Ben-Gan. Warszawa, Spis treści

Microsoft SQL Server Podstawy T-SQL

Tworzenie tabel. Bazy danych - laboratorium, Hanna Kleban 1

Przestrzenne bazy danych Podstawy języka SQL

LAB 3 (część 1 Projektu)

Blaski i cienie wyzwalaczy w relacyjnych bazach danych. Mgr inż. Andrzej Ptasznik

Administracja i programowanie pod Microsoft SQL Server 2000

Podstawy języka SQL. SQL Structured Query Languagestrukturalny

SELECT * FROM tabela WHERE warunek wybiera dane spełniające podany warunek

Wykład 5. SQL praca z tabelami 2

SQL Server i T-SQL w mgnieniu oka : opanuj język zapytań w 10 minut dziennie / Ben Forta. Gliwice, Spis treści

SQL (ang. Structured Query Language)

Relacyjne bazy danych. Podstawy SQL

Aspekty aktywne baz danych

Bazy danych. Bazy danych. Podstawy języka SQL. Dr inż. Paweł Kasprowski.

Autor: Joanna Karwowska

Wykład 8. SQL praca z tabelami 5

1 DML - zapytania, część II Grupowanie Operatory zbiorowe DML - modyfikacja 7. 3 DCL - sterowanie danymi 9.

Podstawy języka SQL. standardy SQL formułowanie zapytań operacje na strukturach danych manipulowanie danymi. Bazy danych s.5-1

Wykład 6. SQL praca z tabelami 3

SQL w praktyce. Miłej i owocnej nauki!!!

Program szkoleniowy Efektywni50+ Moduł IV Podstawy relacyjnych baz danych i język SQL

DECLARE VARIABLE zmienna1 typ danych; BEGIN

LAB 6 BEGIN TRANSACTION, COMMIT, ROLLBACK, SET TRANSACTION ISOLATION LEVEL,

Wstęp 5 Rozdział 1. Podstawy relacyjnych baz danych 9

Wprowadzenie do BD Operacje na bazie i tabelach Co poza zapytaniami? Algebra relacji. Bazy Danych i Systemy informacyjne Wykład 2.

Bazy danych Ćwiczenia projektowe

Ref. 7 - Język SQL - polecenia DDL i DML

Język SQL podstawy zapytań

W SQL Serwerze 2008 wprowadzono parametry tablicowe (Table Valued Parameters - TVP).

Konstruowanie Baz Danych SQL UNION, INTERSECT, EXCEPT

Instrukcja podwaja zarobki osób, których imiona zaczynają się P i dalsze litery alfabetu zakładamy, że takich osbób jest kilkanaście.

Język SQL. Rozdział 9. Język definiowania danych DDL, część 2.

Relacyjne bazy danych. Podstawy SQL

D D L S Q L. Co to jest DDL SQL i jakie s jego ą podstawowe polecenia?

Bazy danych 10. SQL Widoki

Fizyczna struktura bazy danych w SQL Serwerze

Wyzwalacz - procedura wyzwalana, składowana fizycznie w bazie, uruchamiana automatycznie po nastąpieniu określonego w definicji zdarzenia

3. Podzapytania, łączenie tabel i zapytań

Przykłady najlepiej wykonywać od razu na bazie i eksperymentować z nimi.

T-SQL dla każdego / Alison Balter. Gliwice, cop Spis treści. O autorce 11. Dedykacja 12. Podziękowania 12. Wstęp 15

050 SQL ELEMENTY ZAAWANSOWANE. Prof. dr hab. Marek Wisła

Tworzenie zapytań do Microsoft SQL Server

Języki programowania wysokiego poziomu. PHP cz.4. Bazy danych

Szkolenie Oracle SQL podstawy. Terminy lutego 2010 First Minute! 1100zł!

040 STRUCTURED QUERY LANGUAGE. Prof. dr hab. Marek Wisła

Oracle11g: Wprowadzenie do SQL

77. Modelowanie bazy danych rodzaje połączeń relacyjnych, pojęcie klucza obcego.

Programowanie w SQL procedury i funkcje. UWAGA: Proszę nie zapominać o prefiksowaniu nazw obiektów ciągiem [OLIMP\{nr indeksu}] Funkcje użytkownika

Procedury wyzwalane. (c) Instytut Informatyki Politechniki Poznańskiej 1

Hurtownia Świętego Mikołaja projekt bazy danych

E.14 Bazy Danych cz. 18 SQL Funkcje, procedury składowane i wyzwalacze

SQL DDL DML TECHNOLOGIE BAZ DANYCH. Wykład 5: Język DDL i DML. Małgorzata Krętowska

Instrukcja CREATE TABLE

Wykład 5 funkcje i procedury pamiętane widoki (perspektywy) wyzwalacze

Bazy danych 7. SQL podstawy

3 Przygotowali: mgr inż. Barbara Łukawska, mgr inż. Maciej Lasota

Integralność danych Wersje języka SQL Klauzula SELECT i JOIN

PRZESTRZENNE BAZY DANYCH WYKŁAD 2

Bazy danych. Dr inż. Paweł Kasprowski

BAZY DANYCH wprowadzenie do języka SQL. Opracował: dr inż. Piotr Suchomski

Informatyka sem. III studia inżynierskie Transport 2018/19 LAB 2. Lab Backup bazy danych. Tworzenie kopii (backup) bazy danych

Bazy Danych - Instrukcja do Ćwiczenia laboratoryjnego nr 8

Oracle PL/SQL. Paweł Rajba.

Autor: Joanna Karwowska

Administracja i programowanie pod Microsoft SQL Server 2000

Język SQL Złączenia. Laboratorium. Akademia Morska w Gdyni

Informatyka (5) SQL. dr inż. Katarzyna Palikowska Katedra Transportu Szynowego p. 4 Hydro

Język DML. Instrukcje DML w różnych implementacjach SQL są bardzo podobne. Podstawowymi instrukcjami DML są: SELECT INSERT UPDATE DELETE

strukturalny język zapytań używany do tworzenia i modyfikowania baz danych oraz do umieszczania i pobierania danych z baz danych

Wprowadzenie do projektowania i wykorzystania baz danych Relacje

opisuje nazwy kolumn, wyrażenia arytmetyczne, funkcje nazwy tabel lub widoków warunek (wybieranie wierszy)

Lab.8: Podstawy języka SQL.

Wykład 4. SQL praca z tabelami 1

Projekt jest finansowany ze środków Unii Europejskiej, Europejskiego Funduszu Społecznego i budŝetu państwa. Studia Podyplomowe dla Nauczycieli

Podyplomowe Studia Systemy informatyczne w logistyce

41. Zmienne lokalne muszą mieć nazwę, którą poprzedza (maksymalnie 128 znaków) oraz typ (każdy z wyjątkiem: text, ntext oraz image)

Ćwiczenia laboratoryjne nr 11 Bazy danych i SQL.

Bazy danych. dr inż. Arkadiusz Mirakowski

Plan bazy: Kod zakładający bazę danych: DROP TABLE noclegi CASCADE; CREATE TABLE noclegi( id_noclegu SERIAL NOT NULL,

Wykład 2. SQL 1 Structured Query Lenguage

Język SQL, zajęcia nr 1

Składowane procedury i funkcje

Szkolenie autoryzowane. MS Tworzenie zapytań do Microsoft SQL Server Strona szkolenia Terminy szkolenia Rejestracja na szkolenie Promocje

Współczesne systemy baz danych

Administracja i programowanie pod Microsoft SQL Server 2000

Bazy danych Ćwiczenia projektowe

- język zapytań służący do zapisywania wyrażeń relacji, modyfikacji relacji, tworzenia relacji

Wykład 05 Bazy danych

Wyzwalacze. do automatycznego generowania wartości kluczy głównych. Składnia instrukcji tworzacej wyzwalacz

Tworzenie baz danych i tabel

Bazy danych Język SQL część 2 Wykład dla studentów matem

Bloki anonimowe w PL/SQL

Język SQL. instrukcja laboratoryjna. Politechnika Śląska Instytut Informatyki. laboratorium Bazy Danych

SQL 4 Structured Query Lenguage

Współczesne systemy baz danych

Transkrypt:

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

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 2

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 -2 63 (-9 223 372 036 854,775 808) do 2 63-1 (9 223 372 036 854 775 807) 8 INTEGER -2 31 (-2 147 483 648) do 2 31-1 (2 147 483 647) 4 SMALLINT -2 15 (-32 768) do 2 15-1 (32 767) 2 TINYINT 0 do 2 8-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, dec[(m[, n])]. m - łączna ilość cyfr (1 m 38), NUMERIC 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 2 31-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; 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)); DECLARE @next_t AS PRSN; INSERT @next_t SELECT 89032004091,'Adamski'; SELECT * FROM @next_t; 3

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: 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: <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. 4

Każda z kolumn może również mieć zdefiniowane ograniczenia: <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. < 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)); 5

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; EXEC Test 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; CREATE PROCEDURE Test1 AS CREATE TABLE #t (x INT PRIMARY KEY); INSERT INTO #t VALUES (1); SELECT TestCol1 = X FROM #t; EXEC Test2 CREATE TABLE #t (x INT PRIMARY KEY); INSERT INTO #t VALUES (9); EXEC Test1 SELECT TestCol = X FROM #t; Wynik: (1 row(s) affected) TestCol1 1 1 6

(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); SELECT Id = OBJECT_ID('tempdb..#t','U'); SELECT Id = OBJECT_ID('#t','U'); 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 7

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. 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>) [ ; ] 8

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) ; ALTER TABLE dbo.test ADD column_b VARCHAR(20) NULL ; EXEC sp_help TEST; DROP TABLE dbo.test; -- Dokumentacja tabeli TEST Usuwanie kolumny CREATE TABLE dbo.test (column_a INT, column_b VARCHAR(20) NULL) ; ALTER TABLE dbo.test DROP COLUMN column_b ; DROP TABLE dbo.test; Zmiana typu danych w kolumnie CREATE TABLE dbo.test (column_a INT ) ; INSERT INTO dbo.test (column_a) VALUES (10) ; ALTER TABLE dbo.test ALTER COLUMN column_a DECIMAL (5, 2) ; DROP TABLE dbo.test; Dodawanie kolumny z ograniczeniami CREATE TABLE dbo.test (column_a INT) ; ALTER TABLE dbo.test ADD column_b VARCHAR(20) NULL CONSTRAINT TEST_unique UNIQUE ; EXEC sp_help TEST; DROP TABLE dbo.test; 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) ; INSERT INTO dbo.test VALUES (-1) ; ALTER TABLE dbo.test WITH NOCHECK ADD CONSTRAINT TEST_check CHECK (column_a > 1) ; EXEC sp_help TEST ; DROP TABLE dbo.test; 9

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) ; INSERT INTO dbo.test (column_a)values ( 7 ) ; ALTER TABLE dbo.test ADD CONSTRAINT col_b_def DEFAULT 50 FOR column_b ; INSERT INTO dbo.test (column_a) VALUES ( 10 ) ; SELECT * FROM dbo.test; DROP TABLE dbo.test; 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. 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); INSERT INTO #temptable VALUES (10); SELECT * FROM #temptable; IF OBJECT_ID(N'tempdb..#temptable', N'U') IS NOT NULL DROP TABLE #temptable; --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 CREATE VIEW [schema_name. ] view_name [(column [,...n] )] [WITH <view_attribute> [,...n]] AS SELECT_statement [WITH CHECK OPTION] [ ; ] 10

<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 ; 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 ; 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 ; 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 ; 11

Użycie funkcji wbudowanych IF OBJECT_ID ('Sales.SalesPersonPerform', 'V') IS NOT NULL DROP VIEW Sales.SalesPersonPerform ; 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; 2.6. Tworzenie indeksu Do utworzenia nowego indeksu na jednej lub kilku kolumnach tabeli służy polecenie CREATE INDEX. 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. <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. 12

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; CREATE INDEX IX_ProductVendor_VendorID ON Purchasing.ProductVendor (BusinessEntityID); 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 ; CREATE NONCLUSTERED INDEX IX_SalesPerson_SalesQuota_SalesYTD ON Sales.SalesPerson (SalesQuota, SalesYTD); 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; CREATE UNIQUE INDEX AK_UnitMeasure_Name ON Production.UnitMeasure(Name); 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); 13

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. <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. [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: 14

Przykład 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. 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; 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 15

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. 16

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. 17

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. 18

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) ; 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) ; 19

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. 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; Pobranie wybranych kolumn i wierszy. SELECT Name, ProductNumber, ListPrice AS Price FROM Production.Product WHERE ProductLine = 'R' AND DaysToManufacture < 4 ORDER BY Name ASC; 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; Wyświetlenie całkowitego zysku dla każdego produktu. SELECT 'Total income is', ((OrderQty * UnitPrice) * (1.0 - UnitPriceDiscount)), 20