Учебная дисциплина «Хранилища данных» для студентов специальности 080500.62 - Бизнес-информатика профиля «Архитектура предприятия» Практическое занятие №2 Операторы и алгоритмические конструкции языка Transact-SQL Цель: изучить основные операторы и алгоритмические конструкции Transact-SQL. Учебные вопросы: 1. Изучение операторов и алгоритмических конструкций языка Transact-SQL. 2. Применение операторов языка Transact-SQL с использованием SQL Server. 1. Изучение операторов и алгоритмических конструкций языка Transact-SQL. В 1970-х годах был разработан специальный язык SEQUEL (Structured English Query Language), который позднее был переименован в SQL. В 1986 году комитетом ANSI (American National Standards Institute) был принят первый стандарт языка. Последним принятым стандартом является ISO SQL:2008. Язык SQL разрабатывался как непроцедурный язык, который будет доступен обычным пользователям, а не только программистам. Однако со временем язык становился все сложнее и сейчас предназначен в большей степени для программистов. Несмотря на существование стандартов языка SQL, в каждой СУБД используется свое расширение этого языка. Основной причиной использования расширений SQL является потребность применять SQL не только как язык запросов, но и как язык программирования, для этого, как правило, вводятся так называемые хранимые процедуры. СУБД Microsoft SQL Server использует свое расширение языка, которое называется Transact-SQL и включает в себя следующее: управляющие конструкции; локальные переменные; дополнительные функции (математические, строковые и другие); поддержка аутентификации Windows. Типы данных MS SQL Server поддерживает все основные простые типы данных, используемые в современных языках программирования. В версии MS SQL Server 2008 были добавлены несколько новых типов, а некоторые перестали рекомендоваться к использованию. Типы данных в MS SQL Server можно разделить на семь категорий. 1 1. Целые числа: Bit (1 байт). На самом деле первый бит в таблице будет занимать один байт, однако следующие семь бит в этой таблице будут храниться в том же байте. Bigint (8 байт). 64-разрядное целое число, позволяет хранить 63 числа от –2 до +263–1. Int (4 байта). Диапазон значений от –2 147 483 648 до +2 147 483 647. SmallInt (2 байта). Диапазон значений от –32768 до +32767. TinyInt (1 байт). Диапазон значений от 0 до 255. 2. Числа с фиксированной запятой: Decimal или Numeric. Диапазон значений от –1038–1 до +1038–1. Money (8 байт). Денежный формат, диапазон значений от –263 до +263 с четырьмя знаками после запятой. SmallMoney (4 байта). Денежный формат, диапазон значений от –214748,3648 до +214748,3647. 3. Числа с плавающей запятой: Float. Диапазон значений от –1,79E +308 до +1,79E +308. 4. Дата и время: DateTime (8 байт). Диапазон значений от 1 января 1753 года до 31 декабря 9999 года с точностью до трех сотых секунды. DateTime2 (6-8 байт). Новый тип данных, поддерживает точность до 0,1 мс. SmallDateTime (4 байта). Диапазон значений от 1 января 1900 года до 6 июня 2079 года с точностью одна минута. DateTimeOffset (8-10 байт). Аналогичен типу DateTime, но хранит ещё сдвиг относительно времени UTC1. Date (3 байта). Хранит только дату. Диапазон значений от 1 января 0001 года до 31 декабря 9999 года. Time (3-5 байт). Хранит только время с точностью до 0,1 мс. 5. Символьные строки: Char. Строка фиксированной длины. Максимальная длина строки 8000 символов. VarChar. Строка переменной длины. Максимальная длина строки 8000, но при использовании ключевого слова «max» может хранить до 231 байт. 1 UTC (Universal Time Coordinated) – универсальное синхронизированное время. 2 Text. Применялся для хранения больших строк, сейчас рекомендуется использование varchar(max) вместо text. Оставлен для обратной совместимости. Nchar. Строка фиксированной длины в Юникоде. Максимальная длина строки 4000 символов. NvarChar. Строка переменной длины в Юникоде. Максимальная длина строки 4000 символов, но при использовании ключевого слова «max» может хранить до 231 байт. Ntext. Аналогичен типу text, но предназначен для работы с Юникод. Сейчас рекомендуется использовать nvarchar(max). Оставлен для обратной совместимости. 6. Двоичные данные: Binary. Позволяет хранить двоичные данные размером до 8000 байт. VarBinary. Тип данных переменной длины, позволяет хранить до 8000 байт, но при использовании ключевого слова «max» до 231 байт. Image. Использовался для хранения больших объемов данных, сейчас рекомендуется использовать varbinary(max). Оставлен для обратной совместимости. 7. Прочие типы данных: Table. Особый тип данных, используемый в основном для временного хранения таблиц и для передачи в качестве параметра в функции. HierarchyID. Используется для представления положения в иерархической структуре. Sql_variant. Тип данных, хранящий значения различных типов данных, поддерживаемых MS SQL Server. XML. Позволяет хранить XML-данные. Cursor (1 байт). Тип данных для переменных или выходных параметров хранимых процедур, которые содержат ссылку на курсор. Timestamp / rowversion (8 байт). Это тип данных, который представляет собой автоматически сформированные уникальные двоичные числа в базе данных. Значение данного типа генерируется БД автоматически при вставке или изменении записи. UniqueIdentifier (16 байт). Представляет собой GUID (Special Globally Unique Identifier). Гарантируется уникальность данного значения. Переменные в Transact-SQL Любой объект базы данных должен обладать уникальным именем внутри этой базы. На основе имени происходит обращение к этому объекту. Имена объектов называются идентификаторами. Transact-SQL накладывает ряд ограничений на порядок именования объектов: первый символ имени должен быть одним из символов латинского алфавита (A-Z, a-z), либо символом @, # или _, т.е. не допускается использование цифр и прочих специальных символов. Остальная часть 3 имени может включать любые символы алфавита, цифры и некоторые специальные символы; общая длина имени обычного объекта не должна превышать 128 символов, для временных объектов – 116; внутри имени запрещается использование пробелов, скобок и таких символов, как ~, !, %, ^, & и др. имя объекта не должно совпадать с зарезервированным словом и с именем уже существующего объекта; если имя объекта содержит пробелы или совпадает с зарезервированным словом, то его необходимо поместить внутрь квадратных скобок [ ]. Замечание: Transact-SQL является CASE-нечувствительным языком, т.е. не различает регистра символов. Имена локальных переменных должны удовлетворять перечисленным правилам именования объектов и всегда должны начинаться с символа @. Область действия переменной ограничена пакетом операторов или процедурой, в которой она была объявлена. Объявление переменной Синтаксис команды (внутри квадратных скобок в описании синтаксиса располагаются необязательные элементы): DECLARE @ИмяПеременной ТипДанных [ ,…n] Пример объявления одной переменной: DECLARE @sum int Пример объявления нескольких переменных: DECLARE @temp int, @count float Присвоение значения Синтаксис команды: SET @ИмяПеременной = Выражение Пример присвоения значения: SET @sum = 0 В версии MS SQL Server 2008 появились следующие нововведения. Инициализировать переменную стало можно сразу при объявлении, например: DECLARE @iCounter int = 0 4 Появились операторы +=, –=, *=, /= для краткой формы записи арифметических конструкций. Управляющие конструкции Transact-SQL Группировка команд Группировка двух и более команд в единый блок осуществляется с помощью конструкции: BEGIN ... END Такая группировка конструкциях. используется в условных и циклических Конструкция ветвления Выполнение той или иной группы команд в зависимости от выполнения или не выполнения некоторого условия реализуется с помощью конструкции: IF <условие> Оператор [ELSE Оператор ] При отсутствии команд, выполняемых при несоблюдении условия, ключевое слово ELSE можно не указывать. Следует отметить особенность проверки значений на NULL (специальный маркер, обозначающий отсутствие информации). Вместо обычного сравнения: IF @myvar = NULL, следует использовать оператор IS: IF @myvar IS NULL. Конструкция CASE Аналогична оператору CASE в языках программирования. В MS SQL Server 2008 оператор CASE имеет два возможных варианта использования. 1. С входным выражением: CASE <входное выражение> WHEN <выражение when > THEN <результат> [...] [ELSE <результат>] END 5 Пример: SELECT TOP 10 SalesOrderID, SalesOrderID Digit’, Position = CASE SalesOrderID % 10 WHEN 1 THEN ‘Один’ WHEN 2 THEN ‘Два’ WHEN 3 THEN ‘Три’ WHEN 4 THEN ‘Четыре’ ELSE ‘Другое’ END FROM Sales.SalesOrderHeader; % 10 AS ‘Last Результат запроса представлен на рис. 1. Рис. 1. Результат использования оператора CASE 2. Без входного выражения: CASE WHEN <логическое выражение> THEN <результат> [...] [ELSE <результат>] END Используется, как правило, для поиска. Пример: SELECT TOP 10 SalesOrderID % 10 AS 'OrderLastDigit', ProductID % 10 AS 'ProductLastDigit', "How Close?" = CASE WHEN (SalesOrderID % 10) < 3 THEN 'Меньше трёх' WHEN ProductID = 6 THEN 'ProductID равен 6' WHEN ABS(SalesOrderID % 10 - ProductID) <= 1 THEN пределах одного' ELSE 'Больше одного' END FROM Sales.SalesOrderDetail 6 ' В ORDER BY SalesOrderID DESC; Результат выполнения запроса представлен на рис. 2. Рис. 2. Результат использования оператора CASE Циклическая конструкция Transact-SQL поддерживает единственный тип цикла – цикл WHILE, синтаксис которого следующий: WHILE условие Оператор [BREAK | CONTINUE] Замечание. Вертикальная черта в описании синтаксиса означает «или», т.е. в данном примере может быть указан либо BREAK, либо CONTINUE. Тело цикла выполняется до тех пор, пока условие истинно. Цикл можно принудительно остановить, если выполнить в теле цикла команду BREAK. Если же нужно начать цикл заново, не дожидаясь выполнения команд тела цикла, необходимо выполнить команду CONTINUE. Конструкция WAITFOR В некоторых случаях требуется отложить выполнение той или иной команды. Для этих целей можно воспользоваться оператором WAITFOR. Эта команда имеет следующий синтаксис: WAITFOR DELAY <’time’> | TIME <’time’> Если используется параметр DELAY, то указывается, сколько времени необходимо ждать MS SQL Server. Максимально возможная задержка – 24 часа. Пример использования: WAITFOR DELAY ‘01:00’, который приостановит выполнение на один час. Если используется параметр TIME, то исполнение будет приостановлено до наступления заданного времени. Пример использования: 7 WAITFOR TIME ‘01:00’ – приостановление выполнения кода до наступления часа ночи. Блок TRY/CATCH Данную конструкцию можно использовать для обработки исключительных ситуаций. Впервые это конструкция появилась в MS SQL Server 2005. Блок TRY/CATCH в MS SQL Server работает также как и в других языках программирования. Используется следующий синтаксис: BEGIN TRY { <выражения SQL> } END TRY BEGIN CATCH { <выражения SQL> } END CATCH [ ; ] В блоке BEGIN TRY... END TRY выполняются потенциально опасные команды, если при этом произойдет ошибка уровня 11-19, то выполнение будет передано в блок CATCH. Уровни ошибок: 1–10 Информационные сообщения. Например, обнаружение NULL значений при выполнении агрегатных функций. Так как управление в блок CATCH данные ошибки не передают, то для получения информации об ошибки можно использовать функцию @@ERROR. 11–19 Относительно серьезные ошибки. Например, нарушение ограничений внешнего ключа. 20–25 Очень серьезные ошибки. Это ошибки на уровне системы, поэтому в коде нельзя узнать о ее возникновении. Такие ошибки разрывают текущее соединение и прерывают выполнение команд. Комментарии Существует два вида комментариев: однострочные – в этом случае игнорируется текст справа от символов комментария: -- (двойной дефис); многострочные – игнорируется текст, записанный между двумя парами символов: /* … */. Функции Transact-SQL MS SQL Server имеет ряд встроенных функций для облегчения и ускорения обработки данных. Различают три типа функций: функции наборов записей – результатом выполнения является объект, который может быть использован как таблица данных; 8 агрегатные функции – результатом является единственное значение заданного атрибута из некоторого множества записей; скалярные функции – результатом также является одно значение из строго определенного набора аргументов. Скалярные функции Выделяют следующие категории скалярных функций – математические, строковые, для работы с датами, конфигурационные и системные. Рассмотрим каждую категорию. Математические функции Большинство математических функций возвращают результат того же типа, что и исходные значения. Например, при переводе величины угла из градусов в радианы в случае Radians(90) результат равен 1, что неверно, так как в качестве аргумента функции использовано целое число. Правильная запись: Radians (90.0). Abs (выражение) – вычисление абсолютного значения выражения. Можно использовать как целочисленные, так и нецелочисленные величины. IsNumeric (выражение) – проверка, имеет ли указанное выражение числовой тип данных. Результат равен 1, если выражение имеет числовой тип, иначе – 0. Rand () – возвращает случайное значение на основе системного времени в диапазоне от 0 до 1. Floor (выражение) – округление указанного значения до ближайшего минимального целого числа. Ceiling (выражение) – возвращает ближайшее целое число, большее или равное данному. Power (выражение, степень) – возведение в степень выражения. Тип возвращаемого значения совпадает с исходным типом. Sqrt (выражение) – вычисляет квадратный корень. Строковые функции Ascii (строка) – возвращает ASCII-код самого левого символа строки. Char (выражение) – возвращает символ, ASCII-код которого соответствует указанному числовому выражению. Len (строка) – вычисляет длину строки в символах. LTrim (строка), RTrim (строка) – удаляют начальные и концевые пробелы соответственно. Left (строка, число), Right (строка, число) – возвращают указанное количество символов строки, начиная с левого и правого края строки соответственно. SubString (строка, начало, длина) – возвращает для строки подстроку указанной длины, начиная с указанного символа. CharIndex (строка1, строка2 [, старт]) – поиск подстроки строка1 в строке строка2. Возвращает порядковый номер первого символа, с которого 9 начинается первое вхождение подстроки в строку. Дополнительно можно указать стартовую позицию, с которой будет начат поиск. Stuff (строка1, начало, длина, строка2) – удаляет определенное количество символов строки1, начиная с указанного, и заменяет их новой строкой2. Replace (строка1, строка2, строка3) – заменяет все вхождения строки строка2 в исходной строке строка1 на строка3. Reverse (строка) – возвращает строку, символы которой записаны в обратном порядке по отношению к исходной строке. Функции для работы с датами GetDate () – возвращает текущее системное время. IsDate (выражение) – проверяет правильность выражения на соответствие одному из возможных форматов ввода даты. Day (дата), Month(дата), Year(дата) – возвращают день, месяц и год из указанной даты. DateName (тип, дата) – выделяет из даты указанную в типе часть и возвращает ее в символьном формате. Формат частей: yy или yyyy – год, qq или q – квартал, mm или m – месяц, dd или d – день, wk или ww – неделя, hh – час, mi или m – минута, ss или s – секунда, ms – миллисекунда. DatePart (тип, дата) – выделяет из даты указанную часть и возвращает ее в числовом формате. DateAdd (тип, число, дата) – добавляет к указанной дате число, тип которого указан в первом параметре. DateDiff (тип, начало, окончание) – возвращает разницу между указанными частями дат в указанном типе. Конфигурационные функции Возвращают информацию о текущей конфигурации MS SQL Server. Например: @@Version – возвращает информацию о дате, версии и типе процессора сервера. @@ServerName – символьное имя локального MS SQL Server. @@Max_Connections – максимально разрешенное количество одновременных подключений к серверу. Системные функции Возвращают информацию о значениях, объектах и текущих параметрах MS SQL Server. DataLength(выражение) – возвращает число, соответствующее количеству байт, необходимых для хранения результата выражения. @@Error – код последней ошибки, произошедшей в текущем соединении. Если ошибок нет, результат равен 0. Host_Name() – символьное имя компьютера в сети, на котором выполняется команда. 10 System_User и Session_User – возвращают соответственно имя учетной записи пользователя для входа и имя пользователя текущей базы данных. @@IDLE – определяет количество миллисекунд, прошедшее со времени последнего запуска MS SQL Server. NewID() – генерирует новое значение типа UniqueIdentifier. Permission ([ObjectID[, ‘column’]]) – возвращает информацию о правах доступа для текущего пользователя. Аргумент ObjectID указывает идентификационный номер объекта базы данных. Для получения идентификационного номера объекта по его имени используется функция Object_ID(‘имя’). Результатом данной функции является 32-битное значение, каждый бит которого соответствует тому или иному праву доступа. Если значение этого бита равно 1, то доступ к объекту разрешен. Определим, например, имеет ли пользователь право выборки данных из таблицы Product БД AdventureWorks2008: SELECT Permissions (object_id('production.product')) Если первый младший бит результата равен 1, то выборка данных из таблицы Product разрешена. Чтобы проверить право доступа к полю некоторой таблицы, необходимо указать идентификационный номер этой таблицы данных и в аргументе ‘column’ указать имя этого поля. Например, для проверки возможности выборки данных из поля Stor_id таблицы Sales необходимо: SELECT (object_id('production.product'),'ProductID') Permissions Если первый младший бит результата равен 1, то выборка данных из поля ProductID таблицы Product также разрешена. Отладка кода в Management Studio В MS SQL Server 2008 появилась возможность отлаживать SQL-код при помощи пошагового выполнения. Для этого существуют команды Debug – Step Into (F11) и Debug – Step Over (F10). Команда Debug – Toggle Breakpoint (F9) устанавливает точку останову, до которой будет происходить выполнение кода. Во время отладки доступны такие окна: Locals – автоматически содержит список всех локальных переменных и показывает их текущие значения; Watch – позволяет вручную добавлять переменные для отслеживания их значений; Callstack – показывает стек вызовов функций. Снимок экрана во время процесса отладки показан на рис. 3. 11 Рис. 3. Окно отладки в Желтая стрелка указывает на текущую красный кружок – точка останова. Management исполняемую Studio. строку; Краткие итоги. Рассмотрены типы данных, доступные в MS SQL Server 2008. Продемонстрировано использование базовых алгоритмических конструкций и локальных переменных, а также показана возможность отладки SQL-кода. 2. Применение операторов языка Transact-SQL с использованием SQL Server. Требования к отчету: по результатам работы нужно представить набор SQL-скриптов, решающих задачи из раздела «Самостоятельная работа». Задание 1. Подключитесь к серверу MyServ с помощью утилиты Management Studio. Указания к выполнению: 12 1. Запустите SQL Server Management Studio через меню Пуск – Программы – Microsoft SQL Server 2008. 2. Выберите тип аутентификации: SQL Server Authentication. Укажите User name: sa, и Password: пустой и нажмите кнопку Connect. Задание 2. Определить, имеет ли пользователь право выборки из таблицы Product. Указания к выполнению: 1. Установите текущей базой данных AdventureWorks2008. Это можно сделать одним из следующих способов: выполните команду USE AdventureWorks2008; выберите в выпадающем списке AdventureWorks2008 (см. рис. 2.1). Рис. 2.1. Выбор текущей базы данных 2. При помощи функции object_id получим идентификатор таблицы Product. 3. Функция Permissions возвращает 32-битовую маску, в которой каждый бит означает право текущего пользователя на определенное действие. При этом значение бита зависит от параметров, с которыми была вызвана функция. Функция Permissions может быть вызвана одним из трех способов: без параметров – возвращает список разрешенных действий пользователя, которые он может выполнять в текущей БД; с одним параметром obect_id – возвращает список допустимых действий над объектом, например, над таблицей; с двумя параметрами: object_id и атрибут – возвращает разрешенные действия над атрибутом. 13 В таблице приведен список разрешенных действий в соответствии с разными способами вызова функции Permissions. Для каждого действия указан номер и десятичное значение соответствующего бита. Номер бита 0 Бит (в десятичном виде) 1 1 2 2 4 3 4 5 6 8 16 32 64 7 8 12 13 14 128 256 4096 8192 16384 Разрешенное действие Без параметров Object_id CREATE DATABASE CREATE TABLE CREATE PROCEDURE CREATE VIEW CREATE RULE CREATE DEFAULT BACKUP DATABASE BACKUP LOG Зарезервировано SELECT ALL UPDATE ALL REFERENCES ALL INSERT DELECT EXECUTE Object_id и атрибут SELECT UPDATE REFERENCES SELECT ANY UPDATE ANY REFERENCES ANY В данном случае нас интересует младший (нулевой) бит – право на SELECT ALL. 4. Пример вызова функции Permissions (рис. 4): SELECT Permissions (object_id('production.product')) Рис. 4. Результат функции Permissions 5. Для определения того, задан ли интересующий нас бит, можно использовать битовую операцию «И» (&), тогда конечный вариант будет выглядеть следующим образом: IF Permissions (object_id('production.product'))&1=1 SELECT 'Есть право выборки' ELSE SELECT 'Права выборки нет' 14 Рис. 5. Результат функции Permissions для вывода текстового описания 6. Вместо оператора SELECT можно воспользоваться оператором PRINT, который просто позволяет выводить данные в виде текста, а не в виде таблицы, как это делает SELECT. Тогда код будет выглядеть так: IF Permissions (object_id('production.product'))&1=1 PRINT 'Есть право выборки' ELSE PRINT 'Права выборки нет' А результат будет выведен не на вкладку Results, а на вкладку Messages (рис. 6). Рис. 6. Результат использования PRINT Задание 3. Вывести имя компьютера, на котором выполняется команда. Если имя компьютера более девяти букв, то вывести только первые шесть букв. Указания к выполнению: 1. Для получения имени компьютера используется функция HOST_NAME(). 2. Для определения длины строки можно воспользоваться функцией DataLength. 3. Пример выполнения задания: IF (DATALENGTH(HOST_NAME()) / 2 > 9) SELECT LEFT(HOST_Name(), 6) + '...' ELSE SELECT HOST_Name() Замечание. Обратите внимание, что результат функции DATALENGTH мы разделили на два. Это обусловлено тем, что HOST_NAME() возвращает тип nvarchar, в котором под каждый символ отводится два байта. 15 Задание 4. Посчитать количество цифр в числе. Указания к выполнению: 1. Один из возможных вариантов решения данной задачи (см. рис.7): DECLARE @num int, @cnt int SET @num = 19 IF (@num = 0) SET @cnt = 1 ELSE BEGIN SET @cnt = 0 WHILE (@num <> 0) BEGIN SET @cnt = @cnt + 1 SET @num = @num / 10 END END SELECT @cnt AS 'Количество цифр' Рис. 7. Результат работы кода Самостоятельная работа 1. Оптимизировать код решения задания 4: избавиться от условного оператора, должен остаться только цикл WHILE, при этом код должен попрежнему работать как для нуля и положительных чисел, так и для отрицательных. 2. Определить, имеет ли пользователь право доступа к полю 'CardNumber', таблицы CreditCard в базе данных AdventureWorks2008. Если доступ есть, то вывести «Доступ есть», иначе – «В доступе отказано». 3. Написать программу пересчета веса из фунтов в килограммы (1 фунт равняется 453,6 г). Результат должен быть выведен следующим образом, например: 3.3 фунт(а/ов) – это 1 кг 496 г. 4. Вывести информацию о текущих именах сервера, учетной записи и пользователя базы данных в следующем виде: Вы вошли на сервер User400-01\SQL2008 как User400-01\User with dbo permissions. 16 5. Определить количество часов и минут, прошедших со времени запуска служб MS SQL Server. 6. Определить, является ли текущий год високосным. 17