    15 ГЛАВА 

    Microsoft SQL Server 

    Эта глава посвящена системе управления реляционными базами данных \ 
Microsoft SQL Server. Здесь обсуждаются вопросы совместного исполь-1 зования 
данной СУБД и Delphi, а также рассматривается диалект языка SQL, используемый 
в СУБД Microsoft SQL Server. 

    Запуск SQL Server 

    Для запуска и завершения работы СУБД SQL Server используется приложение 
SQL Services Manager. Эта утилита находится в программной группе или папке SQL 
Server. Можно использовать также утилиту Windows Sen/ices, находящуюся в папке 
Control Panel Windows NT. Поскольку СУБД SQL Service может функционировать в 
качестве службы Windows NT, ее можно запускать и останавливать с помощью 
команды Services приложения Service Manager системы Windows NT. 
    Кроме средств управления SQL Server как службой Windows NT, для завершения 
ее работы при необходимости можно использовать команду SHUTDOWN языка 
Transact-SQL. Для немедленного завершения работы сервера в команде SHUTDOWN 
необходимо указать параметр NOWAIT. В противном случае работа сервера 
прекращается только после завершения текущего процесса. 

    Подключение к серверу 

    Многие вопросы, возникающие при работе с Microsoft SQL Server или при 
подключении к серверу, относятся в той же мере и к Sybase SQL Server. До 
недавнего времени фирма Microsoft по лицензии фирмы Sybase использовала код 
Sybase SQL Server. Начиная с версии Microsoft SQL Server 6.0, стратегии 
разработки этих двух программных продуктов пошли в разных направлениях, и 
сотрудничество двух компаний прекратилось. 
    Вследствие того, что Microsoft SQL Server стоит недорого и работает в 
системе Windows NT, можно разрабатывать приложения для этой СУБД архитектуры 
клиент/сервер, в которых клиентная и серверная часть располагаются на одном и 
том же компьютере, т.е. использовать Microsoft SQL Server как локальную СУБД. 
Низкая цена SQL Server позволяет применять ее в этом качестве, что особенно 
популярно в небольших организациях. Если вы также прибегли к такому способу, 
то постарайтесь отладить ваше приложение как можно тщательнее, сделав его 
максимально надежным. Если вам каким-то образом удастся "подвесить" Windows NT 
(что не так-то просто), то это приведет к аварийному завершению работы не 
только клиентной, но и серверной части, вследствие чего могут пострадать 
данные. Это предостережение справедливо для всех платформ и систем SQL Server. 
Если же клиентная и серверная части к тому же располагаются на одном и том же 
компьютере, то будьте вдвойне осторожны. 
    Несмотря на все опасности, работа приложений Delphi на одном компьютере с 
SQL Server выгоднее тем, что облегчается настройка подключения к базе данных. 
Например, в этом случае отпадает необходимость использования настоящего 
TCP/IP-адреса компьютера — вместо этого можно воспользоваться фиктивным 
закольцовывающим (loop-back) адресом 127.0.0.1. 
    
    306 Часть III. Справочные материалы 

    Настройка подключений клиента 

    Подключения со стороны клиента в SQL Server настраиваются с помощью 
утилиты SQL Client Configuration. Она должна находиться в папке Microsoft SQL 
Server. Для настройки нового подключения клиента выполните следующее. 
    1.    Запустите утилиту SQL Client  Configuration. 
    2.   Откройте вкладку Advanced. 
    3.   Введите имя сервера в строке Server. Имя, в принципе, может быть 
любым, но лучше указать реальное имени сервера. Это облегчает настройку всех 
остальных подключений. 
    4.   В списке Net Library Configuration выберите сеть, которая будет 
использоваться по умолчанию. Это могут быть сети с протоколами Named Pipes-или 
TCP/IP, хотя возможны и другие варианты. 
    5.   Если для подключения выбран протокол Named Pipes и реальное имя 
компьютера в качестве имени сервера (в строке Server), то настройка окончена. 
Щелкните на кнопке Add/Modify для добавления псевдонима нового подключения, а 
затем щелкните на кнопке Done. 
    6.    Если выбран протокол, отличный от Named Pipes, то необходимо указать 
дополнительную информацию о подключении, конкретное содержание которой зависит 
от типа протокола. Так, при использовании TCP/IP необходимо знать IP-адрес 
сервера и номер его порта ввода. Эти данные обычно отделяются запятыми. 
Введите требуемую информацию, а затем щелкните на кнопках Add/Modify и Done. 
    Теперь вы располагаете псевдонимом подключения со стороны клиента, который 
может использоваться для обращения к серверу SQL из приложений Delphi. 

    Предупреждение 

    Перед настройкой подключения убедитесь, что у вас установлена нужная 
версия утилиты SQL client Configuration. Для 16-разрядных клиентных приложений 
(например, Windows 3.x) необходима 16-разрядная версия библиотек подключения, 
а для 32-разрядных — 32-разрядная версия. Некоторые средства администрирования 
баз данных независимых производителей (например, DB Artisan) являются 
16-разрядными, хотя и работают в среде Windows NT. Для таких утилит даже в 
32-разрядной операционной системе необходимы 16-разрядные версии 
соответствующих библиотек. 

    Устранение проблем при подключении к серверу Microsoft SQL Server 

    Если у вас возникли проблемы с подключением к Microsoft SQL Server, 
попытайтесь проделать следующее. 
    1.    Используйте для подключения к серверу утилиту Microsoft iSQL/w. Если 
с помощью этой утилиты можно установить подключение, а из приложения Delphi 
нельзя, то, вероятно, имеется ошибка в настройке псевдонима BDE. Вернитесь к 
программе BDE Administrator и проверьте значения параметров (в частности, имя сервера). 
    2.    Если связь с сервером не удается установить даже с помощью утилиты 
ISQL/w, то возможна проблема с протоколом. Если для подключения к серверу 
используется протокол TCP/IP, то попытайтесь замерить пропускную способность 
(pinging) линии связи с компьютером-сервером с помощью утилиты PING, 
поставляемой в составе системам Windows 95 и Windows NT. Для вызова 
используйте имя компьютера, указанное в файле HOSTS, и его IP-адрес. 
    Если для подключения к серверу используются поименованные каналы, то 
воспользуйтесь командой net view \\имя_сервера, где идентификатор имя_сервера 
— это имя сервера Windows NT, на котором работает сервер SQL. Если эта команда 
выполняется успешно, то используйте команду netuse \\имя_сервера\1РС5, заменив 
идентификатор имя__сервера подлинным именем сервера. Если обе команды 
выполняются успешно, то испробуйте утилиты makepipe/readpipe. Запустите 
утилиту makepipe на сервере, а затем запустите на компьютере-клиенте утилиту 
readpipe с параметрами /Sservername /Dteststring. Утилиты makepipe/readpipe 
предназначены для проверки целостности служб поименованных каналов. Для 
завершения работы утилиты makepipe нажмите <Ctrl+C> или <Ctrl+Break>. Если 
какой-либо из перечисленных тестов дает отрицательный результат, то 
проконсультируйтесь с системным администратором Windows NT. Возможно, на 
сервере имеются неполадки в службах поименованных каналов. 

    Глава 15. Microsoft SQL Server 307 

    3.    Если обращение к компьютеру через утилиту PING по IP-адресу 
происходит корректно, а по имени — нет, то проблема, вероятно, связана с 
файлом HOSTS. Временное решение этой проблемы — изменить строку подключения 
таким образом, чтобы вместо имени использовался IP-адрес. Проблему с файлом 
HOSTS необходимо решить как можно быстрее, поскольку подключение к удаленным 
компьютерам по имени является более гибким и удобным способом. 
    4.    Если для подключения к серверу используется протокол IPX, то 
проверьте, доступен ли компьютер-сервер с компьютера-клиента. Это делается 
путем запуска утилиты командной строки isql   /L. При j использовании 
параметра /L данная утилита обращается к функции dbservernum, которая выводит 
| список всех доступных серверов из Bindery. Если вашего сервера нет в списке, 
то возможна неполадка в сети. Для ее обнаружения проконсультируйтесь с 
администратором сети. 
    5.    Если используется протокол TCP/IP, и вызов через PING как по имени, 
