Курсоры могут быть статическими и динамическими.
При объявлении статического курсора должен указываться атрибут STATIC. Открытие статического курсора приводит к выгрузке результирующего набора строк в динамически созданную временную таблицу системной БД TEMPDB, и все дальнейшие курсорные операции осуществляются с этой таблицей. После открытия курсора изменения в исходных таблицах, которые осуществляются в рамках этого или других сеансов, не будут отражаться в курсорном результирующем наборе.
Рис. 13.31–13.33 демонстрируют особенности работы со статическим курсором.
Рис. 13.31. Результирующий набор SELECT-запроса, выполненного
до исполнения сценария на рис. 13.32
На рис. 13.31 представлен результат SELECT-запроса, отражающий содержимое результирующего набора, который будет сформирован в сценарии на рис. 13.32 при открытии курсора с именем C_ TEACHER.
В сценарии на рис. 13.32 объявлен и затем отрыт курсор C_ TEACHER. При этом сформированный результирующий набор (он будет идентичен набору, представленному на рис. 13.31) выгружается во временную таблицу системной БД TEMPDB. Заметьте: все изменения (операторы UPDATE, DELETE и INSERT ограничеы с сверху и снизу линиями комментарий), выполненные в исходной таблице TEACHER, никак не отразились на результате выборки строк курсора с помощью оператора FETCH. В то же время, если снова выполнить SELECT-запрос, аналогичный представленному на рис. 13.31 и курсорному запросу, то получим ожидаемый результат, отражающий изменения в таблице TEACHER (рис. 13.3).
Рис. 13.32. Пример, демонстрирующий особенности работы статического курсора
Рис. 13.33. Результирующий набор SELECT-запроса,
выполненного после исполнения сценария на рис. 13.32
Обратите внимание на применение в сценарии на рис. 13.2 системной функции @@ CURSOR_ ROWS, с помощью которой можно получить количество строк в результирующем наборе статического курсора.
Вернем таблицу TEACHER в состояние, предшествующее выполнению сценария на рис. 13.32 и соответствующее запросу на рис. 13.31. После этого выполним сценарий, представленный на рис. 13.34, в котором применяется динамический курсор.
Рис. 13.34. Пример, демонстрирующий особенности работы
динамического курсора
Заметим: изменение, выполненное оператором UPDATE, отразилось в результирующем наборе; удаленной (DELETE) строке соответствует строка со значением NULL во всех столбцах, а добавленная (INSERT) в исходную таблицу строка в курсорный результирующий набор не введена.
Обратите внимание: значение функции @@ CURSOR_ ROWS после открытия динамического курсора всегда равно –1.
Следует отметить, что кроме STATIC и DYNAMIC-курсоров допускается использовать курсоры с атрибутом KEYSET, занимающие промежуточное положение между STATIC и DYNAMIC. Для знакомства с KEYSET- курсорами рекомендуется изучить пособие [5].
13.15.4. Курсоры с атрибутами FORWARD_ ONLY и SCROLL
По умолчанию для курсора установлен атрибут SCROLL, позволяющий применять оператор FETCH с дополнительными опциями позиционирования.
Для демонстрации возможностей позиционирования в SCROLL- курсорах предварительно рассмотрим запрос на рис. 13.35, применяющий функцию ROW_NUMBER.
Рис. 13.35. Применение оконной функции ROW_NUMBER
для сортировки нумерации строк
Функция ROW_NUMBER предназначена для нумерации строк результирующего набора и относится к классу оконных встроенных функций T-SQL. Основным признаком того, что применяется оконная функция, является ключевое слово OVER, за которым в скобках следуют опции, разбивающие результирующий набор на подмножества (окна) строк, а также сортирующие эти строки внутри подмножества. В приведенном примере разбиение не осуществляется, поэтому все строки результирующего набора только сортируются. Результатом выполнения функции является номер строки в результирующем наборе. Более подробно с оконными функциями можно ознакомиться в пособии [5].
Рис. 13.36. Пример, демонстрирующий опции позиционирования
оператора FETCH, доступные в SCROLL-курсорах
Курсоры с атрибутом FORWARD_ONLY допускают чтение строк результирующего набора только в одном порядке – сверху вниз (FETCH NEXT).
13.15.5. Курсоры с атрибутами FOR UPDATE и READ_ ONLY
Курсор дает возможность программисту последовательно обрабатывать строки результирующего набора строк, полученного в результате выполнения связанного с курсором SELECT-запроса.
Для курсоров с установленным свойством FOR UPDATE, помимо чтения данных из строк с помощью оператора FETCH, можно эти строки изменять или удалять с помощью специального формата операторов UPDATE и DELETE.
На рис. 13.37–13.38 представлен пример использования курсора со свойством FOR UPDATE.
Рис. 13.37. Результирующий набор SELECT-запроса, выполненного
до запуска сценария на рис. 13.38
Обратите внимание: при объявлении курсора C_ TEACHER (рис. 13.38) используется ключевая фраза FOR UPDATE, дающая возможность применять операторы DELETE и UPDATE для удаления или изменения строки таблицы.
В секции WHERE операторы DELETE и UPDATE (рис. 13.38) используют операцию CURRENT OF, для которой указывается имя курсора (в примере C_ TEACHER). Такой формат операторов позволяет удалять или изменять строки в таблице (TEACHER), соответствующие текущей позиции курсора в результирующем наборе.
Рис. 13.38. Сценарий, демонстрирующий применение курсора
со свойством FOR UPDATE
Свойством FOR UPDATE могут обладать только динамические (обладают по умолчанию) и ключевые (в пособии не рассматриваются) курсоры.
Курсору может быть установлено свойство READ_ONLY, запрещающее применение операции CURRENT OF в секции WHERE операторов DELETE и UPDATE. Однако свойство READ_ONLY не мешает применять эти операторы без использования CURRENT OF (рис. 13.39).
Рис. 13.39. Сценарий, демонстрирующий применение курсора
со свойством READ_ONLY
В сценарии на рис. 13.39 при объявлении курсора C_ TEACHER используется ключевое слово READ_ONLY. Для удаления и изменения строк таблицы TEACHER применяются операторы DELETE и UPDATE, не применяющие операцию CURRENT OF в секции WHERE.
Следует отметить, что атрибут READ_ONLY имеет смысл только для динамических и ключевых курсоров, статические курсоры по определению применяются только для чтения.
Применение транзакций
Состояние БД называют согласованным, если хранящиеся данные удовлетворяют всем ограничениям целостности и не противоречат друг другу. Первая часть определения очевидна, вторая требует пояснения. Приведем пример.
Рассмотрим БД банковской системы, учитывающей операции на текущем счете клиента в таблице Текущий счет, а кассовые операции (выдача и прием наличных денежных средств) – в таблице Касса (рис. 13.40).
Рис. 13.40. Схема выполнения операции «Выдача наличных»
Если клиент банка получает 50 единиц денежных средств со своего текущего счета в виде наличности, то этому событию в гипотетической банковской системе будет соответствовать банковская операция «Выдача наличных», которая в БД представляется в виде результата выполнения двух операторов INSERT, добавляющих по строке в таблицы Текущий счет и Касса. Добавленная строка в таблицу Текущий счет будет отражать тот факт, что обязательства банка перед клиентом теперь уменьшатся на 50 единиц (уменьшился остаток на текущем счете), а строка в таблице Касса – факт уменьшения наличных денег в кассе банка на те же 50 единиц. Если два оператора INSERT выполнились успешно, то БД перешла из одного согласованного состояния в другое, тоже согласованное.
Предположим теперь, что после успешного выполнения первого оператора INSERT, добавившего строку в таблицу Текущий счет, произошел системный сбой, не позволивший выполнить второй оператор INSERT и, соответственно, клиенту получить причитающиеся ему наличные денежные средства. Произойдет рассогласование, которое заключается в том, что обязательства банка перед клиентом уменьшились, а кассовый остаток остался прежним – клиент не получил наличные. В этом случае БД перешла из согласованного состояния в несогласованное.
Как видно из приведенного примера, понятие «согласованное состояние БД» зависит от той предметной области, состояние которой отражается в БД. Очевидно, что если бы рассматривалась БД, хранящая, например, данные о ходе технологического процесса, то согласованность бы понималась иначе.
С другой стороны, рассогласование в любом случае будет происходить в тогда, когда при необходимости одновременно выполнить несколько изменений в БД, выполняется только их часть, а другая часть не выполнится вообще. Тогда, по всей видимости, если бы был механизм, позволяющий объединять несколько операторов изменения БД в одну атомарную операцию, которая либо полностью выполнялась, либо полностью не выполнялась, то эта проблемы была бы решена.
В первом приближении транзакцией будем назвать механизм БД, позволяющий объединять несколько операторов, изменяющих БД таким образом, чтобы при выполнении этой совокупности операторов они или все выполнились, или все не выполнились.
Дата: 2019-02-25, просмотров: 323.