Нові можливості T-SQL в MS SQL Server 2005 h2>
Гайдар Магдануров p>
Передмова h2>
В MS SQL Server 2005 з'явилося безліч нововведень,
що дозволяють ще більш продуктивно використати цю СУБД. Багато хто з них, такі
як нові типи даних, інтеграція з платформою. NET, підтримка XML, нові
функції ранжирування, покращення в системі безпеки та інше, вже були раніше
описані в журналі RSDN Magazine [1, 2, 3, 4, 5]. У цій статті будуть розглянуті
нові оператори та функції роботи з даними. У зв'язку із прийдешнім в листопаді виходом
фінальної версії, наведена інформація є надзвичайно актуальною для всіх
розробників, які використовують SQL Server. p>
Крім опису нових можливостей в статті наведені
приклади коду, що реалізують подібну функціональність, але працюють у попередніх
версіях SQL Server, тому ця стаття може бути корисна не тільки читачам,
планують використання SQL Server 2005, але й користувачам більш ранніх
версій цієї СУБД. p>
Демонстраційна база даних h2>
У статті не будуть розглядати стандартні
демонстраційні бази даних, що поставляються з SQL Server (Northwind,
AdventureWorks). Для найбільшої наочності прикладів, створимо невелику базу
даних деякого уявного магазину, що торгує ноутбуками. p>
Користувачеві цієї бази даних необхідно: мати
інформацію про моделі, що є в наявності на складі, здійснювати вибірку
моделей на підставі ціни і марки виробника, також, користувачеві необхідно
мати можливість оформляти замовлення клієнтів і складати чергу замовлень на
виконання. p>
Для реалізації цих бажань буде використана база
даних складається з чотирьох таблиць: Brands - довідник виробників,
що дозволяє відстежувати відносини компаній з точки зору «батьківська-дочірня»;
Products - таблиця наявних на складі моделей, що містить необхідну
інформацію про ціну, кількість, назву та базової конфігурації; Orders --
таблиця, що містить інформацію про замовлення; QrdersQueue - таблиця, що реалізує
функціональність черги замовлень. p>
CREATE TABLE [dbo]. [Brands] ( p>
[BrandID] [int] IDENTITY (1,1)
NOT NULL, p>
[Name] [nvarchar] (32) NOT NULL, p>
[ParentID] [int] NULL DEFAULT
((0)) p>
) p>
CREATE TABLE [dbo]. [Orders] ( p>
[OrderID] [int] IDENTITY (1,1)
NOT NULL, p>
[Date] [datetime] NOT NULL, p>
[ProductID] [int] NOT NULL, p>
[Quantity] [int] NOT NULL
DEFAULT ((1)) p>
) p>
CREATE TABLE [dbo]. [Products] ( p>
[ProductID] [int] IDENTITY (1,1)
NOT NULL, p>
[BrandID] [int] NOT NULL, p>
[Model] [nvarchar] (32) NOT
NULL, p>
[Configuration] [nvarchar] (128)
NOT NULL, p>
[Price] [money] NOT NULL, p>
[Quantity] [numeric] (18, 0) NOT
NULL p>
) p>
CREATE TABLE [dbo]. [OrdersQueue] ( p>
[QueueID] [int] IDENTITY (1,1)
NOT NULL, p>
[OrderID] [int] NOT NULL p>
) p>
Нові можливості T-SQL
p>
На початку статті будуть розглянуті нові функції й оператори
T-SQL в SQL Server 2005 і приклади їх використання, зміни, зачепили
яким він був раніше оператор TOP, після чого розказано про нову можливість
обробки помилок у T-SQL. p>
Загальні табличні вирази
p>
Загальні табличні вирази (Common Table Expressions,
CTE) дозволяють визначати часові іменований набір даних, функціонально
схожий на подання (View), доступний в межах пакету (batch). p>
Для спрощення подальшого викладу, введемо більш
простий термін віртуальне уявлення замість дослівного англійського перекладу
загальне табличне вираз. p>
Віртуальні подання дозволяють використовувати
одного разу оголошене у процедурі подання замість вкладених запитів, як
це доводилося робити в більш ранніх версіях SQL Server, що значно покращує
читаність T-SQL коду. Для оголошення подання використовується синтаксис p>
WITH ІмяПредставленія (ІмяПоля, ІмяПоля,
...) AS (Підзапит) p>
де число полів в оголошенні подання повинне
відповідати числу одержуваних полів у підзапит. p>
Припустимо, необхідно здійснити вибірку всіх моделей,
ціна яких перевищує середню ціну в модельному ряду свого виробника. p>
Завдання можна вирішити, використовуючи віртуальне
подання p>
WITH AvgPrice (BrandID, Price) AS p>
(SELECT BrandID, AVG (Price) FROM Products GROUP BY BrandID) p>
SELECT P. Model FROM Products AS P INNER JOIN AvgPrice AS A ON p>
P. BrandID = A. BrandID AND P. Price> A. Price p>
або використовуючи вкладений підзапит p>
SELECT
P. Model FROM Products AS P p>
INNER JOIN (SELECT BrandID, AVG (Price) FROM
Products GROUP BY BrandID) AS A ON p>
P. BrandID = A. BrandID AND P. Price>
A. Price p>
Як видно з прикладу, використання CTE і вкладених
підзапитів еквівалентно, але, читач легко може уявити ситуацію, коли
одне і те ж віртуальне представлення даних потрібно використовувати кілька разів
в збереженої процедурою, в цьому випадку один раз оголошене подання з
використанням CTE потребує значно менше SQL коду. p>
Рекурсія з використанням віртуальних уявлень
p>
Одним з основних переваг віртуальних уявлень
(CTE), є просте і наочне побудова рекурсивних виразів. P>
Досить часто зустрічаються таблиці з ієрархічною
структурою даних ( «дерева»). У випадку, коли необхідно отримати рівень
вкладеності елемента, кращим рішенням буде використання рекурсивного запиту
з використанням віртуального представлення. Припустимо, в магазині, що використовує
демонстраційну базу даних, вирішили додати можливість задавати «ступінь
спорідненості »фірм, для визначення дочірніх компаній відомих брендів. p>
Для таблиці Brands потрібно створити віртуальний
уявлення, що використовує рекурсію для отримання рівня вкладеності: p>
WITH C (BrandID, [Name], ParentID, NestingLevel) AS p>
( p>
SELECT B. BrandID, B. [Name],
B. ParentID, 1 FROM Brands AS B WHERE ParentID = 0 p>
UNION ALL p>
SELECT B. BrandID, B. [Name],
B. ParentID, (NestingLevel + 1) FROM Brands AS B p>
INNER JOIN C ON C. BrandID =
B. ParentID p>
) p>
SELECT * FROM C p>
Результатом виконання запиту буде таблиця, наприклад
така: p>
BrandID Name ParentID NestingLevel p>
----------------------------------------------- --- p>
1 Parent1 0 1 p>
2 Parent2 0 1 p>
3 Child1 1 2 p>
4 Child11 3 3 p>
5 Child12 3 3 p>
Загальний принцип побудови рекурсивного вираження p>
WITH ІмяCTE (Визначення)
AS p>
( p>
SELECT ... - Вибірка з початковим умовою, p>
UNION ALL - Об'єднання результатів p>
SELECT ... - Вибірка определяющаяя крок
рекурсії p>
INNER JOIN CTE.ДочернійID =
ІмяТабліци.РодітельскійID - Приєднання «по батькові» p>
) p>
Без використання віртуального уявлення, для
досягнення того ж результату доведеться написати значно складніший
запит: p>
DECLARE @ CurrentID int p>
DECLARE @ Level int p>
SELECT TOP (1) @ CurrentID = BrandID FROM Brands ORDER BY BrandID p>
DECLARE @ StackTable TABLE (ID int, Level int) p>
DECLARE @ OutputTable TABLE (ID int, [Name] nvarchar (32), ParentID int,
Level int) p>
INSERT INTO @ StackTable VALUES (@ CurrentID, 1) p>
SET @ Level = 1 p>
WHILE @ Level> 0 p>
BEGIN p>
IF EXISTS (SELECT * FROM
@ StackTable WHERE Level = @ Level) p>
BEGIN p>
SELECT @ CurrentID = ID FROM @ StackTable WHERE Level = @ Level p>
INSERT INTO @ OutputTable p>
SELECT BrandID, [Name], ParentID, @ Level AS Level FROM Brands p>
WHERE BrandID = @ CurrentID p>
DELETE FROM @ StackTable
WHERE Level = @ Level AND ID = @ CurrentID p>
p>
INSERT @ StackTable p>
SELECT BrandID, @ Level + 1 FROM Brands WHERE ParentID = @ CurrentID p>
IF @ @ ROWCOUNT> 0 p>
SET @ Level = @ Level + 1 p>
END p>
ELSE p>
SET @ Level = @ Level - 1 p>
END p>
SELECT * FROM @ OutputTable ORDER BY ID p>
Як бачить читач, код без використання віртуальних
уявлень більш громіздкий і складний для розуміння. Незважаючи на те, що
подібний код нескладно написати, досить просто допустити прикру помилку, на
пошуки якої може піти багато часу. p>
Крім того, рекурсія з використанням віртуального
уявлення значно перевершує в продуктивності підхід з використанням
тимчасових таблиць. Так, для тестового набору зі ста тисяч записів в таблиці
Brands, час виконання коду з використанням віртуального представлення
виявилося в чотири рази менше, ніж час виконання коду без використання
той. Приблизно те ж відношення отримано і для менших наборів даних. P>
Оператори EXCEPT і INTERSECT
h2>
Оператори EXCEPT і INTERSECT дозволяють здійснити
вибірку даних, спільних або різних для декількох наборів даних. Синтаксис
нових операторів абсолютно аналогічний оператору UNION. p>
Припустимо, необхідно отримати BrandID виробників,
моделі яких не присутні в таблиці Products. Тоді, застосувавши оператор
EXCEPT наступним чином: p>
SELECT B. BrandID FROM Brands B p>
EXCEPT p>
SELECT P. BrandID FROM Products P p>
можна досягти того ж результату, що і при
використанні оператора EXITS в комбінації з оператором заперечення NOT: p>
SELECT
B. BrandID FROM Brands B p>
WHERE
NOT EXISTS (SELECT P. BrandID FROM Products P WHERE P. BrandID = B. BrandID) p>
Аналогічно, для того, щоб отримати BrandID виробників,
чиї моделі присутні в таблиці Products. Можна використовувати оператор
INTERSECT: p>
SELECT
B. BrandID FROM Brands B p>
INTERSECT p>
SELECT
P. BrandID FROM Products P p>
а можна і оператор EXIST без заперечення: p>
SELECT
B. BrandID FROM Brands B p>
WHERE
EXISTS (SELECT P. BrandID FROM Products P WHERE P. BrandID = B. BrandID) p>
або ж зовсім звичний синтаксис INNER JOIN: p>
SELECT
DISTINCT B. BrandID FROM Brands B p>
INNER JOIN Products P ON B. BrandID =
P. BrandID p>
Очевидно, що нові оператори дозволяють зменшити
кількість коду, необхідного для реалізації вибірки, причому виграш в обсязі
коду зростає пропорційно числу полів у вибірці. Також, не менш важливим
перевагою є краща читаність коду. p>
Продуктивність запиту при використанні нових
операторів, практично не відрізняється від продуктивності запитів з EXISTS і
JOIN. Число читань (Reads) і час виконання (Duration) мало відрізняються в
обох випадках. p>
Оператор APPLY
p>
Іноді, при написанні складних процедур для роботи з
даними, зручно використовувати функції, повертають не скалярний значення, а
таблицю. У попередніх версіях SQL Server не було можливості в конструкціях
JOIN використовувати як аргументи викликається функції параметри з
зовнішнього запиту. Наприклад, створимо процедуру GetProductDetails: p>
CREATE
FUNCTION GetProductDetails (@ ProductID int) RETURNS TABLE p>
AS p>
RETURN
SELECT P. Model, P. Configuration, P. Price FROM Products P p>
WHERE P. ProductID = @ ProductID p>
Наступний код, який використовує GetProductDetails приведе
до помилки: p>
- Увага! Цей код не працює p>
SELECT
O. [Date], P. Model, P. Configuration, P. Price FROM Orders O p>
OUTER JOIN GetProductDetails (O. ProductID) AS
P ON P. ProductID = O. ProductID p>
У SQL Server 2005 для подібного використання функцій
призначений оператор APPLY. Використовуючи його замість JOIN можна досягти бажаного
результату: p>
SELECT
O. [Date], P. Model, P. Configuration, P. Price FROM Orders O p>
OUTER APPLY GetProductDetails (O. ProductID)
AS P p>
Оператор APPLY використовується в комбінації з двома
ключовими словами: CROSS і OUTER. Функціональність CROSS APPLY аналогічна INNER
JOIN - у випадку, якщо процедура не повертає результат, то рядок не потрапляє
в результуючий набір даних, OUTER APPLY працює аналогічно OUTER JOIN --
якщо процедура не повертає результат, то рядок все-таки потрапляє в
результуючий набір, а в колонках, відповідних одержуваним з процедури
даними будуть знаходитися значення NULL. p>
Виходячи з плану виконання запиту, функція
GetProductDetails виконується для кожного параметра, що отримується із зовнішнього
запиту, що призводить до драматичних наслідків з точки зору
продуктивності. Таким чином, використання APPLY для значних обсягів
даних може бути далеко не найкращим рішенням. Тому, необхідно
ретельно перевіряти продуктивність запитів, що використовують APPLY на реальних
обсягах даних і, відповідно до цього, робити висновок про розумність застосування
цього оператора при побудові запиту. p>
Інструкція TABLESAMPLE
p>
Іноді буває необхідно отримати деяку вибірку
записів з бази даних, що відображає характер даних, що містяться в базі. Для
здійснення подібної вибірки в SQL Server 2005 добавлена інструкція
TABLESAMPLE, яка в якості параметру приймає кількість рядків або
відносна кількість рядків у відсотках від загального числа в таблиці.
Використовується інструкція наступним чином: p>
SELECT СпіскоПолей FROM ІмяТабліци
TABLESAMPLE (КолічествоПроцентов PERCENT) p>
або, якщо потрібно вибрати певну кількість рядків p>
SELECT СпіскоПолей FROM ІмяТабліци
TABLESAMPLE (ЧіслоСтрок ROWS) p>
Проте варто відзначити, що буде повернуто НЕ
задану кількість строк (ROWS) або відсотків (PERCENT), а лише приблизно
відповідне заданому кількість. p>
Якщо необхідно отримувати вибірку постійного
змісту протягом кількох повторюваних запитів, то потрібно вказати після
інструкції TABLESAMLE додатково інструкцію REPEATTABLE: p>
SELECT СпіскоПолей FROM ІмяТабліци
TABLESAMPLE (ЧіслоСтрок ROWS) REPEATTABLE (ЧіслоПовтореній) p>
Функція OUTPUT
p>
Нова функція OUTPUT служить для повторного
використання даних запиту. За допомогою цієї функції можна отримати змінені
в поточному запиті дані та будуть використані для вставки в іншу таблицю, або
повернути ці дані в викликає код. p>
Уявімо, що в магазині, що використовує демонстраційну
базу даних, відбулася радісна подія, і вся партія, що надійшли в продаж
ноутбуків була закуплена великим замовником в момент вступу. У цьому випадку
необхідно дані, що вставляються в таблицю Products, помістити також і в таблицю
Orders. У SQL Server 2005 це можна зробити в одному запиті до бази даних: p>
INSERT
INTO Products (BrandID, Model, Configuration, Price, Quantity) p>
OUTPUT GETDATE (), inserted.ProductID,
inserted.Quantity p>
INTO Orders ([Date], ProductID, Quantity) p>
VALUES (@ BrandID, @ Model, @ Configuration,
@ Price, @ Quantity) p>
Читач легко побачить з прикладу, що для доступу до
змінним даними (вставляються в таблицю в даному прикладі) використовується
ідентифікатор (ім'я псевдо таблиці), що вказує на характер операції,
що проводиться з даними. Можливе використання наступних ідентифікаторів: p>
inserted, для команди INSERT p>
deleted, для команди DELETE p>
У разі використання функції OUTPUT в запиті
UPDATE, змінені дані будуть доступні в псевдо таблиці inserted, а дані,
які піддалися зміні в псевдо таблиці deleted. p>
Функція OUTPUT не може бути використана в запиті
INSERT, в якому вставка проводиться до подання даних (View), а також для
вставки змінених даних до подання або табличну функцію. p>
Також варто пам'ятати про те, що OUTPUT не гарантує,
що елементи будуть завантажувати в таблицю в тому ж порядку, в якому відбувається
застосування змін. При цьому, якщо в процесі виконання запиту UPDATE
змінюються будь-які змінні або параметри, то OUTPUT повертає модифіковані
значення параметрів або змінних, тобто такі значення, які змінні
або параметри мали до виконання запиту. p>
Застосування функції OUTPUT
p>
Вибірка вставлених даних p>
Іноді буває зручно отримати в якості результату виконання
процедури, вставляють дані в таблицю, результуючу рядок, особливо коли
цей рядок містить колонку з унікальним значенням. Використовуючи OUTPUT це можна
наступним чином: p>
DECLARE
@ TempBrands TABLE (BrandID int, [Name] nvarchar (32)) p>
INSERT
INTO Brands ([Name]) OUTPUT inserted .* INTO @ TempBrands p>
VALUES (@ Name) p>
SELECT
* FROM @ TempBrands p>
Відзначимо, що цей приклад показує роботу з одного
рядком, оскільки при втавке великої кількості рядків, поряок проходження
може бути порушений (як уже було написано вище, OUTPUT не гарантує порядок
рядків) і використовувати значення BrandID в зухвалій коді без Додаткова
перевірок буде проблематично. p>
Звичайно, немає жодної проблеми в тому, щоб отримати в
результаті запиту BrandID, не використовуючи OUTPUT, оскільки зазвичай всі дані
вже є в зухвалій процедуру коді (вони ж і передаються як
аргументів самої процедури), за винятком елемента з унікальним значенням. p>
INSERT
INTO Brands ([Name]) VALUES (@ Name) p>
SELECT @ @ IDENTITY p>
Реалізація функціональності черги p>
Функція OUTPUT також дозволяє зручно реалізувати
функціональність черги, «витягуючи» з таблиці запис, при цьому видаляти її.
Наприклад, якщо буде потрібно функціональність черг на виконання замовлення, то
необхідно буде створити таблицю-чергу, наприклад p>
CREATE
TABLE [Queue] ( p>
[QueueID] [int] IDENTITY (1,1) NOT NULL, p>
[OrderID]
[int] NOT NULL p>
) p>
і за допомогою неї реалізувати необхідну
функціональність, використовуючи функцію OUTPUT: p>
DECLARE @ Queue TABLE (QueueID int, OrderID int) p>
DELETE TOP 1 FROM [Queue] ORDER BY QueueID p>
OUTPUT deleted.QueueID, deleted.OrderID INTO @ Queue p>
SELECT * FROM @ Queue p>
Без використання функції OUTPUT, код виходить
трохи більш громіздким: p>
DECLARE @ Queue TABLE (QueueID int, OrderID int) p>
INSERT INTO @ Queue (QueueID, OrderID) SELECT TOP 1 [Queue]. QueueID,
[Queue]. OrderID FROM [Queue] p>
DELETE [Queue] FROM [Queue] AS Q1 p>
INNER JOIN @ Queue AS Q2 ON
Q1.QueueID = Q2.QueueID p>
SELECT * FROM @ Queue p>
Опції PIVOT і UNPIVOT
p>
Магазин ноутбуків з успіхом використовує
демонстраційну базу даних протягом багатьох років, і накопичив величезну
статистику з продажу ноутбуків. Природно бажання знати, для порівняння,
обсяги продажів за різні роки і загальну суму прибутку. Для того, щоб з таблиць
Orders і Products отримати необхідну власників магазину інформацію кращим
способом є використання ключового функції PIVOT, дозволяющей як би
«Розвернути» дані в таблиці. P>
SELECT Model, [2005], [2004] FROM ( p>
SELECT P. Model, DATEPART (year,
O. [Date]) AS [Year], O. Quantity FROM Orders O p>
INNER JOIN Products P ON
P. ProductID = O. ProductID p>
) AS C p>
PIVOT (SUM (Quantity) FOR [Year] IN ([2005], [2004])) AS PVT p>
З використанням віртуального представлення код можна
написати трохи інакше: p>
WITH C (Model, [Year], Quantity) AS ( p>
SELECT P. Model, DATEPART (year,
O. [Date]) AS [Year], O. Quantity FROM Orders O p>
INNER JOIN Products P ON
P. ProductID = O. ProductID p>
) p>
SELECT Model, [2005], [2004] FROM C p>
PIVOT (SUM (Quantity) FOR [Year] IN ([2005], [2004])) AS PVT p>
Результатом виконання даного коду в демонстраційній
базі даних буде таблицю з трьома колонками: Model, 2005 і 2004. Наприклад: p>
Model 2005 2004 p>
----------------------------------- p>
A75-S206 10 24 p>
M40-110 17 38 p>
S215SR 2 10 p>
T2XRP 35 12 p>
V6800V 12 4 p>
У попередніх версіях SQL Server, де не була
реалізована функція PIVOT і CTE, щоб досягти необхідного результату, довелося
б писати код на зразок наведеного нижче. p>
SELECT
C. Model, p>
SUM (CASE C. [Year] WHEN 2005 THEN C. Quantity
ELSE 0 END) AS [2005], p>
SUM (CASE C. [Year] WHEN 2004 THEN C. Quantity
ELSE 0 END) AS [2004] p>
FROM
( p>
SELECT P. Model, DATEPART (year, O. [Date]) AS
[Year], O. Quantity FROM Orders O p>
INNER JOIN Products P ON P. ProductID =
O. ProductID p>
) AS C p>
GROUP
BY C. Model p>
Читач, навіть недосвідчений у програмуванні на T-SQL,
напевно відзначить складність роботи з кодом, написаний без використання
функції PIVOT, у випадку більш складних запитів. У той же час, PIVOT є
лише синтаксичної оболонкою для наведеної вище конструкції. Подивившись плани
виконання прикладу, наведеного вище та прикладу, з використанням функції
PIVOT, можна переконатися в їх ідентичності. P>
Функція UNPIVOT виконує процедуру зворотний PIVOT,
«Розгортаючи» назад таблицю даних, що піддалися «обробці» функцією PIVOT
, В початковий стан. Покладемо, що для ведення статистики є наступна
таблиця p>
CREATE TABLE [Statistics] ( p>
[Model] [nvarchar] (32) NOT
NULL, p>
[2005] [int] NOT NULL, p>
[2004] [int] NOT NULL p>
) p>
що містить дані, отримані в ході виконання
попереднього запиту - приклад використання функції PIVOT. p>
SELECT
* FROM [Statistics] p>
UNPIVOT (TotalQuantity FOR [Year] IN ([2005],
[2004])) AS PVT p>
Результатом виконання буде таблиця з трьох стовпців:
Model, TotalQuantity, Year. p>
Model TotalQuantity Year p>
------------------------------------------ p>
A75-S206 10 2004 p>
A75-S206 24 2005 p>
M40-110 17 2004 p>
M40-110 38 2005 p>
Оновлений оператор TOP
p>
Оператор TOP широко використовується для обмеження числа
рядків, що повертаються командою SELECT. У попередніх версіях SQL Server, оператор
TOP брав як параметр тільки константу. У SQL Server 2005
параметром цього оператора може бути змінна, вираз чи вкладений
питання. p>
Наприклад, у такий спосіб можна здійснити вибірку
такого числа моделей деякого виробника, що відповідає середньому
кількістю моделей кожного виробника в таблиці Products: p>
SELECT
TOP (SELECT AVG (AvgNum) * FROM p>
(SELECT
COUNT (*) AS AvgNum FROM Products GROUP BY BrandID) AS NumTable) P. Model FROM
Products P p>
Для використання в якості параметра оператора TOP
змінної, вирази або вкладеного запиту необхідно укладати її в круглі
дужки: p>
SELECT
TOP (@ Num) * FROM ІмяТабліци p>
При використанні константи, дужки не обов'язкові в
команді SELECT, але обов'язкові при використанні з командами, що змінюють
дані, наприклад: p>
DELETE
TOP (10) FROM Orders ORDER BY Date DESC p>
У попередніх версіях SQL Server для використання
змінної як параметр оператора TOP доводилося вдаватися до складних
конструкціям або динамічному створення запиту. p>
DECLARE @ DynamicQuery varchar (100) p>
SET @ DynamicQuery = 'SELECT TOP' + CAST (@ N AS varchar) + '* FROM
Products ' p>
EXECUTE (@ DynamicQuery) p>
Розбиття даних на сторінки з використанням
оператора TOP
p>
Найбільш простим способом використання оператора TOP
для розбиття на сторінки є використання зміщення по колонці ID.
Процедура приймає параметр - кількість записів на сторінці і «останній» ID,
отриманий у попередньому запиті. При цьому, завдяки новим можливостям
оператора TOP, можна варіювати кількість записів на сторінці, використовуючи
таку просту процедуру. p>
SELECT
TOP (@ N) * FROM ІмяТабліци WHERE КолонкаID> @ ID p>
Більш загальний підхід, який не потребує збереження
«Останнього» ID попереднього запиту і формально не залежить від значення ID
виглядає так: p>
SELECT
* FROM (SELECT TOP (@ N * (@ PageNum + 1)) * FROM ІмяТабліци p>
ORDER
BY КолонкаID) AS PTable p>
WHERE
КолонкаID NOT IN (SELECT TOP (@ N *
@ PageNum) КолонкаID FROM ІмяТабліци p>
ORDER BY КолонкаID) p>
Слід звернути увагу читача, що запит буде
виконувати своє завдання лише за умови того, що колонка КолонкаID містить
унікальні значення. Таким чином, для забезпечення розбиття даних за допомогою
такої процедури потрібно мати в таблиці колонку IDENTITY. p>
Для того, щоб подібна процедура працювала в більш ранніх
версіях SQL Server, необхідно використовувати динамічне створення запиту: p>
DECLARE @ Query nvarchar (200) p>
SET @ Query = 'SELECT * FROM (SELECT TOP' + CAST (@ N * (@ PageNum + 1)
AS nvarchar) + p>
'* FROM ІмяТабліци ORDER BY КолонкаID) AS P p>
WHERE КолонкаID NOT IN (SELECT TOP '+ CAST (@ N * @ PageNum
AS nvarchar) + p>
'КолонкаID FROM ІмяТабліци ORDER BY КолонкаID)' p>
EXECUTE (@ Query) p>
Обробка помилок в SQL
p>
У зв'язку з інтеграцією SQL Server з платформою. NET,
мови якої підтримують гнучкий механізм обробки виключень, розробники
SQL Server включили до T-SQL давно бажану SQL-програмістами можливість
обробки виключень. Поточна реалізація в SQL Server 2005 дозволяє
обробляти некритичні помилки за допомогою схожого на що став вже стандартним
синтаксис TRY ... CATCH. p>
BEGIN
TRY p>
- «Небезпечний» запит p>
END
TRY p>
BEGIN
CATCH p>
- Обробка помилки p>
END
CATCH p>
Механізм обробки помилок у T-SQL, звичайно, не такий
гнучкий, як в. NET мовами, але, тим не менше, дозволяє зробити досить
багато, аналізуючи код помилки, що повертається функцією @ @ ERROR. Наприклад, якщо
таблиця Products задана так, що не дозволяє зберігати від'ємне значення в
колонці Quantity: p>
CREATE TABLE [Products] ( p>
[ProductID] [int] IDENTITY (1,1)
NOT NULL, p>
[BrandID] [int] NOT NULL, p>
[Model] [nvarchar] (32) NOT
NULL, p>
[Configuration] [nvarchar] (128)
NOT NULL, p>
[Price] [money] NOT NULL, p>
[Quantity] [int] NOT NULL,
CHECK ([Quantity]> = 0) p>
) p>
то можна використовувати наступний код для зміни
кількості наявних на складі ноутбуків і створення замовлення: p>
BEGIN TRY p>
BEGIN TRAN - Створення транзакції p>
INSERT INTO Orders ([Date],
ProductID, Quantity, [Year]) VALUES (GETDATE (), @ ProductID, @ Quantity, @ Year) p>
SET @ OrderID = @ @ IDENTITY p>
UPDATE Products2 SET Quantity =
Quantity - @ Quantity WHERE ProductID = @ ProductID p>
UPDATE Orders SET Quantity =
@ Quantity WHERE OrderID = @ OrderID p>
COMMIT - Якщо немає помилок, то підтверджуємо транзакцію p>
END TRY p>
BEGIN CATCH p>
DECLARE @ Err int p>
SET @ Err = @ @ ERROR p>
ROLLBACK - Відкат транзакції p>
IF @ ERR = 547 p>
BEGIN p>
SELECT 'Недостатньо ноутов на складі' AS
Error p>
END p>
ELSE p>
BEGIN p>
SELECT 'Невідома помилка' AS Error, @ Err
AS ErrorNumber p>
END p>
END CATCH p>
Висновок
p>
Нехай нові можливості Transact-SQL в SQL Server 2005
не вносять нічого принципово нового в пристрій SQL Server, але дозволяють
значно швидше створювати більш зрозумілий і легко читається код, спрощуючи,
таким чином, життя розробника. p>
На закінчення, автор настійно рекомендує читачеві
ознайомитися зі статтями з списку літератури, оскільки в них описані
кардинальні зміни основної концепції SQL Server. p>
Список літератури h2>
Іван Бодягін, Нові можливості MS SQL Server 2004
"Yukon", RSDN Magazine # 6-2003 p>
Антон Злагостев, MS SQL Server 9 "Yukon". Інтеграція з
. NET, RSDN Magazine # 6-2003 p>
Іван Бодягін, версійність в "Yukon", RSDN Magazine
# 6-2003 p>
Іван Бодягін, MS SQL 2005: віконні функції, RSDN
Magazine # 6-2004 p>
Олексій Ширшов, Використання XML спільно з SQL,
RSDN Magazine # 2-2004 p>
Для підготовки даної роботи були використані
матеріали з сайту http://www.rsdn.ru/
p>