так и по IP-адресу не происходит, то, по всей видимости, имеется неполадка в 
сети. Проверьте такие очевидные вещи, как правильность IP-адреса сервера. 
Попробуйте обратиться по фиктивному адресу TCP/IP, 127.0.0.1, чтобы проверить 
правильность работы стека TCP/IP. Этот адрес предназначен для имитации 
обращения по сети к самому вызывающему компьютеру. Если такой вызов не 
срабатывает, то в конфигурации протокола имеются серьезные ошибки. Для их 
устранения необходимо проконсультироваться с администратором сети. 
    6.    Если подключение через ISQL/W не срабатывает, но вызов через PING 
происходит корректно, то проверьте, является ли порт, указанный в строке 
подключения, портом ввода сервера базы данных. Для определения необходимого 
номера порта следует обратиться к администратору базы данных. 
    7.    Если в конфигурации параметров на первый взгляд нет ошибок, то можно 
попробовать сменить протокол (в том случае, если имеется выбор). Поскольку 
сервер можно настроить на прием сообщений сразу по нескольким протоколам, его 
можно временно использовать с работающим протоколом, пока не будет обнаружена 
причина неполадок. 
    В системе Windows NT имеется совершенно незаменимый инструмент отладки — 
программа Windows NT Diagnostics, находящаяся в папке Administrative Tools. С 
ее помощью можно взглянуть на ресурсы компьютера, так сказать, с высоты 
птичьего полета. Она представляет собой версию для Windows популярной 
DOS-программы MSD (Microsoft Diagnostics), которая много лет поставлялась 
вместе с различными версиями DOS и Windows. Имя выполняемого файла программы — 
WINMSD.ЕХЕ; он находится в каталоге \wiNNT\SYSTEM32. 

    Настройка псевдонима ВОЕ 

    Как только сервер базы данных становится доступным для подключения по 
сети, наступает очередь создания псевдонима BDE для того, чтобы приложение 
Delphi могло обращаться к серверу. Эта тема освещается в другом месте книги, 
однако здесь приводится ее краткий обзор — как удобства, так и для раскрытия 
взаимосвязи между настройкой драйверов баз данных и настройкой псевдонимов BDE. 
    Псевдонимы BDE создаются либо с помощью утилиты BDE Administrator, либо с 
помощью приложения Delphi Database Explorer. Приведенные ниже инструкции 
относятся к программе BDE Administrator. 
    1.   Запустите средство BDE Administrator, щелкните правой кнопкой мыши на 
вкладке Databases и выберите из меню пункт New. После появления диалогового 
окна New Database Alias выберите в списке Database Driver Name пункт MSSQL и 
щелкните на кнопке ОК. 
    2.    После добавления нового псевдонима введите его имя. 
    3.    Настройте параметры нового псевдонима на вкладке Definition. 
    4.    Щелкните на параметре SERVER NAME и установите его значение равным 
имени вашего сервера SQL. Это должно быть то же самое имя, которое 
использовалось в утилите SQL Client Configuration. 
    5.    По желанию можно указать в строке USER NAME имя пользователя 
сервера, автоматически регистрируемого в системе по умолчанию. Введенное имя 
будет отображаться при каждом появлении диалогового окна регистрации, 
используемого Delphi для подключения к серверу базы данных. 
    Для сохранения изменений и выхода из программы BDE Administrator щелкните 
на кнопке Apply. 

    308 Часть III. Справочные материалы 

    Специальные параметры псевдонима ВОЕ 

    Ниже перечислены некоторые параметры псевдонима BDE, которые могут 
оказаться полезными при подключении к серверу Microsoft SQL Server. Хотя для 
начала можно принять значения этих параметров, предложенные по умолчанию, 
полезно знать, какие средства имеются в вашем распоряжении при возникновении 
тех или иных проблем (особенно при отладке и выявлении ошибок). Обратите 
внимание, что некоторые из этих параметров относятся к уровню драйверов. 
Доступ к параметрам этого уровня осуществляется через вкладку Configuration 
программы BDE Administrator. 

    Параметр DRIVER FLAGS и обработка объектов в бинарном формате 

    Операции чтения и записи объектов в бинарном формате (BLOB — Binary Large 
OBjects) иногда вызывают аварийное завершение приложения Microsoft SQL Server. 
Если это случилось, попробуйте изменить значение параметра DRIVER FLAGS вашего 
псевдонима с нуля на единицу. Таким образом можно решить проблему, но учтите, 
что при этом могут возникнуть задержки при операциях записи объектов BLOB. 

    APPLICATION NAME 

    В качестве значения параметра APPLICATION NAME можно указать имя процесса, 
которое затем будет появляться в списке системных процессов SQL Server. Таким 
образом можно отличить свой процесс от других. 

    CONNECT TIMEOUT 

    Этот параметр предназначен для выбора интервала времени, в течение 
которого клиентная часть приложения ожидает установления связи с сервером SQL. 
По умолчанию значение этого параметра равно 60 с. Увеличение данного значения 
может привести к повышению вероятности подключения рабочих станций-клиентов 
(особенно тех, которые работают с серверами через глобальные сети). 

    HOST NAME 

    Значение данного параметра — это имя рабочей станции, которое появляется в 
таблице системных процессов SQL Server. Благодаря этому можно различить 
подключения друг от друга, например, в листингах, генерируемых хранимой 
процедурой sp_who. 

    NATIONAL LANG NAME 

    В этом параметре указывается язык, который должен использоваться для 
сообщений об ошибках. Если язык не указан, используется язык, предусмотренный 
в SQL Server по умолчанию. 

    TDS PACKET SIZE 

    Этот параметр используется для выбора размера пакетов Tabular Data Stream 
(TDS). TDS — это протокол высокого уровня, который используется в SQL Server 
для обмена данными с клиентами. Хотя в программе BDE Administrator можно 
указать любой размер пакета в диапазоне от 0 до 65535 байт, рекомендуется 
ограничиться диапазоном, поддерживаемым в SQL Server: от 512 до 32767 байт. 
Может оказаться, что увеличение размера пакета приводит к повышению общей 
пропускной способности системы из-за снижения количества пакетов, необходимого 
для передачи больших объемов данных (например, полей типа BLOB). По умолчанию 
размер пакета установлен равным 4096 байт; для оптимальной производительности 
рекомендуется выбирать размер между 4096 и 8192. 
    Для определения текущего максимального размера пакета, поддерживаемого 
сервером, можно использовать хранимую процедуру SQL Server sp_conf igure. Для 
отображения списка текущих размеров сетевых пакетов введите команду 
sp_configure 'network packet size'. Необходимо установить значение этого 
параметра, прежде чем изменять соответствующий параметр в программе BDE 
Administrator. Если значения параметра TDS PACKET SIZE в программе BDE 
Administrator и параметра network packet size в SQL Server не совпадают, то 
могут возникнуть следующие ошибки. 

    Q   Error:   unknown  user  name   or  password 
    Q   Server  error —  4002   Login  failed 
    Q   Server  error —   20014   Login   incorrect 

    Глава 15. Microsoft SQL Server 309 

    На заметку 

    Для изменения размера пакетов, установленного по умолчанию, необходим 
протокол TDS версии 5 или более поздней. 

    DATABASE NAME 

    Этот параметр используется для указания имени базы данных SQL, к которой 
необходимо подключиться. При создании псевдонимов SQL Server обычной практикой 
является выбор отдельного псевдонима для каждой отдельной базы данных. Чтобы 
указать базу данных для каждого псевдонима, используется параметр DATABASE 
NAME. Хотя этот параметр можно оставить пустым для выбора базы данных сервера 
по умолчанию, этого делать не рекомендуется — такая двусмысленность может 
привести к конфликтам, а также к необходимости обращаться к системной таблице 
регистрации для выяснения соответствия между именами базами данных и их псевдонимами. 

    BLOB EDIT LOGGING 

    Установив этот параметр равным false, можно отключить контроль изменений в 
полях BLOB. Данное значение параметра минимизирует потребность в ресурсах 
памяти и дискового пространства, а также улучшает производительность системы. 
Объекты BLOB будут передаваться с использованием утилиты bulk copy, так что 
необходимо будет включить режим select into/bulk copy в базе данных 
назначения, например, с помощью хранимой процедуры sp_dboption. 

    MAX QUERY TIME 

    Этот параметр задает интервал времени, в течение которого драйверы SQL 
Links ожидают завершения асинхронного запроса, прежде чем отменить его. Для 
драйверов Microsoft и Sybase SQL Links в настоящее время по умолчанию 
предусмотрен синхронный режим запроса. Для выбора времени ожидания по 
синхронному запросу используется параметр TIMEOUT вкладки MSSQL driver. 
Асинхронное выполнение запросов включается путем увеличения значения параметра 
DRIVER FLAG вкладки MSSQL driver на 2048. По умолчанию драйвер SQL Links 
предоставляет запросу для его завершения пять минут (300 секунд). 

    Азы SQL 

    Хотя программный продукт и называется SQL Server, "сервировать" средства 
SQL вам в значительной мере придется самостоятельно. SQL Server — это на самом 
деле сервер баз данных, а не сервер SQL, просто общение с ним происходит с 
использованием SQL. В этом разделе дается введение в диалект Transact-SQL, 
используемый для работы с SQL Server, а также затрагиваются некоторые 
возможности и особенности, которые отличают его от реализаций SQL других 
производителей. Предполагается, что ваш сервер находится в активном состоянии, 
и вы знаете, как связаться с ним с помощью утилиты ISQL. 

    Создание базы данных 

    У вас уже, наверное, есть база данных, содержащая несколько временных 
таблиц для работы с примерами данной главы. Если нет, то такую базу данных 
нетрудно создать. В SQL база данных создается командой CREATE DATABASE. Точный 
синтаксис команды зависит от поставщика данной версии. Вот базовый синтаксис 
SQL Server. 

    CREATE   DATABASE  имяБД  ON  устройство_данных=размер LOG  ON  устройство_регистрации=размер 

    Прежде чем создавать базу данных, необходимо узнать, на каких логических 
устройствах ее можно располагать. С помощью логических устройств SQL Server 
при создании базы данных можно избежать использования имен физических дисков. 
    Для создания устройств SQL Server используется команда DISK INIT. Вот 
пример ее применения. 

    DISK INIT 
    name='saldatOO', 
    physname='с:\mssql\data\saldatOO.dat', 
    vdevno=5, 
    size=2048 

    310 Часть III. Справочные материалы 

    В качестве значения параметра name указывается имя логического устройства. 
Параметр physname используется для подробного описания местонахождения и имени 
файла устройства. Если устройство создается в корневом каталоге диска Windows 
NT, то достаточно указать букву логического диска. Параметр vdevno содержит 
номер логического виртуального устройства. Единственное требование, 
предъявляемое к нему, — уникальность номера для каждого отдельного устройства, 
существующего на сервере. Диапазон допустимых значений — от 1 до 255. Значение 
0 зарезервировано для основного устройства. Параметр size содержит количество 
двухкилобайтовых страниц, занимаемых устройством. Например, если создается 
устройство емкостью 4 Мбайт (4096 Кбайт), то следует указать значение 2048. 
Устройства данных и регистрации создаются одинаковыми командами. Вот пример 
команды создания устройства регистрации SQL Server. 

    DISK   INIT 
    name='sallogOO', 
    physname='с:\mssql\data\sallogOO.dat', 
    vdevno=6, 
    size=512 

    Создание виртуальных устройств с помощью команды DISK INIT происходит 
гораздо быстрее в файловой системе NTFS, чем в FAT. В системе FAT новое 
устройство сразу после создания должно инициализироваться нулями, что для 
больших устройств занимает некоторое время. В противоположность этому создание 
устройств в системе NTFS происходит мгновенно, поскольку нет необходимости в 
их инициализации. После создания устройств можно создавать саму базу данных, 
которая будет на них храниться. Вот пример команды CREATE  DATABASE, 
использующей только что созданные устройства: 

    CREATE DATABASE SALES ON saldatOO=4 LOG ON sallogOO=l 

   Если у вас до сих пор не было базы данных для проработки примеров этого раздела, 
то не мешкайте — создайте ее прямо сейчас. 

    Команда USE 

    Команда USE изменяет контекст активной базы данных или, проще говоря, она 
переключает текущую базу данных. Команда имеет следующий синтаксис: 

    USE  имяБД 

    Обратите внимание, что новую текущую базу данных можно также выбрать из 
списка DB утилиты ISQL. Создав с помощью утилиты ISQL новую базу данных, 
раскройте этот список и выберите из него пункт <Refresh>, чтобы обновить 
перечень доступных баз данных. После повторного раскрытия списка в нем 
появится созданная база данных. 

    Создание таблиц 

    После создания базы данных и выполнения команды USE для ее активизации 
можно приступать к созданию объектов базы данных. Практически все основные 
понятия реляционных баз данных можно продемонстрировать на примере набора из 
трех таблиц. Для работы с примерами этой главы начните с создания трех таблиц, 
приведенных ниже. Таблицы создаются оператором SQL CREATE TABLE. Для создания 
таблицы CUSTOMER введите в окне утилиты ISQL следующую команду. 

    CREATE   TABLE   CUSTOMER 
    ( 
    CustomerNumber 
    LastName 
    FirstName 
    StreetAddress 
    City 
    State 
    Zip 
    int	NOT NULL, 
    char (30)	NULL, 
    char (30)	NULL, 
    char (30)	NULL, 
    char (20)	NULL, 
    char (2)	NULL, 
    char (10)	NULL 

    Глава 15. Microsoft SQL Server 311 

    Затем с помощью следующей команды создайте таблицу SALE. 

    CREATE   TABLE   SALE ( 
    SaleNumber	int                 NOT  NULL, 
    SaleDate                     datetime     NULL, 
    CustomerNumber        int                 NOT  NULL, 
    ItemNumber                 int                 NOT  NULL, 
    Amount                         money ) 

    Итак, таблица SALE создана. Осталась всего одна таблица — ITEM, и она 
создается следующей командой. 

    CREATE TABLE ITEM ItemNumber Description Price )	int char (30) money	NOT 
NULL, NULL, NULL 

    Добавление столбцов 

    Для добавления столбцов в существующую таблицу используется команда SQL 
ALTER TABLE. Microsoft SQL Server относится к числу тех немногих серверов, 
которые не поддерживают модификацию или сбрасывание столбцов таблиц. Следующая 
команда показывает пример добавления столбца в таблицу. 

    ALTER TABLE CONTACT 
    ADD PhoneNumber char (10) NULL 

    Обратите внимание: нельзя добавить столбец со значением NOT NULL в 
таблицу, где уже есть строки, поскольку сразу же после добавления в таблицу 
этот столбец должен допускать значения NULL. 

    Ограничения 

    Ограничением (constraint) называется механизм определения допустимых типов 
данных данного столбца. С помощью ограничений можно задавать значения для 
полей по умолчанию. Ограничения могут задаваться непосредственно при создании 
таблицы с помощью команды CREATE TABLE или впоследствии, с помощью команды 
ALTER TABLE. Вот пример ограничения первичного ключа. 

    ALTER   TABLE   CUSTOMER 
    ADD   PRIMARY  KEY    (CustomerNumber) 

    Приведенная команда добавляет в таблицу CUSTOMER ограничение типа 
первичного ключа, назначая первичным ключом таблицы поле CustomerNumber. В 
результате для таблицы создается уникальный индекс, использующий в качестве 
ключа столбец CustomerNumber. Обратите внимание, что в качестве первичного 
ключа нельзя использовать столбец, допускающий использование значения NULL. 
    Ограничение внешнего ключа определяет столбец одной таблицы, значения 
которого должны существовать во второй таблице, называемой внешней. В отличие 
от первичного ключа, внешний ключ не является уникальным индексом строки. 
Наоборот, ключевые столбцы должны быть первичными (уникальными) ключами во 
внешней таблице. При добавлении ограничения внешнего ключа в таблицу SQL 
Server автоматически строит вторичный ключ по ключевым полям. Вот пример 
соответствующей команды. 

    ALTER  TABLE   SALE 
    ADD  FOREIGN  KEY   (CustomerNumber)   REFERENCES   CUSTOMER 

    Эта ограничение назначает поле CustomerNumber таблицы SALE внешним ключом, 
который ссылается на аналогичное поле таблицы CUSTOMER. Это означает, что 
введенные в таблицу SALE номера покупателей должны существовать в таблице 
CUSTOMER, а также то, что номера, использующиеся в таблице SALE, нельзя 
удалить из таблицы CUSTOMER. Такая возможность обеспечения наличия связи между 
двумя таблицами путем ее изначального определения называется декларативной 
ссылочной целостностью (declarative referential integrity). Этот термин 
означает, что обеспечение целостности ссылок таблиц друг на друга выполняется 
при их создании или объявлении на уровне сервера базы данных, а не на уровне приложения. 

    312	Часть III. Справочные материалы 

    Третьим типом ограничений является сравнение значений столбца со списком 
предварительно определенных значений. Вот пример задания такого ограничения. 

    ALTER   TABLE   CUSTOMER 
    ADD  CONSTRAINT   INVALID_STATE   CHECK   (State   in   ('OK',    'AR',    'MO')) 

    Обратите внимание на негативный смысл имени, выбранного для ограничения. 
Это делается для того, чтобы при выдаче сообщения о нарушении установленного 
ограничения пользователь мог бы определить источник проблемы по одному лишь 
имени ограничения. Кроме того, таким образом можно сэкономить усилия при 
замене обработчика исключительной ситуации, генерируемой Delphi по умолчанию, 
на созданный вами. 

    Тестирование ограничений 

    Необходимо тестировать каждое ограничение, налагаемое на таблицу. Чтобы 
проделать это, попытайтесь внести в базу данных значение, которое запрещено 
наложенным ограничением. Например, для тестирования описанного выше 
ограничения INVALID_STATE введите в окне утилиты ISQL следующую команду. 

    INSERT   INTO  CUSTOMER   (CustomerNumber,   State) VALUES    (123,'CA') 

    Поскольку ранее наложенное ограничение устанавливает, что в качестве 
названия кода штата должны использоваться только значения ' ОК', ' AR' и ' 
МО', попытка ввода приведенной выше команды должна закончиться сообщением об ошибке. 
    Если заданное ограничение не функционирует как положено, то проверьте, 
правильно ли оно добавлена и корректно ли оно выполняет проверку данных. 

    Создание индексов 

    Индексы на сервере SQL создаются командой CREATE  INDEX. Вот ее базовый синтаксис. 

    CREATE   INDEX   SALE02   ON   SALE    (SaleDate) 

    Здесь SALE02 — имя нового индекса, SALE — имя таблицы, по которой строится 
индекс, а SaleDate — ключ индекса. Обратите внимание, что имена индексов SQL 
Server должны быть уникальны по всей базе данных, в которой они находятся. 
    С помощью варианта данной команды CREATE UNIQUE INDEX создается индекс, не 
допускающий повторений. 

    CREATE UNIQUE INDEX SALE01 ON SALE (SaleNumber) 

    Вставка данных 

    Оператор SQL INSERT используется для добавления данных в таблицу базы 
данных SQL Server. С помощью ключевого слова VALUES оператора INSERT можно 
вставить одну строку; если же выбрать несколько строк из другой таблицы, то 
можно вставить все эти строки одновременно. Для добавления данных в каждую из 
трех таблиц используются команды, приведенные ниже. Вначале вставляются три 
строки в таблицу CUSTOMER. 

    LastName,   FirstName,   StreetAddress,   City,   State, 
    INSERT   INTO  CUSTOMER   (CustomerNumber, Zip) 
    VALUES(1,'Doe','John','123 Sunnylane' 
    INSERT INTO CUSTOMER (CustomerNumber, LastName, FirstName, StreetAddress, 
City, State, Zip) 
    VALUES(2,'Doe','Jane',423 Sunnylane 
    INSERT INTO CUSTOMER Zip) 
    VALUES(3,'Philgates','Buck','57 Riverside','Reo 
    'Anywhere','MO','73115' 
    'Anywhere', 'MO', '73115' ; 
    (CustomerNumber, LastName, FirstName, StreetAddress, City, State, '65803' ) 

    После этого добавляются три строки в таблицу ITEM. 

    INSERT	INTO ITEM	(ItemNumber,	Description,	Price)	VALUES(1001,'Zoso LP',13.45) 
    INSERT	INTO ITEM	(ItemNumber,	Description,	Price)	VALUES(1002,'White LP',67.90) 
    INSERT	INTO ITEM	(ItemNumber,	Description,	Price)	VALUES(1003,'Bad Co. LP',11.45) 

    Глава 15. Microsoft SQL Server 313 

    Наконец, добавляются четыре строки в таблицу SALE.	1 

    INSERT INTO SALE (SaleNumber, SaleDate, CustomerNumber, ItemNumber, 
Amount)  VALUES(101,'10/18/90',1,1001,13.45) I 
    INSERT INTO SALE (SaleNumber, SaleDate, CustomerNumber, ItemNumber, 
Amount) I , VALUES(102, '02/27/92', 2,1002, 67. 90) I 
    INSERT INTO SALE (SaleNumber, SaleDate, CustomerNumber, ItemNumber, 
Amount) " VALUES(103,'05/20/95',3,1003,11.45) 
    INSERT INTO SALE (SaleNumber, SaleDate, CustomerNumber, ItemNumber, 
Amount) VALUES(104,'11/27/97',1,1002,67.90) 

    Обратите внимание, что при вводе списка столбцов нет необходимости 
включать все столбцы или соблюдать порядок их следования в таблице, однако 
список значений должен соответствовать содержанию и порядку списка столбцов, 
указанных в команде INSERT, например: 

    INSERT INTO ITEM (Price, ItemNumber) VALUES(13.45,1001) 


    Команда UPDATE 

    Команда SQL UPDATE используется для изменения данных, которые уже 
находятся в таблице. Оператор UPDATE может содержать ключевое слово WHERE, 
которое определяет, какие именно строки следует модифицировать. Вот синтаксис 
данной команды: 

    UPDATE CUSTOMER SET Zip='65803' WHERE City='SpringField' 

    Наличие ключевого слова WHERE в операторе UPDATE может привести к тому, 
что в таблице будет изменена, например, всего одна строка; в этом случае для 
изменения всех строк таблицы достаточно убрать ключевое слово WHERE: 

    UPDATE CUSTOMER SET State='MO' 

    Столбец можно модифицировать также с использованием значений других 
столбцов таблицы, или даже его собственных значений. Например, необходимо 
увеличить цену каждого наименования товара в таблице ITEM на семь процентов. 
Для этого команда UPDATE используется следующим образом. 

    UPDATE   ITEM 
    SET Price=Price+(Price*.07) 


    Команда DELETE 

    Для удаления строк из таблицы используется команда DELETE. Чтобы удалить 
все строки, используйте следующий синтаксис. 

    DELETE FROM CUSTOMER 

    Команда DELETE может содержать ключевое слово WHERE для отбора отдельных строк: 

    DELETE FROM CUSTOMER WHERE LastNameO'Doe' 


    Управление транзакциями 

    Транзакцией (transaction) называется группа изменений в базе данных. 
Пользовательские транзакции инициируются с помощью команды BEGIN TRANSACTION. 
Все внесенные в ходе транзакции изменения заносятся в базу данных с помощью 
команды COMMIT, а отменяются командой ROLLBACK. Обе эти команды применимы 
только к изменениям, внесенным в базу данных после последней команды COMMIT; 
все сделанные до этого изменения отменить нельзя. 

    На заметку 

    1~Наряру с обычными операторами языка управления данными (DML — Data 
Manipulation Language), например INSERT, UPDATE и DELETE, в пользовательские 
транзакции можно включать также операторы языка оп-эр^деления/данных|^DL: 
-^ipata^etio.itip^Larjguaae). Если отменить транзакцию, в ходе которой создается 

    314 Часть III. Справочные материалы 

    объект, то объект уничтожается. Это свойство можно использовать для 
сохранения или сброса содержимсР" ; го рабочей таблицы в зависимости от 
успешной вставки в нее каких-либо данных. Так, если в одну транзакцию включены 
операторы CREATE TABLE и INSERT, то при неудачном выполнении оператора INSERT 
таблица автоматически уничтожается. 

    Команда SELECT 

    По команде SQL SELECT отображается содержимое таблицы. Для примера давайте 
проверим содержимое трех таблиц, созданных в настоящей главе, с использованием 
этой команды. Введите для каждой таблицы команду SELECT * FROM имя_таблицы, 
заменив имя_таблицы на фактическое имя (т.е. на CUSTOMER, SALE или ITEM). К 
настоящему моменту в каждой из трех таблиц должно быть по крайней мере по три 
строки. Проверьте это с помощью оператора SELECT. 
    По команде SELECT * выводятся все столбцы всех строк таблицы. Чтобы 
выбрать отдельные поля, замените звездочку на список полей, отделенных друг от 
друга запятыми: 

    SELECT   CustomerNumber,    LastName,    State   FROM  CUSTOMER 


    Выражения в столбцах 

    Каждый пункт в списке полей оператора SELECT может представлять собой не 
просто название столбца, но выражение (expression column), включающее 
арифметические операции, константы и функции. Вот пример оператора SELECT, 
который возвращает записи из таблицы SALE с торговой наценкой $15: 

    SELECT   SaleNumber,SaleDate,Amount+15  AmountPlusShipPING FROM   SALE 


    Вычисляемые столбцы 

    Вычисляемые столбцы (aggregate column) — это функции, применяемые для 
выполнения каких-то вычислений над некоторым набором данных. В качестве таких 
функций могут служить COUNT, SUM, AVG, MIN, MAX и др. Рассмотрим несколько 
примеры их использования. Следующий запрос подсчитывает количество 
покупателей, внесенных в таблицу. 

    SELECT COUNT(*) FROM CUSTOMER 

    По данному запросу выводится сумма максимальной продажи. 

SELECT  MAX(Amount)    FROM   SALE 

    Наконец, следующий запрос возвращает общую сумму всех продаж. 

    SELECT SUM(Amount) FROM SALE 


    Ключевое слово WHERE 

    Ключевое слово WHERE используется для задания дополнительных условий на 
данные, выбираемые оператором SELECT. Вот некоторые примеры. Следующий 
оператор возвращает список клиентов, живущих в шт. Миссури (код штата — МО). 

    SELECT * FROM CUSTOMER WHERE State='MO' 

    Следующий запрос возвращает список тех покупателей, у которых в поле 
почтового адреса имеется строка Sunny: 

    SELECT * FROM CUSTOMER 
    WHERE StreetAddress LIKE '%Sunny%' 

    Обратите внимание, что сравнение производится с учетом верхнего и нижнего 
регистра символов. Если это не нужно, то используйте функцию UPPER для 
преобразования всех символов полей к верхнему регистру. Следующий оператор 
возвращает список продаж на сумму более $500. 

    SELECT * FROM SALE WHERE Amount > 500 

    А этот запрос возвращает список только тех продаж, которые имели место с 
18 октября 1990 г. по 20 мая 1995 г. включительно. 

    SELECT * FROM SALE WHERE SaleDate BETWEEN '10/18/90' AND '05/20/95' 
    
    Глава 15. Microsoft SQL Server 315 

    Объединения 

    Ключевое слово WHERE используется также для создания объединения (join) 
одной таблицы с другой И| образования составных наборов данных. Присоединение 
одной таблицы к другой с помощью WHERE требу-| ет двух изменений в базовом 
синтаксисе команды SELECT. Первое изменение состоит в использовании операторе 
SELECT ключевого слова FROM, с помощью которого указываются дополнительные 
таблицы^ второе — в применении операции сравнения (=) для создания выражения, 
которое с помощью ключев слова WHERE определяет поля, используемые для 
объединения указанных таблиц. Вот пример: 

    SELECT  CUSTOMER.CustomerNumber,   SALE.Amount FROM  CUSTOMER,    SALE 
WHERE   CUSTOMER.CustomerNumber=SALE.CustomerNumber 

    Обратите внимание на то, что списке, заданном с помощью ключевого слова 
FROM, указана таблица s; также на то, что для объединения таблиц CUSTOMER и 
SALE используется знак равенства между их пс CustomerNumber. Таблица, 
расположенная слева от знака равенства, называется внешней (outer) а справа| 
внутренней (inner). Их также называют соответственно левой (left) и правой 
(right) таблицами, что указывает на 1 расположение в левом объединении (left 
join) — самом распространенном типе объединений в запросах SQL. 

    Различие между внутренними и внешними объединениями 

    Упомянутые в предыдущем разделе левые объединения известны также  под 
формальным названи^ внутренних объединений (inner join).  Внутренние 
объединения возвращают строки таблицы только в случае,  если  выполняется 
условие  объединения.   В  противоположность этому,  во внешнем объедине 
(outer join) строки возвращаются независимо от выполнения условия, однако если 
условие не выполняе ся, то в качестве значений полей внутренней таблицы в 
выходной набор данных помещаются значеь NULL. Вот пример внешнего объединения 
в языке Transact-SQL. 

    SELECT   CUSTOMER.CustomerNumber,    SALE.Amount FROM   CUSTOMER,    SALE 
WHERE   CUSTOMER.CustomerNumber*=SALE.CustomerNumber 

    ANSI-синтаксис объединений 

    Помимо собственного синтаксиса, для построения объединений  система  SQL  
Server поддерживает^ ANSI-синтаксис. Для левого внутреннего объединения он 
выглядит следующим образом. 

    SELECT   CUSTOMER.CustomerNumber,    SALE.Amount FROM   CUSTOMER   LEFT   
JOIN   SALE ON  CUSTOMER.CustomerNumber=SALE.CustomerNumber 

    Для левого внешнего объединения используется следующий синтаксис. 

    SELECT   CUSTOMER.   CustomerNumber,    SALE.Amount FROM   CUSTOMER   LEFT 
  OUTER   JOIN   SALE ON   CUSTOMER.CustomerNumber=SALE.CustomerNumber 

    Для построения правых внешних объединений достаточно заменить LEFT на 
RIGHT. Обратите внимание, что правые и левые внутренние объединения — это 
фактически одно и то же, и между ними нет ж: каких синтаксических отличий. 

    Многоуровневые объединения 

    Многоуровневым объединением (multi-tier join) называется объединение, 
включающее более двух таблш С помощью таких объединений таблица А 
присоединяется к таблице Б, которая в свою очередь присоедь няется к таблице 
в. Рассмотрим следующий запрос. 

    SELECT  C.LastName,С.FirstName,I.Description,S.Amount FROM   CUSTOMER   C, 
SALE   S, ITEM   I WHERE C.CustomerNumber=S.CustomerNumber AND S.ItemNumber=I.ItemNumber 

    В данном запросе таблицы CUSTOMER и SALE объединяются по общему ключу — 
пол;-CustomerNumber. После этого по общему ключу, полю ItemNumber, 
объединяются таблицы SALE и ITE: В результате все три таблицы объединяются в 
один общий набор данных. 

    316	Часть III. Справочные материалы 316	Часть III. Справочные материалы 

    Самообъединения 

    Помимо объединения с другими таблицами, любая таблица может быть 
объединена сама с собой. Этот тип объединений называется рефлексивным 
(reflexive) или самообъединением (self-join). Рассмотрим следующий запрос. 

    SELECT  S.CustomerNumber,   S.Amount,    (S.Amount   /   
SUM(S2.Amount))*100   Percentage FROM  SALE   S, SALE   S2 
    WHERE  S.CustomerNumber=S2.CustomerNumber GROUP  BY  S.CustomerNumber,   S.Amount 

    Целью этого запроса является получение информации о продажах каждому 
отдельному покупателю, со сравнением объема каждой продажи и общего объема 
продаж данному клиенту. Единственным способом проделать все это в одном 
операторе SELECT является использование самообъединений. Данные собираются и 
группируются по покупателям, а затем таблица SALE присоединяется сама к себе 
для выяснения общего объема продаж каждому покупателю. После этого объем 
текущей продажи делится на общий объем и преобразуется к процентному значению. 

    Тета-объединения 

    В тета-объединениях (theta join) две таблицы объединяются с использованием 
операций сравнения, отличных от проверки на равенство. Обычно в таких 
объединениях используется операция проверки неравенства (о). Ниже приводится 
пример тета-объединения; это разновидность запроса, использованного выше для 
демонстрации самообъединений. 

    SELECT  С.CustomerNumber,S.Amount,SUM(S2.Amount)   OTHERS 
    FROM  CUSTOMER  C, 
    SALE   S, 
    SALE   32 
    WHERE  C.CustomerNumber=S.CustomerNumber 
    AND  С.CustomerNumber<>S2.CustomerNumber 
    GROUP  BY  C.CustomerNumber,   S.Amount 

    Фактически данный запрос содержит два объединения. Во-первых, для 
получения всех продаж каждому покупателю объединяются таблицы CUSTOMER и SALE. 
Во-вторых, используется тета-объединение для получения всех продаж, которые не 
связаны с данным покупателем. Поскольку для обращения к одной и той же таблице 
SALE используются два разных типа объединений, для нее введены два разных псевдонима. 

    Полные объединения 

    В полном объединении (full join) строки двух таблиц обрабатываются без 
использования условий, задаваемых с помощью ключевого слова WHERE. Это 
объединение применяется для получения данных из таблиц с нестрогими связями. 
Если ни одна из таблиц не обязана содержать те строки, которые вам нужны, то 
можно объединить их во внешнее объединение для получения всех строк. Вот 
пример такого объединения: 

    SELECT   ITEM.Description,   ITEM.Price,   SALE.Amount 
    FROM  SALE   FULL  OUTER  JOIN   ITEM 
    ON   ITEM.ItemNumber=SALE.ItemNumber 


    Декартово произведение 

    Декартово произведение (Cartesian product) — это произведение всех строк 
одной таблицы на строки другой таблицы. Возникновение декартова произведения 
обычно возникает по недоразумению, в результате пропуска или неправильного 
использования объединений между таблицами. Вот пример: 

    (SELECT   SALE.SaleNumber,   ITEM.ItemNumber FROM  SALE,    ITEM ORDER BY  
SaleNumber,   ItemNumber 

    	Получение декартового произведения для больших таблиц может надолго 
загрузить сервер. Так надолго, что иногда приходится отменять запрос или 
отключаться от сервера. Поэтому декартовых произведений следует по возможности 
избегать, особенно в больших таблицах. 

    Глава 15. Microsoft SQL Server     317 

    Вложенные запросы 

    Вложенным запросом (subquery) называется оператор SELECT, указанный после 
ключевого слова WHERE другого оператора SELECT. Обычно вложенные запросы 
используются для получения списка данных, по которому затем производится новый 
поиск в таблице. 

    SELECT   *   FROM  CUSTOMER 
    WHERE  CustomerNumber   IN(SELECT  CustomerNumber   FROM  SALE) 

    Некоторые операторы, такие как ANY, ALL, SOME, EXISTS и SINGULAR, работают 
исключительно во вложенных запросах. Хотя ключевое слово ALL используется 
также в операторе SELECT, как отдельный оператор оно применяется только во 
вложенных запросах. 

    GROUP  BY 

    Поскольку SQL является языком запросов, ориентированным на множества, 
операторы группировки данных встроены непосредственно в язык. Программисты, 
работающие с другими СУБД, нередко находят такой подход необычным ввиду своей 
привычки работать с данными построчно. Построчный перебор таблицы для 
получения некоторой итоговой информации — довольно распространенный способ 
обработки данных в локальных СУБД для персональных компьютеров. К счастью, в 
SQL это не так. Один-единственный оператор SQL может делать то же самое, что и 
10, а то и 50, строк кода dBASE "Виновниками" этого чуда являются ключевое 
слово GROUP BY оператора SELECT и функции вычисляемых столбцов SQL. Вот пример 
использования элемента GROUP BY. 

    SELECT   CUSTOMER.CustomerNumber,   sum(SALE.Amount)   TotalSale 
    FROM   CUSTOMER,    SALE 
    WHERE  CUSTOMER.CustomerNumber=SALE.CustomerNumber 
    GROUP  BY  CUSTOMER.CustomerNumber 

    Данный запрос возвращает список всех покупателей вместе с общим объемом 
продаж по каждому покупателю. 
    Как определить, какие поля нужно перечислять после ключевого слова GROUP 
BY? Работая с SQL Server, необходимо группировать строки по всем не являющимся 
вычисляемыми столбцам, включенным в список оператора SELECT. Использование 
ключевого слова GROUP BY подразумевает наличие в списке полей оператора SELECT 
хотя бы одного вычисляемого столбца; SQL Server просто не даст вам вставить 
элемент GROUP BY, если такого столбца не будет. 

    HAVING 

    Ключевое слово HAVING оператора SELECT используется для наложения условий 
на строки, возвращаемые при использовании ключевого слова GROUP BY. Результат 
его совместной работы с GROUP BY напоминает результат работы оператора SELECT 
с ключевым словом WHERE, с той разницей, что HAVING выполняет операции над 
строками возвращаемого набора данных, а не над строками таблицы. 
    Обычно бывает удобнее налагать условия на строки таблицы, чем на строки 
возвращаемого набора данных. Как правило, использование HAVING менее 
эффективно, чем WHERE, потому что в первом случае строки выбираются после их 
организации в группы, тогда как во втором — до этого. Однако вот один из 
примеров удачного использования ключевого слова HAVING. 

    SELECT   CUSTOMER.LastName,   COUNT (*)   NumberWithName 
    FROM  CUSTOMER 
    GROUP  BY  CUSTOMER.LastName 
    HAVING  COUNT(*)    >   1 

    Наилучшим использованием HAVING является наложение ограничений на строки 
возвращаемого набора данных на основе вычисляемых столбцов, В этом случае 
ключевое слово WHERE просто не срабатывает, поскольку информация, заданная в 
условии, не существует до выполнения запроса и вычисления результатов. 

    ORDER   BY 

    Ключевое слово ORDER BY используется для упорядочения строк в возвращаемом 
наборе. Вот пример его использования. 

    SELECT * FROM CUSTOMER ORDER BY STATE 

    318	Часть III. Справочные материалы 318	Часть III. Справочные материалы 

    Псевдонимы столбцов 

    Вы, должно быть, отметили, что для результатов вычисления функций 
наподобие COUNT () и зим () постоянно использовались имена фиктивных столбцов. 
Такие имена называются псевдонимами столбов (column alias) и предназначены для 
того, чтобы запросы и результаты их выполнения было легче читать. В диалекте 
языка SQL СУБД SQL Server псевдоним столбца может стоять сразу же после 
соответствующего столбца в списке оператора SELECT или слева от названия поля, 
перед знаком равенства. Например, в следующем запросе для функции COUNT (), 
представляющей вычисляемый столбец, используется псевдоним NumberWithName. 

    SELECT   CUSTOMER.LastName,   NumberWithName=COUNT(*) 
    FROM   CUSTOMER 
    GROUP  BY  CUSTOMER.LastName 
    HAVING   COUNT(*)    >   1 

    Псевдонимы столбцов можно использовать для любого элемента возвращаемого 
набора данных, а не только для обозначения результатов функций. Вот пример 
псевдонима, расположенного справа от столбца, на который он ссылается. 

    SELECT  CUSTOMER.LastName   LNAME, 
    FROM  CUSTOMER 
    GROUP  BY  CUSTOMER.LastName 
    COUNT(' 
    NumberWithName 

    В возвращаемом наборе этого запроса вместо настоящего имени поля LastName 
подставляется псевдоним LName. Обратите внимание, что псевдонимы нельзя 
применять в других фрагментах запроса, например, в условиях WHERE и GROUP BY — 
в них необходимо использовать настоящие имена столбцов. 

    Псевдонимы таблиц 

    Вместо того, чтобы всякий раз в операторе SELECT употреблять полное имя 
таблицы, можно заменить его кратким удобным обозначением по своему выбору. Это 
делается путем указания псевдонима таблицы (table alias) в списке таблиц, 
определяемом с помощью ключевого слова FROM оператора SELECT. Псевдоним 
ставится справа от настоящего имени таблицы, как показано в следующем примере. 

    SELECT  С.LastName,   COUNT {*)   NumberWithName FROM  CUSTOMER  С GROUP 
BY C.LastName 

    Обратите внимание, что псевдоним можно использовать в списке полей 
оператора SELECT даже до его синтаксического определения. Это возможно 
благодаря тому, что ссылки на объекты базы данных разрешаются сервером до 
выполнения запроса. 


    Представления 

    Представление (view) таблицы в SQL создается с помощью оператора SELECT, 
после чего с полученным набором данных можно обращаться как с таблицей, и, в 
свою очередь, применять к нему операторы SELECT. В некоторых случаях к 
представлению можно применять также операторы INSERT, DELETE и UPDATE. В самом 
представлении не хранится никаких данных; это всего лишь логическая 
конструкция. Представление можно считать маленькой SQL-программой, которая 
выполняется при каждом запросе. При обращении к представлению оптимизатор 
запросов находит оператор SELECT, используемый для создания представления, 
совмещает его с оператором, применяемым к представлению, и оптимизирует оба 
оператора, рассматривая их как один запрос. 

    Представления SQL создаются с помощью команды CREATE VIEW. Вот пример: 

    CREATE  VIEW  MOCUSTOMERS  AS 
    SELECT   * 
    FROM CUSTOMER 
    WHERE State='MO' 

    После создания представления к нему можно обращаться с запросами точно так 
же, как к таблице. 

    SELECT * FROM MOCUSTOMERS 

    При выполнении этого запроса обратите внимание, что даже при отсутствии 
ключевого слова WHERE во внешнем операторе SELECT, применяемом к 
представлению, результат выглядит так, будто WHERE присутствует, потому что 
данное ключевое слово встроено в само представление. 

    Глава 15. Microsoft SQL Server 319 Глава 15. Microsoft SQL Server 319 

    Оператор SELECT, который образует представление, может делать практически 
все то же самое, ч, обычный оператор SELECT, за одним исключением: он не может 
содержать ключевого слова ORDER Это ограничение существует не только в SQL 
Server, но и в СУБД Sybase, InterBase и Oracle. 
    При создании модифицируемого представления можно указать, чтобы сервер 
проверял, удовлетворяют ли модифицируемые или добавляемые в запрос строки 
критериям, указанным в представлении. Другими словами, сервер может следить за 
тем, чтобы модифицированная или добавленная запись не вышла за рамки 
представления и не исчезла из виду. Это делается путем использования ключевого 
выражения WITH CHECK OPTION в команде CREATE VIEW. Вот пример соответствующей команды. 

    CREATE VIEW MOCUSTOMERS AS SELECT * FROM CUSTOMER WHERE State='MO' WITH 
CHECK OPTION 

    После этого будут блокироваться все попытки модифицировать старые или 
ввести новые записи, г-: содержащие в поле State значение 'МО'. 

    Хранимые процедуры 

    Хранимой процедурой (stored procedure) называется скомпилированная 
программа на языке SQL, которая хранится в базе данных вместе с другими 
объектами. Хранимые процедуры создаются командой CREATE PROCEDURE, пример 
которой приведен ниже. 

    CREATE   PROCEDURE   listcustomers 
    AS 
    BEGIN 
    SELECT   LastName   FROM  CUSTOMER END 

    Если процедура использует какие-либо параметры, ее синтаксис несколько 
меняется. Вот Спитаке^ для SQL Server: 

    CREATE  PROCEDURE  listcustomersbystate(@State   varchar(2),   
@LastNameMask  varchar(SO)) 
    AS 
    BEGIN 
    SELECT LastName FROM CUSTOMER 
    WHERE State=@State AND LastName LIKE @LastNameMask END 


    Сценарии 

    Нередко бывает удобно конструировать операторы языка описания данных (Data 
Definition Language --DDL), в том числе хранимые процедуры, с применением 
файлов сценариев (script) SQL. Эти файлы можн , редактировать в любом 
текстовом редакторе; в большинстве хороших редакторов SQL поддерживается 
сохранение содержимого сценариев на диске. Помните, что такие сценарии должны 
содержать все необхо димые операторы USE и разделители со. Запуск сценария SQL 
Server на выполнение производится щелчком на кнопке Load ISQL Script в окне 
утилиты ISQL. Процедура, определенная в сценарии, приведенном г листинге 15.1, 
генерирует список объектов, похожий на тот, что выводится по команде DIR. 

    Листинг 15.1. Файл SQL-сценария, содержащий хранимую процедуру sp__dir 

    use master 
    до 
    /* 
    * DROP PROC dbo.sp_dir 
    */ 
    IF OBJECT_ID('dbo.sp_dir') IS NOT NULL BEGIN 
    DROP PROC dbo.sp_dir 
    PRINT '<« DROPPED PROC dbo.sp_dir >»' END go create procedure sp_dir Smask 
varchar(30) = '%', @obtype varchar(2) = 'U', Sorderby 

    320	Часть III. Справочные материалы 

    varchar(3)='/N' as /* 
    Хранимая процедура, предназначенная для вывода содержимого каталоге, 
наподобие команды DIR DOS. 
    Имеет три параметра: 
    Omask = шаблон имен выводимых объектов (по умолчанию выводятся все 
объекты). @obtype = тип объектов (по умолчанию — пользовательские таблицы). 
    @orderby = столбец, по которому нужно отсортировать выводимый листинг. 
Можно использовать следующие значения. 
    /N  =	сортировка по именам. 
    /R  =	сортировка по количеству строк. 
    /S =	сортировка по размеру. 
    /D =	сортировка по дате создания. 
    /DS =	сортировка по размеру страниц данных. 
    /IS =	сортировка по размеру страниц индексов. 
    /US =	сортировка по размеру неиспользованных страниц. 
    /RL =	сортировка по максимальной длине строки. 
    /О  =	сортировка по владельцу. 
    По умолчанию используется сортировка по именам. 
    Значения параметров можно указывать либо в соответствующих позициях 
командной строки, например: 
    sp_dir 'TRA%', 'U', '/S' 
    либо с помощью ссылки на имена, например: 
    sp_dir @mask='TRA%',@obtype='U',@orderby='/S' 
    Все параметры являются необязательными. Вызов без параметров эквивалентен 
следующей команде: 
    sp_dir '%','U','/N' 
    Written by Ken Henderson 3/13/97 3:39PM 
    V 
    CREATE TABLE isp_dir( 
    id	int	NOT NULL, 
    name	varchar(30)	NOT NULL, 
    type	char(2)	NOT NULL, 
    date_created	datetime	NOT NULL, 
    row_count	int	NOT NULL, 
    row_len_in__bytes	int	NOT NULL, 
    total_size__in_KB	int	NOT NULL, 
    data_space_in_KB	int	NOT NULL, 
    index_space_in_KB	int	NOT NULL, 
    unused_space_ in_KB	int	NOT NULL, 
    owner ~    ~	varchar(30)	NOT NULL) 
    insert into lsp_dir select o.id, 
    о.name, 
    o.type, 
    date_created=	o.crdate, 
    row_count =	isnull(rows,0), 
    row_len__in_bytes=       isnull((select sum(length) from syscolumns where 
id=o.id and o.type" in ( ' U ' , ' S ' ) ) , 0) , 
    total_size_in_KB =       isnull((select sum(reserved) from sysindexes 
where in-did in (0, 1, 255) and id = o.id),0)*2, 
    data_space_in_KB =      isnull(((select sum(dpages) from sysindexes where indid 

    Глава 15. Microsoft SQL Server     321 11  Delphi 3 и системы клиент/сервер 

< 2 and id = о.id)+
(select isnull(sum(used), 0) from sysindexes where indid = 255 and id = o.id)},0)*2,
index_space_in_KB =     isnull(((select sum(used) from sysindexes where indid in (0, 1, 255") and~id~= o.id) -
((select sum(dpages) from sysindexes where indid < 2 and id = o.id)+
(select isnull(sum(used), 0) from sysindexes where indid = 255 and id = о.id))),0)*2,
unused_space_in_KB =    isnull (( (select sum(reserved) from sysindexes where ir.-did in (0, 1, 255) and id = o.id) -
(select sum(used) from sysindexes where indid in (0, I, 255) and id = o.id)),0)*2,
owner=	user_name(o.uid) from sysobjects o, sysindexes i
where o.name like @mask and o.type like Sobtype and o.id*=i.id and i.indid<=l
select @orderby=upper(@orderby)
if @orderby = '/N'
alter table #sp_dir add constraint PK_dir primary key clustered (name,id) else if @orderby = '/R'
alter table #sp_dir add constraint PK_dir primary key clustered (row_count,name) else if @orderby = '/S'
alter table #sp_dir add constraint PK_dir primary key clustered (total_size_in_KB,name) else if @orderby = '/D'
alter table #sp_dir add constraint PK_dir primary key clustered (date_created,name) else if @orderby = '/DS'
alter table #sp_dir add constraint PK_dir primary key clustered (data_space_in_KB,name) else if @orderby = '/IS'
alter table #sp_dir add constraint PK_dir primary key clustered (index_space_in_KB,name) else if Sorderby = '/US'
alter table #sp_dir add constraint PK_dir primary key clustered (unused_space_in_KB, name) if @orde~rby =~'/RL'
alter table #sp_dir add constraint PK_dir primary key clustered (row_len_in_bytes,name) else if @orderby = '/0'
alter table #sp_dir add constraint PK_dir primary key clustered (owner,name)
alter table	#sp_dir	add sequencer int identity
alter table	#sp_dir	drop constraint PK_dir
alter table	#sp_dir	add primary key clustered (sequencer)
insert into #sp_dir
(id,name,type, date_created,row_count,row_len_in_bytes,total_size_in_KB,data_ space_in_Kb
,index_space_in_KB,unused_space_in_KB,owner)
select power(2.0,31)-
1,'TOTAL:','NA',getdate(),row_count=sum(row_count),row_len_in_bytes=max(row_len_in_byte
s),total_size_in_KB=sum(total_size_in_KB),date_space=sum(data_space_in_KB) ,
index_space_in_KB=sum(index_space_in_KB),unused_space_in_KB=sum(unused_space_in_KB) , 'NA

322	Часть III. Справочные материалы

    from #sp_dir 
    select name,type,date_created, row_count, row_len_in_bytes, total 
size_in_KB, data_space_in_KB, index_space_in_KB, unused_space_in_KB, owner 
from #sp_dir 
    drop table #sp_dir 
    go 
    IF OBJECT_ID('dbo.sp_dir') IS NOT NULL 
    PRINT '«< CREATED PROC dbo.sp_dir >»' ELSE 
    PRINT '<« FAILED CREATING PROC dbo.sp_dir »>' 
    go 

    Обратите внимание на оператор в начале файла, который определяет базу 
данных для хранения процедуры, а также на использование разделителя со для 
отделения фрагментов сценария. 

    На заметку 
    Полный текст этой процедуры находится на компакт-диске, прилагаемом к этой книге. 

    Выполнение хранимых процедур 

    Хранимые процедуры SQL Server выполняются с помощью команды EXECUTE, 
которая' имеет следующий синтаксис. 

    EXECUTE  имя_процедуры параметры 

    Слово EXECUTE можно сократить до ЕХЕС, или вообще опустить его, если эта 
команда стоит в командном файле первой. Например, процедуру listcustomers 
можно запустить на выполнение в окне утилиты ISQL следующим образом. 

    listcustomers 

    Параметры в хранимую процедуру можно передавать как по порядку, так и по именам: 

    exec listcustomersbystate 'MO','%' 

    ИЛИ exec listcustomersbystate @LastNameMask='%',@State='MO' 


    Триггеры 

    Триггеры (trigger) имеют определенное сходство с хранимыми процедурами, но 
в то же время отличаются от них. Это программы на языке SQL, которые 
запускаются автоматически при выполнении определенной операции над конкретной 
таблицей: вставке, обновлении или удалении данных, т.е. ассоциируются с этой 
операцией. Вот пример триггера на языке Transact-SQL. 

    CREATE TRIGGER SALEDelete ON CUSTOMER FOR DELETE 
    AS 
    BEGIN 
    DELETE FROM SALE 
    WHERE CustomerNumber=(Select CustomerNumber FROM 
    deleted) END 

    Этот триггер удаляет данные о продажах определенному покупателю из таблицы 
SALE, как только запись об этом покупателе удаляется из таблицы CUSTOMER. 
Такое удаление называется каскадным (cascading delete), поскольку операция 
удаления записи из одной таблицы вызывает каскад операций удаления данных в 
других таблицах, связанных с ней по ключу. 
    Обратите внимание на использование виртуальной таблицы deleted. Во время 
выполнения триггера операции DELETE на сервере создается временная таблица под 
названием deleted, содержащая удаляемые строки. В приведенном триггере эта 
таблица используется для определения значения поля CustomerNumber в удаляемой 
записи. Затем это значение используется для удаления строк из таблицы SALE. 

    Глава 15. Microsoft SQL Server 323 

    При срабатывании триггеров операций INSERT и UPDATE на сервере создается 
похожая таблица под названием inserted. Эта таблица существует фактически 
только в памяти компьютера и больше нигде, но к ней можно обращаться из 
триггера точно так же, как и к любой другой таблице. 

    Курсоры 

    Курсоры (cursor) — это компромисс между ориентированным на множества 
подходом SQL и потребностью в построчных операциях. С помощью курсоров можно 
работать с отдельными строками таблицы. Обычно курсоры не пишутся на языке 
SQL, а автоматически создаются системой BDE, но иногда они оказываются 
удобными для использования в хранимых процедурах. 
    Над курсорами выполняются четыре основные операции: объявление, открытие, 
извлечение данных и закрытие. С помощью курсоров можно также модифицировать и 
удалять строки таблицы. 
    Объявление курсора содержит оператор SELECT и (для модифицируемых 
курсоров) список модифицируемых полей. Вот пример такого объявления. 

    DECLARE CUSTOMER_SELECT CURSOR FOR SELECT * FROM CUSTOMER 

    Прежде чем считывать строки, используя курсор, его необходимо открыть. Для 
инициирования запроса, содержащегося в объявлении курсора, используется 
команда OPEN. 

    OPEN CUSTOMER_SELECT 

    По команде OPEN в приложение не передаются никакие данные. Для этого 
необходимо использовать команду FETCH. 

    FETCH CUSTOMER_SELECT 

    По этой команде из возвращаемого курсором набора данных извлекается одна 
строка. Все последующие вызовы FETCH приводят к извлечению очередных строк. В 
курсорах SQL Server поддерживается только одностороннее продвижение по записям 
таблицы: с помощью команды FETCH нельзя возвращаться к ранее пройденным 
записям. Для этого необходимо закрыть курсор командой CLOSE и снова открыть 
его командой OPEN. 

    На заметку 
    Отсутствие в SQL Server поддержки двунаправленных курсоров (bidirectional 
cursor) — это еще не повод не использовать их. Система BDE эмулирует 
двунаправленные курсоры на уровне клиентной части приложения независимо от 
того, поддерживаются ли они платформой сервера. Вот почему по таким структурам 
данных, как TQuery и ТТаЫе, можно передвигаться как вперед, так и назад. 

    Строки, полученные из модифицируемого курсора, можно модифицировать с 
помощью специальных версий команд UPDATE и DELETE. Модифицируемый курсор 
объявляется с использованием элемента FOR UPDATE OF. Вот пример такого объявления. 

    DECLARE CUSTOMER_UPDATE CURSOR FOR SELECT * FROM CUSTOMER FOR UPDATE OF LastName 

    На заметку 
    В списке, определяемом с помощью ключевого выражения FOR UPDATE OF, 
следует перечислять только те поля, которые на самом деле будут 
модифицироваться. Наличие в этом списке лишних полей замедляет работу сервера. 

    Для удаления или модифицирования текущей строки курсора в дополнение к 
команде DELETE или UPDATE используется синтаксическая конструкция WHERE 
CURRENT OF имя_курсора, как в следующем примере: 

    UPDATE CUSTOMER 
    SET LastName="Cane" 
    WHERE CURRENT OF CUSTOMER UPDATE 

    324 Часть III. Справочные материалы 

    или 

    DELETE FROM CUSTOMER 
    WHERE CURRENT OF CUSTOMERJJPDATE 

    Для завершения работы курсора его закрывают командой CLOSE. Вот ее синтаксис: 

    CLOSE CUSTOMER_UPDATE 

    Закрытие курсора не приводит к освобождению системных ресурсов, которые он 
использовал. Для этого применяется команда DEALLOCATE: 

    DEALLOCATE CUSTOMER UPDATE 

    Резюме 

    Из этой главы вы узнали, как запустить SQL Server, как подключиться к 
серверу и как выявить и устранить возможные неполадки при подключении. Глава 
содержит достаточно подробное введение в диалект Transact-SQL для SQL Server, 
а также описание выполнения некоторых основных операций над базами данных. 
    СУБД Microsoft SQL Server сама по себе является предметом для отдельной 
книги. Тем не менее можно надеяться, что представленное здесь краткое введение 
значительно облегчит жизнь разработчикам приложений Delphi, которые должны 
взаимодействовать с SQL Server. 

    Что дальше... 

    Подобно этой главе, в главе 16, "Oracle" дается подробное введение в 
разработку приложений Delphi для работы с базами данных Oracle. 

    Глава 15. Microsoft SQL Server 325