Хранимые процедуры
Нередко операция с данными представляет набор инструкций, которые необходимо выполнить в определенной последовательности. Например, при добавлении данных покупки товара необходимо внести данные в таблицу заказов. Однако перед этим надо проверить, а есть ли покупаемый товар в наличии. Возможно, при этом понадобится проверить еще ряд дополнительных условий. То есть фактически процесс покупки товара охватывает несколько действий, которые должны выполняться в определенной последовательности. И в этом случае более оптимально будет инкапсулировать все эти действия в один объект — хранимую процедуру (stored procedure).
То есть по сути хранимые процедуры представляют набор инструкций, которые выполняются как единое целое. Тем самым хранимые процедуры позволяют упростить комплексные операции и вынести их в единый объект. Изменится процесс покупки товара, соответственно достаточно будет изменить код процедуры. То есть процедура также упрощает управление кодом.
Также хранимые процедуры позволяют ограничить доступ к данным в таблицах и тем самым уменьшить вероятность преднамеренных или неосознанных нежелательных действий в отношении этих данных.
И еще один важный аспект — производительность. Хранимые процедуры обычно выполняются быстрее, чем обычные SQL-инструкции. Все потому что код процедур компилируется один раз при первом ее запуске, а затем сохраняется в скомпилированной форме.
Для создания хранимой процедуры применяется команда CREATE PROCEDURE или CREATE PROC .
Таким образом, хранимая процедура имеет три ключевых особенности: упрощение кода, безопасность и производительность.
Например, пусть в базе данных есть таблица, которая хранит данные о товарах:
Создадим хранимую процедуру для извлечения данных из этой таблицы:
Поскольку команда CREATE PROCEDURE должна вызываться в отдельном пакете, то после команды USE, которая устанавливает текущую базу данных, используется команда GO для определения нового пакета.
После имени процедуры должно идти ключевое слово AS.
Для отделения тела процедуры от остальной части скрипта код процедуры нередко помещается в блок BEGIN. END:
После добавления процедуры мы ее можем увидеть в узле базы данных в SQL Server Management Studio в подузле Programmability -> Stored Procedures :
How to view the stored procedure code in SQL Server Management Studio
I am new to SQL Server. I am logged into my database through SQL Server Management Studio.
I have a list of stored procedures. How do I view the stored procedure code?
Right clicking on the stored procedure does not have any option like view contents of stored procedure .
10 Answers 10
I guess this is a better way to view a stored procedure’s code:
Right click on the stored procedure and select Script Stored Procedure as | CREATE To | New Query Editor Window / Clipboard / File.
You can also do Modify when you right click on the stored procedure.
For multiple procedures at once, click on the Stored Procedures folder, hit F7 to open the Object Explorer Details pane, hold Ctrl and click to select all the ones that you want, and then right click and select Script Stored Procedure as | CREATE To.
Хранимые процедуры в microsoft sql server
Хранимые процедуры (Stored Procedure) представляют собой набор команд, состоящий из одного или нескольких операторов SQL или функций и сохраняемый в базе данных в откомпилированном виде.
По отношению к БД — это объекты, которые создаются и хранятся в БД. Они могут быть вызваны из клиентских приложений. При этом одна процедура может быть использована в любом количестве клиентских приложений, что позволяет существенно сэкономить трудозатраты на создание прикладного программного обеспечения и эффективно применять стратегию повторного использования кода. Так же как и любые процедуры в стандартных языках программирования, хранимые процедуры могут иметь входные и выходные параметры или не иметь их вовсе.
Каждая хранимая процедура компилируется при первом выполнении, в процессе компиляции строится оптимальный план выполнения процедуры. Описание процедуры совместно с планом ее выполнения хранится в системных таблицах БД.
С точки зрения приложений, работающих с БД, хранимые процедуры— это подпрограммы, которые выполняются на сервере.
Хранимые процедуры могут быть активизированы не только пользовательскими приложениями, но и триггерами.
По умолчанию выполнить хранимую процедуру может только ее владелец, которым является владелец БД, и создатель хранимой процедуры. Однако владелец хранимой процедуры может делегировать права на ее запуск другим пользователям.
Типы хранимых процедур
Системные хранимые процедуры предназначены для выполнения различных административных действий. Практически все действия по администрированию сервера выполняются с их помощью.
Можно сказать, что системные хранимые процедуры являются интерфейсом, обеспечивающим работу с системными таблицами.
Системные хранимые процедуры имеют префикс sp_, хранятся в системной базе данных и могут быть вызваны в контексте любой другой базы данных.
Пользовательские хранимые процедуры реализуют те или иные действия. Хранимые процедуры – полноценный объект базы данных. Вследствие этого каждая хранимая процедура располагается в конкретной базе данных, где и выполняется.
Временные хранимые процедуры существуют лишь некоторое время, после чего автоматически уничтожаются сервером. Они делятся на локальные и глобальные.
Локальные временные хранимые процедуры могут быть вызваны только из того соединения, в котором созданы. При создании такой процедуры ей необходимо дать имя, начинающееся с одного символа #.
Как и все временные объекты, хранимые процедуры этого типа автоматически удаляются при отключении пользователя, перезапуске или остановке сервера.
Глобальные временные хранимые процедуры доступны для любых соединений сервера, на котором имеется такая же процедура. Для ее определения достаточно дать ей имя, начинающееся с символов ##.
Удаляются эти процедуры при перезапуске или остановке сервера, а также при закрытии соединения, в контексте которого они были созданы.
Создание хранимой процедуры предполагает решение следующих задач:
планирование прав доступа. При создании хранимой процедуры следует учитывать, что она будет иметь те же права доступа к объектам базы данных, что и создавший ее пользователь;
определение параметров хранимой процедуры, хранимые процедуры могут обладать входными и выходными параметрами;
разработка кода хранимой процедуры. Код процедуры может содержать последовательность любых команд SQL, включая вызов других хранимых процедур.
Синтаксис оператора создания новой или изменения имеющейся хранимой процедуры в обозначениях MS SQL Server:
[=default][OUTPUT] ][. n]
sql_оператор [. n]
Параметры оператора создания новой или изменения имеющейся хранимой процедуры:
Используя префиксы sp_, #, ## в имени, создаваемую процедуру можно определить в качестве системной или временной.
Как видно из синтаксиса команды, не допускается указывать имя владельца, которому будет принадлежать создаваемая процедура, а также имя базы данных, где она должна быть размещена. Таким образом, чтобы разместить создаваемую хранимую процедуру в конкретной базе данных, необходимо выполнить команду CREATE PROCEDURE в контексте этой базы данных.
При обращении из тела хранимой процедуры к объектам той же базы данных можно использовать укороченные имена, т. е. без указания имени базы данных. Когда же требуется обратиться к объектам, расположенным в других базах данных, указание имени базы данных обязательно.
Номер в имени – это идентификационный номер хранимой процедуры, однозначно определяющий ее в группе процедур. Для удобства управления процедурами логически однотипные хранимые процедуры можно группировать, присваивая им одинаковые имена, но разные идентификационные номера.
Для передачи входных и выходных данных в создаваемой хранимой процедуре могут использоваться параметры, имена которых, как и имена локальных переменных, должны начинаться с символа @. В одной хранимой процедуре можно задать множество параметров, разделенных запятыми.
В теле процедуры не должны применяться локальные переменные, чьи имена совпадают с именами параметров этой процедуры.
Для определения типа данных, который будет иметь соответствующий параметр хранимой процедуры, используются все типы данных SQL, включая определенные пользователем, за исключением table. Однако тип данных CURSOR может быть использован только как выходной параметр хранимой процедуры, т.е. с указанием ключевого слова OUTPUT.
При указании типа данных cursor нужно также указать ключевые слова VARYING и OUTPUT. Выходных параметров типа cursor может быть несколько.
Наличие ключевого слова OUTPUT означает, что соответствующий параметр предназначен для возвращения данных из хранимой процедуры. Однако это вовсе не означает, что параметр не подходит для передачи значений в хранимую процедуру.
Указание ключевого слова OUTPUT предписывает серверу при выходе из хранимой процедуры присвоить текущее значение параметра локальной переменной, которая была указана при вызове процедуры в качестве значения параметра.
Не разрешается использование любых выражений или констант, допустимое для обычных параметров. Аргументы типов text, ntext и image не могут быть выходными, если процедура не является процедурой CLR.
При указании ключевого слова OUTPUT значение соответствующего параметра при вызове процедуры может быть задано только с помощью локальной переменной.
Ключевое слово VARYING применяется совместно с параметром OUTPUT, имеющим тип CURSOR. Оно определяет, что выходным параметром будет результирующее множество.
Ключевое слово DEFAULT представляет собой значение, которое будет принимать соответствующий параметр по умолчанию. Таким образом, при вызове процедуры можно не указывать явно значение соответствующего параметра.
Так как сервер кэширует план исполнения запроса и компилированный код, при последующем вызове процедуры будут использоваться уже готовые значения. Однако в некоторых случаях все же требуется выполнять перекомпиляцию кода процедуры. Указание ключевого слова RECOMPILE предписывает системе создавать план выполнения хранимой процедуры при каждом ее вызове.
Параметр FOR REPLICATION востребован при репликации данных.
Ключевое слово ENCRYPTION предписывает серверу выполнить шифрование кода хранимой процедуры, что может обеспечить защиту от использования авторских алгоритмов, реализующих работу хранимой процедуры.
Ключевое слово AS размещается в начале собственно тела хранимой процедуры, т.е. набора команд SQL, с помощью которых и будет реализовываться то или иное действие. В теле процедуры могут применяться практически все команды SQL, объявляться транзакции, устанавливаться блокировки и вызываться другие хранимые процедуры.
Инструкцию CREATE PROCEDURE нельзя объединять с другими инструкциями Transact-SQL в одном пакете.
Использование RETURN в хранимой процедуре. Выход из хранимой процедуры можно осуществить посредством команды RETURN.
Позволяет выйти из процедуры в любой точке по указанному условию, а также позволяет передать результат выполнения процедуры числом, по которому можно судить о качестве и правильности выполнения процедуры.
Синтаксис:
RETURN [ integer_expression ]
Аргументы:
integer_expression — возвращаемое целочисленное значение. Хранимые процедуры могут возвращать целочисленное значение вызывающей их процедуре или приложению. Тип int. Пример приведен ниже.
Удаление хранимой процедуры осуществляется командой:
Каждая хранимая процедура является объектом БД. Она имеет уникальное имя и уникальный внутренний номер в системном каталоге. При изменении текста хранимой процедуры мы должны сначала уничтожить данную процедуру как объект, хранимый в БД, и только после этого записать на ее место новую. Следует отметить, что при удалении хранимой процедуры удаляются одновременно все ее версии, нельзя удалить только одну версию хранимой процедуры.
Для выполнения хранимой процедуры используется команда:
[ @return_status = ]
имя_процедуры [;номер]
Если вызов хранимой процедуры не является единственной командой в пакете, то присутствие команды EXECUTE обязательно. Более того, эта команда требуется для вызова процедуры из тела другой процедуры или триггера.
Использование ключевого слова OUTPUT при вызове процедуры разрешается только для параметров, которые были объявлены при создании процедуры с ключевым словом OUTPUT.
Когда же при вызове процедуры для параметра указывается ключевое слово DEFAULT, то будет использовано значение по умолчанию. Естественно, указанное слово DEFAULT разрешается только для тех параметров, для которых определено значение по умолчанию.
Из синтаксиса команды EXECUTE видно, что имена параметров могут быть опущены при вызове процедуры. Однако в этом случае пользователь должен указывать значения для параметров в том же порядке, в каком они перечислялись при создании процедуры.
Параметры, для которых задано значение по умолчанию, в списке вызова можно не указывать.
Отметим, что при вызове процедуры указываются либо имена параметров со значениями, либо только значения без имени параметра. Их комбинирование не допускается.
Пример:
CREATE TABLE dbo.Table11
(c1 int PRIMARY KEY NOT NULL, c2 int NOT NULL);
INSERT INTO dbo.Table11 VALUES (1, 10);
INSERT INTO dbo.Table11 VALUES (2, 20);
INSERT INTO dbo.Table11 VALUES (3, 30);
Процедура:
CREATE PROC my_proc11 @par1 int output, @par2 int output
SELECT @par1= c1, @par2 = c2 FROM dbo.Table11;
Обращение:
Declare @p1 int, @p2 int
EXEC my_proc11 @p1 output, @p2 output
При указании ключевого слова OUTPUT значение соответствующего параметра при вызове процедуры может быть задано только с помощью локальной переменной.
Выводится только одна строка (последняя).
Пример задания значения входного параметра по умолчанию:
CREATE PROC my_proc55 @par1 int output, @par2 int output, @par3 As int =10
SELECT @par1= c1, @par2 = c2 FROM dbo.Table5 where c2=@par3;
Обращение к процедуре:
Declare @p1 int, @p2 int
EXEC my_proc55 @p1 output, @p2 output —.
Declare @p1 int, @p2 int
EXEC my_proc55 @p1 output, @p2 output, DEFAULT
Примеры создания и использования хранимых процедур для базы данных DB_Books:
Процедура без параметров:
CREATE PROCEDURE Count_Books AS
Select count(Code_book) from Books
Обращение к процедуре:
Процедура c входным параметром @Count_pages:
CREATE PROCEDURE Count_Books_Pages @Count_pages as Int
AS Select count(Code_book) from Books
Обращение к процедуре:
EXEC Count_Books_Pages 100
Процедура c входными параметрами @Count_pages и @Title:
CREATE PROCEDURE Count_Books_Title @Count_pages as Int, @Title AS Char(10) AS
Select count(Code_book) from Books
WHERE Pages>=@Count_pages AND Title_book LIKE @Title
Обращение к процедуре:
EXEC Count_Books_Title 100, ‘П%’
Процедура c входными параметрами @Count_pages и @Title и выходным параметром @Itogo:
CREATE PROCEDURE Count_Books_Itogo @Count_pages Int, @Title Char(10), @Itogo Int OUTPUT
Select @Itogo = count(Code_book) from Books
WHERE Pages>=@Count_pages AND Title_book LIKE @Title
Обращение к процедуре:
Declare @q As int
EXEC Count_Books_Itogo 100, ‘П%’, @q output
Процедура c входным параметром @param и RETURN:
CREATE PROCEDURE checkname @param int AS
IF (SELECT Name_author FROM authors WHERE Code_author = @param) = ‘Пушкин А.С.’
Обращение к процедуре:
DECLARE @return_status As int
EXEC @return_status = checkname 3
SELECT ‘Return Status’ = @return_status
Процедура c входным параметром @k для получения всей информации о конкретном авторе:
CREATE PROC select_author @k CHAR(30)
AS SELECT * FROM Authors WHERE name_author=@k
Обращение к процедуре:
EXEC select_author ‘Пушкин А.С.’
Declare @p1 As CHAR(30)
set @p1=’Пушкин А.С.’
EXEC select_author @p1
Использование типа данных cursor в параметре OUTPUT
Хранимые процедуры языка Transact-SQL могут использовать тип данных cursor только для параметров OUTPUT. Если тип данных cursor указан для параметра, должны быть также указаны оба параметра VARYING и OUTPUT. Если для параметра указано ключевое слово VARYING, тип данных должен быть cursor и должно быть указано ключевое слово OUTPUT.
Примечание: Тип данных cursor не может быть связан с переменными приложения через интерфейсы API баз данных, таких как OLE DB, ODBC, ADO и DB-Library. Поскольку параметры OUTPUT должны быть связаны прежде, чем приложение может выполнить хранимую процедуру, хранимые процедуры с параметрами OUTPUT типа cursor не могут быть вызваны из функций API базы данных. Эти процедуры могут быть вызваны из пакетов языка Transact-SQL, хранимых процедур или триггеров, только когда переменная OUTPUT типа cursor присвоена локальной переменной языка Transact-SQL типа cursor.
Следующие правила относятся к выходным параметрам типа cursor при выполнении процедуры:
Для однонаправленного курсора в результирующий набор курсора будут возвращены только строки с текущей позиции курсора до конца курсора. Текущая позиция курсора определяется при окончании выполнения хранимой процедуры.
Непрокручиваемый курсор открыт в процедуре на результирующем наборе по имени RS из 100 строк.
Процедура выбирает первые 5 строк результирующего набора RS.
Процедура возвращает результат участнику.
Результирующий набор RS, возвращенный участнику, состоит из строк с 6 по 100 из набора RS, и курсор в участнике позиционирован перед первой строкой RS.
Для однонаправленного курсора, если курсор позиционирован перед первой строкой после завершения хранимой процедуры, весь результирующий набор будет возвращен к вызывающему пакету, хранимой процедуре или триггеру. После возврата позиция курсора будет установлена перед первой строкой.
Для однонаправленного курсора, если курсор позиционирован за концом последней строки после завершения хранимой процедуры, вызывающему пакету, хранимой процедуре или триггеру будет возвращен пустой результирующий набор.
Для прокручиваемого курсора, все строки в результирующем наборе будут возвращены к вызывающему пакету, хранимой процедуре или триггеру после выполнения хранимой процедуры. При возврате позиция курсора остается в позиции последней выборки, выполненной в процедуре.
Для любого типа курсора, если курсор закрыт, то вызывающему пакету, хранимой процедуре или триггеру будет возвращено значение NULL. Это же произойдет в случае, если курсор присвоен параметру, но этот курсор никогда не открывался.
Примечание. Закрытое состояние имеет значение только во время возврата. Например, можно при выполнении процедуры закрыть курсор, снова открыть его позже в процедуре и возвратить этот результирующий набор курсора в вызывающий пакет, хранимую процедуру или триггер.
В следующем примере создается хранимая процедура, которая указывает выходной параметр @currency_cursor, используя тип данных cursor. Хранимая процедура затем будет вызвана из пакета.
Создание и заполнение таблицы для примера:
IF OBJECT_ID (‘Table1′, N’U’) IS NOT NULL
DROP TABLE Table1;
CREATE TABLE Table1
(c1 int PRIMARY KEY NOT NULL, c2 int NOT NULL);
INSERT INTO Table1 VALUES (1, 10);
INSERT INTO Table1 VALUES (2, 20);
INSERT INTO Table1 VALUES (3, 30);
select * from Table1
Создание процедуры:
IF OBJECT_ID ( ‘PrimerCursor’, ‘P’ ) IS NOT NULL
DROP PROCEDURE PrimerCursor;
CREATE PROCEDURE PrimerCursor
@CurrencyCursor CURSOR VARYING OUTPUT
SET @CurrencyCursor = CURSOR
STATIC FORWARD_ONLY FOR
select c1, c2 from Table1
Обращение к процедуре:
DECLARE @MyCursor CURSOR;
EXEC PrimerCursor @CurrencyCursor = @MyCursor OUTPUT;
—обратите внимание на синтаксис, @CurrencyCursor = @MyCursor
WHILE (@@FETCH_STATUS = 0)
FETCH NEXT FROM @MyCursor
См. выше. Для однонаправленного курсора, если курсор позиционирован перед первой строкой после завершения хранимой процедуры, весь результирующий набор будет возвращен к вызывающему пакету, хранимой процедуре или триггеру. После возврата позиция курсора будет установлена перед первой строкой.
Измененный пример:
IF OBJECT_ID ( ‘PrimerCursor’, ‘P’ ) IS NOT NULL
DROP PROCEDURE PrimerCursor;
CREATE PROCEDURE PrimerCursor
@CurrencyCursor CURSOR VARYING OUTPUT
SET @CurrencyCursor = CURSOR
STATIC SCROLL FOR
select c1, c2 from Table1
FETCH ABSOLUTE 2 FROM @CurrencyCursor
FETCH prior FROM @CurrencyCursor
—Обращение к процедуре:
DECLARE @MyCursor CURSOR;
EXEC PrimerCursor @CurrencyCursor = @MyCursor OUTPUT;
FETCH NEXT FROM @MyCursor
См. выше. Для прокручиваемого курсора, все строки в результирующем наборе будут возвращены к вызывающему пакету, хранимой процедуре или триггеру после выполнения хранимой процедуры. При возврате позиция курсора остается в позиции последней выборки, выполненной в процедуре.
—Создание процедуры с выходным параметром курсором
IF OBJECT_ID ( ‘dbo.uspCurrencyCursor’, ‘P’ ) IS NOT NULL
DROP PROCEDURE dbo.uspCurrencyCursor;
CREATE PROCEDURE dbo.uspCurrencyCursor
@CurrencyCursor CURSOR VARYING OUTPUT
SET @CurrencyCursor = CURSOR
FORWARD_ONLY DYNAMIC FOR
SELECT CurrencyCode, Name
FROM Sales.Currency where Name Like ‘S%’;
DECLARE @MyCursor CURSOR;
EXEC dbo.uspCurrencyCursor @CurrencyCursor = @MyCursor OUTPUT;
WHILE (@@FETCH_STATUS = 0)
FETCH NEXT FROM @MyCursor;
Функции, определенные пользователем
Функции всегда имеют один возвращаемый параметр.
Функции, определенные пользователем, могут быть скалярными или табличными.
Скалярная функция возвращает атомарное (скалярное) значение.
Функции являются табличными, если предложение returns возвращает набор строк.
Функции создаются при помощи оператора create function, который имеет cледующий синтаксис:
create function [schema_name.]function_name
[WITH (ENCRYPTION | SCHEMABINDING)]
| RETURN (select_statement) >
schema_name — имя схемы, которой назначено владение созданной функцией;
function_name — имя новой функции;
@ parameter_name — имя входного параметра;
parameter_data_type — задает тип данных параметра;
default — задает необязательное значение по умолчанию для соответствующего параметра. Значением по умолчанию может быть также пустое значение null.
RETURNS — задает тип данных значения, возвращаемого функцией. Это может быть любой стандартный тип данных, поддерживаемый системой базы данных, включая тип данных table (SQL 2008). (Только один стандартный тип данных, который нельзя использовать, является тип данных timestamp);
TABLE —указывает, что возвращаемым значением функции является таблица. Функциям, возвращающим табличное значение, могут передаваться только константы и @local_variables.
block — является блоком begin/end, который содержит реализацию функции. Последним оператором блока должен быть оператор return с аргументом. Значение аргумента — это значение, возвращаемое данной функцией.
В теле блока begin/end допустимы только следующие операторы:
операторы присваивания, такие как set;
операторы управления потоком выполнения, такие как while и if;
операторы declare, определяющие локальные переменные данных;
операторы select, содержащие списки выбора с выражениями, которые присваиваются в качестве значений переменным, являющимся локальными в этой функции;
операторы insert, update и delete, изменяющие переменные типа table, которые являются локальными в этой функции.
По умолчанию только участники фиксированной серверной роли sysadmin, а также участники фиксированных ролей базы данных db_owner и db_ddladmin могут использовать оператор create function.
Скалярная функция возвращает атомарное (скалярное) значение. Это означает, что в предложении returns скалярной функции можно задать один из стандартных типов данных.
RETURN scalar_expression —возвращаемое атомарное (скалярное) значение.
[ WITH <function_option> [ ,. n ] ]
function_body
RETURN scalar_expression
Функции являются табличными, если предложение returns возвращает набор строк.
RETURN (select_statement) – определяет выходные табличные данные функции. Инструкция RETURN не может иметь аргумента.
with encrYption — кодирует информацию в системном каталоге, который содержит текст оператора create function.
with schemabinding связывает функцию с объектами базы данных.
Пример: функция вычисляет среднее 3 чисел.
CREATE FUNCTION SRED
(@X1 Int, @X2 Int, @X3 Int)
declare @RES As real
set @RES =(@X1+@X2+@X3)/3
Вызов:
select dbo.SRED (3, 4, 5)
Пример: функция вычисляет дополнительные затраты, если увеличиваются бюджеты проектов
CREATE FUNCTION compute_costs (@percent INT =10) — значение по умолчанию
DECLARE @additional_costs DEC (14,2), @sum_budget dec(16,2)
SELECT @sum_budget = SUM (budget) FROM project
SET @additional_costs = @sum_budget * @percent/100
Входная переменная @percent задает процент увеличения бюджетов. Блок begin/end объявляет две локальные переменные: @additionai_cost и @sum_budget. Затем функция присваивает переменной @sum_budget сумму всех бюджетов, используя специальную форму оператора select. После этого функция вычисляет общие дополнительные затраты и возвращает это значение с помощью оператора return.
Пример: функция вычисляет возраст сотрудника на сегодняшний день.
IF OBJECT_ID(‘dbo.fn_age’) IS NOT NULL DROP FUNCTION dbo.fn_age;
CREATE FUNCTION dbo.fn_age
@birthdate AS DATETIME,
@eventdate AS DATETIME
DATEDIFF(year, @birthdate, @eventdate)
— CASE WHEN MONTH(@eventdate) + DAY(@eventdate)
Функции может быть вызвана в операторах Transact-SQL, таких как select, insert, update или delete.
Для вызова функции задается ее имя, за которым следуют круглые скобки. В этих скобках можно задать один или более аргументов. Аргументы являются значениями или выражениями, передаваемыми входным параметрам, которые заданы сразу после имени функции.
При вызове функции, когда все входные параметры не имеют значения по умолчанию, нужно задать значения для каждого параметра в том же порядке, в котором эти параметры определены в операторе create function.
Пример: использование функции compute_cost
SELECT project_no, project_name
WHERE budget < dbo.compute_costs (25)
Выдает имена и номера всех проектов, где бюджет меньше, чем общая дополнительная стоимость всех проектов при заданном проценте.
Пример: использование функции compute_cost
SELECT dbo.compute_costs (25)
Пример: использование функции dbo.fn_age
empid, firstname, lastname, birthdate,
dbo.fn_age(birthdate, GETDATE ()) AS age
Функции являются табличными, если предложение returns возвращает набор строк.
Ни одна из инструкций Transact-SQL в возвращающей табличное значение функции не может возвращать результирующий набор непосредственно пользователю. Единственные данные, которые функция может вернуть пользователю, это таблица table, возвращаемая этой функцией.
В зависимости от того, как определено тело функции, табличные функции могут быть классифицированы как линейные или как многооператорные функции.
Если предложение returns задает table без указания списка столбцов, то эта функция является линейной. Линейные функции возвращают результат выполнения оператора select в виде переменной типа данных table
Синтаксис:
[ WITH <function_option> [ ,. n ] ]
RETURN [ ( ] select_stmt [ ) ]
Пример:
CREATE FUNCTION employees_in_project (@pr_number CHAR(4))
RETURNS TABLE
AS RETURN (SELECT emp_fname, emp_lname
FROM works_on, employee
WHERE employee.emp_no = works_on.emp_no
AND project_no = @pr_number)
Функция employees_in_project отображает имена всех служащих, которые связаны с конкретным проектом. Входной параметр @pr_number задает номер проекта. Поскольку функция в общем случае вращает набор строк, предложение returns содержит тип данных TABLE. Блока begin/end в примере нет, потому что предложение return содержит оператор select.
Обращение к функции имеет вид:
SELECT * FROM employees_in_project(‘p3’)
Пример использования функции, возвращающей таблицу:
CREATE FUNCTION fn_getcustomerorders1(@CustomerID int, @TopRecords bigint)
SELECT TOP (@TopRecords) *
WHERE CustomerID = @CustomerID
ORDER BY OrderDate DESC
Обращение к функции:
SELECT * FROM fn_getcustomerorders1(5,3 );
Результат:
Многооператорная табличная функция включает имя, определяющее table. Имя задает внутреннюю переменную типа table. Можно использовать эту переменную для добавления в нее строк, а затем вернуть эту переменную в качестве возвращаемого значения функции.
Синтаксис:
RETURNS @return_variable TABLE < table_type_definition >
[ WITH <function_option> [ ,. n ] ]
function_body
RETURNS определяет имя локальной возвращаемой переменной для таблицы, которую возвращает эта функция. Предложение RETURNS также определяет формат таблицы. Область видимости имени локальной возвращаемой переменной является локальной в этой функции.
Пример: В следующем примере создается функция dbo.ufnGetContactInformation и демонстрируются компоненты возвращающей табличное значение функции. В этой функции именем локальной возвращаемой переменной является @retContactInformation. Инструкции в теле функции вставляют строки в эту переменную для создания табличных результатов, возвращаемых этой функцией.
IF OBJECT_ID(N’dbo.ufnGetContactInformation’, N’TF’) IS NOT NULL
DROP FUNCTION dbo.ufnGetContactInformation;
CREATE FUNCTION dbo.ufnGetContactInformation(@ContactID int)
—@ContactID входной параметр – индекс контакта
RETURNS @retContactInformation TABLE
— Поля, возвращаемые функцией
ContactID int PRIMARY KEY NOT NULL,
FirstName nvarchar(50) NULL,
LastName nvarchar(50) NULL,
JobTitle nvarchar(50) NULL,
ContactType nvarchar(50) NULL
— Присвоение общей информации
WHERE ContactID = @ContactID;
WHEN EXISTS(SELECT * FROM HumanResources.Employee AS e
WHERE e.ContactID = @ContactID)
THEN (SELECT Title
WHERE ContactID = @ContactID)
WHEN EXISTS(SELECT * FROM Purchasing.VendorContact AS vc
INNER JOIN Person.ContactType AS ct
ON vc.ContactTypeID = ct.ContactTypeID
WHERE vc.ContactID = @ContactID)
THEN (SELECT ct.Name
FROM Purchasing.VendorContact AS vc
INNER JOIN Person.ContactType AS ct
ON vc.ContactTypeID = ct.ContactTypeID
WHERE vc.ContactID = @ContactID)
WHEN EXISTS(SELECT * FROM Sales.StoreContact AS sc
INNER JOIN Person.ContactType AS ct
ON sc.ContactTypeID = ct.ContactTypeID
WHERE sc.ContactID = @ContactID)
THEN (SELECT ct.Name
FROM Sales.StoreContact AS sc
INNER JOIN Person.ContactType AS ct
ON sc.ContactTypeID = ct.ContactTypeID
WHERE ContactID = @ContactID)
WHEN EXISTS(SELECT * FROM HumanResources.Employee AS e
WHERE e.ContactID = @ContactID)
WHEN EXISTS(SELECT * FROM Purchasing.VendorContact AS vc
INNER JOIN Person.ContactType AS ct
ON vc.ContactTypeID = ct.ContactTypeID
WHERE vc.ContactID = @ContactID)
THEN ‘Vendor Contact’
WHEN EXISTS(SELECT * FROM Sales.StoreContact AS sc
INNER JOIN Person.ContactType AS ct
ON sc.ContactTypeID = ct.ContactTypeID
WHERE sc.ContactID = @ContactID)
THEN ‘Store Contact’
WHEN EXISTS(SELECT * FROM Sales.Individual AS i
WHERE i.ContactID = @ContactID)
— формирование вызываемой информации
IF @ContactID IS NOT NULL
INSERT INTO @retContactInformation
SELECT @ContactID, @FirstName, @LastName, @JobTitle, @ContactType;
Обращение к функции:
SELECT ContactID, FirstName, LastName, JobTitle, ContactType
FROM dbo.ufnGetContactInformation(2200);
Пользовательские функции, возвращающие тип данных table, могут быть полноценной альтернативой представлениям. Ссылка на эти функции происходит как на возвращающие табличное значение функции. Возвращающая табличное значение пользовательская функция может быть использована там, где в запросах Transact-SQL разрешены табличные выражения или выражения представлений. В то время как представления ограничены одной инструкцией SELECT, пользовательские функции могут содержать дополнительные инструкции, обеспечивающие более эффективную логику, чем та, которая возможна в представлениях.
Возвращающая табличное значение пользовательская функция также может заменять хранимые процедуры, возвращающие один результирующий набор. На таблицу, возвращаемую пользовательской функцией, можно ссылаться в предложении FROM инструкции Transact-SQL, в котором нельзя ссылаться на хранимые процедуры, возвращающие результирующие наборы.
Вложенные хранимые процедуры
Вложенностью называют ситуацию, когда хранимая процедура вызывает другую процедуру или выполняет управляемый код, ссылаясь на подпрограмму, тип или статистическую функцию среды Common Language Runtime (CLR) Integration. Любая ссылка на управляемый код внутри хранимой процедуры Transact-SQL считается одним уровнем вложенности.
Вложенность хранимых процедур и ссылок на управляемый код ограничена 32 уровнями. Уровень вложенности увеличивается на единицу, когда вызванная хранимая процедура или управляемый код начинает выполняться, и уменьшается на единицу, когда заканчивает. Если уровень вложенности превышает максимальное значение, вся цепочка вызовов заканчивается ошибкой. Текущий уровень вложенности хранимых процедур можно получить при помощи функции @@NESTLEVEL.
Хранимые процедуры могут вызывать сами себя, этот способ называется рекурсией.
Пример. Создать процедуру для определения общего количества товаров, приобретенных фирмой, в которой работает заданный сотрудник.
Сначала разрабатывается процедура для определения фирмы, где работает сотрудник (вложенная процедура).
CREATE PROC my_proc7 @n VARCHAR(20), @f VARCHAR(20) OUTPUT
Затем создается процедура (вызывающая процедура), подсчитывающая общее количество товара, который закуплен интересующей нас фирмой.
3.2. Хранимые процедуры
На мой взгляд, возможности объектов просмотра слишком малы и далеки от идеала. Главная их проблема — статичность. Чтобы получить новый результат (добавить или изменить критерий поиска) приходится изменять саму хранимую процедуру, что достаточно проблематично и большая часть преимуществ объектов просмотра просто теряется.
Хранимые процедуры – это именованный набор операторов Transact-SQL хранящийся на сервере. Хранимые процедуры – это метод выполнения повторяющихся задач и при этом обладают большими возможностями, чем объекты просмотра.
Сервер SQL поддерживает 5 типов встроенных процедур:
- системные хранимые процедуры – хранятся в базе данных master. Система хранит процедуры (определяющиеся по префиксу sp_) предоставляющие эффективные методы получения информации из системных таблиц. Они позволяют системному администратору выполнять администраторские задачи над базой данных, которые обновляют необходимые таблицы напрямую. Системные встроенные процедуры могут быть выполнены из любой базы данных;
- локальные хранимые процедуры – создаются в определенных пользовательских таблицах;
- временные хранимые процедуры – могут быть локальными с именами, начинающимися с единичного знака # или глобальными начинающимися со знака ## (как и локальные/глобальные временные таблицы). Локальные временные процедуры доступны только в единственной пользовательской сессии. Глобальные – доступны всем пользователям. Как и для таблиц, так и для процедур я не рекомендую использовать временные процедуры. Я еще не встречался с такой задачей, которую нельзя было решить без временных процедур;
- удаленные хранимые процедуры – устаревшая технология MS SQL Server. На данные момент эту задачу решают распределенные запросы;
- расширенные встроенные процедуры (содержат в имени префикс xp_) – разрабатываются в виде DLL (Dynamic Link Library, динамически подгружаемая библиотека) и выполняются вне окружения SQL Server. Обычно такие процедуры идентифицируются по префиксу xp_.
Хранимые процедуры в MS SQL Server похожи на процедуры в других языках программирования. Если вы имели опыт программирования на каком-либо языке и не понаслышке знаете о таком понятии как процедуры, то материал этой главы покажется вам слишком простым. Но уровень подготовки читателей может быть разным, поэтому я постараюсь описать все максимально простым и доступным языком.
Итак, процедура — это блок из одной или более команд. Это может быть не просто один запрос, а целая программа, с собственной логикой (операторы IF), циклами. Процедура может принимать заранее определенные переменные и использовать их в своих расчетах, благодаря чему, результат работы процедуры может быть динамическим, и будет зависеть от определенных условий и/или состояния получаемых переменных.
В процедуре вы можете:
- использовать операторы, которые выполняют любые операции в базе данных (выборка, вставка, изменение или удаление данных), включая возможность вызова других встроенных процедур;
- использовать входные параметры;
- возвращать статус выполнения в вызывающую процедуру или модуль для отображения удачного или ошибочного выполнения;
- возврат нескольких значений в вызывающую процедуру или модуль в форме выходных параметров.
Выполнение хранимой процедуры включает ее создание, и после этого выполнение в первый раз, когда план выполнения помещается в кэш. Кэш процедур это пространство памяти, содержащее план выполнения всех выполняемых сейчас операторов Transact-SQL. Размер кэша изменяется, динамически соответствуя необходимому уровню. Если в кэше есть план выполнения, то процедура выполняется быстрее, за счет того, что серверу не нужно разбирать запрос и вырабатывать необходимые действия для решения поставленной задачи.
Когда хранимая процедура создается, операторы проверяются на синтаксическую корректность, чтобы в коде не было явных ошибок написания и использования операторов. На этом этапе логика работы еще не может быть проверена. Если синтаксис ошибочен, то возвращается ошибка и встроенная процедура не сохраняется. Если синтаксис корректен, то, сервер SQL сохраняет имя процедуры в системной таблице sysobjects, а текст в системной таблице syscomments текущей базы данных.
Процесс вызова имен с задержкой позволяет хранимым процедурам ссылаться на объекты, которые не существуют в момент создания процедуры. Этот процесс добавляет эластичности, потому что процедуры и объекты, на которые она ссылается, могут создаваться в любом порядке. Но при этом, все необходимые объекты должны существовать в момент выполнения процедуры. Имена проверяются именно во время выполнения процедуры.
Некоторые изменения в базе данных могут изменить план выполнения, делая его неэффективным или недействительным. Сервер определяет эти изменения и автоматически перекомпилирует план, когда возникает что-то из следующего:
- любые структурные изменения сделанные в таблице или в объекте просмотра ссылающемся в запросе (ALTER TABLE или ALTER VIEW);
- сгенерирована новая статистика с помощью оператора UPDATE STATISTIC;
- индекс, который использовался планом выполнения, удален;
- сделаны значительные изменения в ключах (операторы INSERT, DELETE).
Для определения оптимального плана выполнения, сервер определяет количество данных в используемых таблицах, наличие и тип индексов таблицы, распределение данных в индексных колонках, наличие объединений.
3.2.1. Создание хранимых процедур
На этом теорию на время остановим и посмотрим, как на практике создаются хранимые процедуры. Для этого используется оператор CREATE PROCEDURE, который выглядит следующим образом:
Для создания процедуры, вы должны иметь соответствующие права, например, быть владельцем базы данных или администратором сервера базы данных.
Вы можете создать процедуры только в текущей базе данных, исключая временные процедуры, которые всегда создаются в базе данных tempdb. Создание процедуры похоже на создание объекта просмотра. Первым делом напишите и протестируйте операторы Transact-SQL. После этого, если вы получили результат, который ожидали, создавайте процедуру.
Для имен процедур лучше всего выбрать префикс, который будет указывать, что эта процедура создана именно вами. Только не используйте для этого префикс sp_, чтобы не было конфликтов с системными процедурами.
Давайте попробуем создать процедуру, которая будет получать из таблицы данные о работниках телефонах, т.е. следующий запрос:
Это простейшая процедура, которая не будет использовать переменных, поэтому для ее создания необходимо написать:
Как видите, в начало запроса всего лишь добавляется две строки (хотя, можно написать и в одну). В первой мы пишем операторы CREATE PROCEDURE и имя процедуры, а во второй строке ключевое слово AS. После этого идет простой запрос SELECT, который выбирает данные.
3.2.2. Выполнение процедур
Чтобы разговор был более продуктивным, давайте рассмотрим, как можно выполнять процедуры. Для этого используется оператор EXECUTE, который выглядит следующим образом:
В общем виде команда выглядит достаточно страшно, но к концу главы мы рассмотрим достаточно примеров, и вы увидите, что ничего страшного тут нет. Для процедуры GetPhones, которую мы создали ранее, необходимо указать только:
Результат выполнения команды:
Наша процедура просто выбирает данные, и именно их мы видим в результате.
3.2.3. Удаление процедур
Теперь посмотрим, как можно удалять процедуры. Для этого используется оператор DROP PROCEDURE, который позволяет удалять несколько процедур сразу. В общем виде этот оператор выглядит:
Изменение процедур рассмотрим чуть позже, потому что у нас итак достаточно много информации и нужно рассмотреть немного примеров, чтобы на практике закрепить все возможности процедур.
3.2.4. Использование параметров
Давайте создадим процедуру с параметрами. Допустим, что мы хотим создать процедуру, которая будет искать телефон нужного работника по фамилии. Для этого необходимо в качестве параметра получать искомую фамилию и использовать ее во время поиска:
Параметры перечисляются через запятую после имени процедуры в виде имя тип. Я выделил параметры отдельной строкой (вторая), которая идет после имени процедуры, но до ключевого слова AS. В данном примере только один параметр с именем @Famil и типом varchar длиной в 50 символов.
Имена параметров подчиняются тем же правилам именования, что и переменные и используются также. В данном примере, в секции WHERE происходит сравнение поля «vcName» с параметров @Famil.
Чтобы выполнить процедуру с параметром, нужно написать следующий запрос:
Значения, которые будут присвоены параметрам во время выполнения процедуры, перечисляются через запятую после имени процедуры.
Необходимо заметить, что некоторые программы, например, Query Analyzer, не требуют писать оператор EXEC. Достаточно написать имя процедуры и перечислить параметры:
Но такой пример может сработать далеко не всегда, вернее, не во всех программах. Я рекомендую всегда писать вначале оператор EXECUTE или сокращенно EXEC.
Параметры нужно передавать в том же порядке, как они были указаны в объявлении, но можно сделать и отступление, если указывать их в виде имя=значение. Например, в процедуре GetPhones параметр называется @Famil. Это значит, что мы можем вызвать процедуру следующим образом.
В этом примере, после имени процедуры мы пишем имя параметра и присваиваем ему значение знаком равенства.
3.2.5. Преимущества хранимых процедур
В коде процедуры вы можете использовать практически любые объекты базы данных MS SQL Server, а именно: объекты просмотра, таблицы, функции определенные пользователем и другие процедуры, а также временные таблицы. Если процедура создает временную локальную таблицу, то она существует только во время выполнения и невидима после завершения выполнения.
Хранимые процедуры представляют множество преимуществ, среди которых можно выделить следующее:
- разделение кода — во время решения различных задач очень часто приходится выполнять одни и те же действия. Чтобы не писать один и тот же код в разных задачах, их можно вынести в отдельную процедуру
- разделение логики приложений с другими, таким образом, гарантируется совместимый доступ и модификация данных;
- если процедуры поддерживают все бизнес функции, которые нужны для выполнения пользователю, пользователь никогда не нуждается в прямом доступе к таблицам. Все можно делать через процедуры, которые могут выступать дополнительным гарантом целостности данных и безопасности базы данных;
- предоставляет механизм защиты. Пользователи могут получать право выполнять процедуры, даже если у них нет права на использование вьюшки или таблицы, на которую ссылается процедура;
- повышение производительности, за счет выполнения множество задач, как набор операторов Transact-SQL и хранения плана выполнения в кэше.
Помимо этого, процедура обладает всеми преимуществами, которыми обладают объекты просмотра, например, уменьшение сетевого трафика. Пользователи могут выполнять комплекс операций, посылая только один запрос, что уменьшает количество запросов между клиентом и сервером.
3.2.6. Практика создания и использования процедур
Давайте создадим процедуру, которая будет принимать несколько параметров и при этом использовать логику. В нашей таблице товаров нет ограничения уникальности на сочетание полей название товара и дату, а ведь по логике вещей должно быть. Если в таблице есть два товара, купленных в один день, то это не добавляет программе красоты. Такие покупки должны объединяться, ведь у нас есть поле для хранения количества.
Проблему можно решить и без добавления индекса уникальности, хотя в реальном приложении я бы создал. Будем считать, что индекс не создается только для того, чтобы администратор мог добавлять дубликаты покупок. Пользователям можно разрешить добавление записей только через процедуру.
Итак, давайте создадим такую процедуру (см. листинге 3.1).
В качестве параметров передаются значения всех полей. Внутри процедуры делаем запрос на выборку строки с переданной в качестве параметра датой и названием товара. Если запрос вернет хоть одну строку (а больше и не должен, потому что это уже дубликат), то выводим на экран сообщение. Иначе, добавляем в таблицу запись с указанными параметрами.
Для выполнения процедуры выполним следующий запрос:
Значения для всех полей перечислены в том же порядке, в котором они перечислены при создании процедуры. Попробуйте выполнить добавление одного и того же товара дважды. В ответ на это, вы должны увидеть сообщение о том, что товар уже существует.
Если вы хотите передать параметры в другом порядке, то необходимо указывать их имена. В следующем примере мы передаем сначала значение количества товаров:
Благодаря явному указанию имен, порядок может быть любым.
Процедуры могут быть вложенными (одна процедура может вызывать другую). Вложенные процедуры должны удовлетворять следующим условиям:
- процедуры могут быть вложены до 32 уровней. Если более 32 уровней, то происходит ошибка;
- текущей уровень вложенности хранится в системной переменной @@nestlevel;
- если первая процедура вызывает вторую, то вторая может получить доступ ко всем объектам первой, включая временные таблицы, потому что они в этот момент существуют;
- встроенные процедуры могут быть рекурсивными. Например, если процедура 1 вызвала процедуру 2, то процедура 2 может вызвать первую;
Давайте рассмотрим вызов пользовательской процедуры из другой. Для этого создадим следующий вариант процедуры добавления товара:
В этом примере создается процедура AddGoods1, в которой вводится проверка, если дата товара больше текущей, то выводится соответствующее сообщение. Если дата корректна, то будет вызвана уже существующая процедура AddGoods.
Желательно чтобы права на объекты, которые используются в процедуре и сама процедура принадлежали одному и тому же пользователю. Для исключения ситуации, когда владелец процедуры и таблицы, на которую ссылается процедура, различны, все объекты должны принадлежать dbo. Я уже не раз говорил об этом и напоминаю еще раз – без особой надобности не указывайте владельцев. Лучше всего будет, если объекты будут принадлежать пользователю dbo.
Старайтесь создавать процедуры так, чтобы они выполняли по одной задаче. Дело в том, что одна из задач может в сочетании с другими решениями. Например, если бы мы добавили проверку даты, которую мы сделали в процедуре AddGoods1 в процедуру AddGoods, то нельзя было бы добавить товар, с датой более текущей. А так как у нас каждая процедура выполняет небольшую задачу, пользователям можно дать возможность выполнять более защищенную AddGoods1, а администраторы могут иметь возможность работы с AddGoods и при особой надобности добавлять товары с любой датой.
Вы можете создавать процедуры, которые будут работать как системные. Для этого вы должны войти под учетной записью администратора и использовать базу данных master, чтобы процедуры сохранялись в этой базе. В этом случае, такие процедуры, будут доступны из любой базы данных.
Процедуры могут и не выполнять каких-либо запросов из базы данных. Например, следующая пользовательская процедура просто возвращает текстовую строку:
Выполнив команду EXEC TestData, на экране появится таблица с одной только строкой. Но процедура все же выполняет запрос SELECT, а ведь можно обойтись и без него, если достаточно только вывести на экран строку. Для вывода на экран достаточно воспользоваться оператором PRINT:
3.2.7. Изменение процедур
Для изменения процедуры используйте оператор ALTER PROCEDURE. Сервер заменяет существующее описание процедуры тем, что указано в ALTER PROCEDURE. Строго рекомендуется не изменять системные процедуры напрямую. Вместо этого создавайте свой собственный вариант, копируйте в нее операторы из существующей процедуры и после этого делайте необходимые изменения.
Если вы хотите изменить процедуру, которая была создана с какими-нибудь опциями, например WITH ENCRYPTION, вы должны включить эти опции в опции ALTER PROCEDURE, для сохранения функциональности, которую предоставляет опция.
Во время выполнения оператора ALTER PROCEDURE изменяется только одна процедура. Если она ссылается на другие, то они не изменяются.
Оператор ALTER PROCEDURE в общем виде выглядит следующим образом:
Следующий пример изменяет процедуру AddGoods1:
Изменения произошли в последнем параметре — @Number. Я установил для него значение по умолчанию 1. Теперь при вызове можно указывать только три значения. Если количество не указано, то будет использоваться значение 1.
3.2.8. Использование процедур при вставке данных
Оператор INSERT может заполнять локальную таблицу результирующим набором, который возвращается из локальной или удаленной процедуры. Сервер SQL заполняет таблицу данными, которые возвращаются оператором SELECT в процедуре. Таблица должна существовать и типы данных должны совпадать.
Рассмотрим эту возможность. Для начала создадим процедуру, которая будет выбирать данные на определенную дату:
Следующий пример использует процедуру для вставки данных в таблицу товаров:
Данный запрос вставляет в таблицу товаров результат выполнения процедуры GetGoods. Количество и типы полей должны совпадать, а у нас они будут совпадать, потому что процедура выбирает данные из той же таблицы товаров данные за указанную дату.
Теперь если просмотреть таблицу товаров, то вы увидите, что данные за первое января 2005-го года в таблице содержаться дважды. Именно на эту дату процедура выбирала данные, и их вставили в таблице товаров. Чтобы лучше было двойные записи, отсортируйте их по дате и названию:
3.2.9. Опции
Теперь посмотрим, какие дополнительные параметры можно использовать во время создания процедуры. Таких параметров два:
- RECOMPILE – указывает на то, что MS SQL Server не должен сохранять план выполнения, компиляция будет происходит при каждом выполнении;
- ENCRYPTION – запись в таблице syscomments с текстом процедуры должна шифроваться.
Посмотрим, как можно использовать шифрование:
Опция WITH ENCRYPTION указывается после всех параметров процедуры, но до ключевого слова AS.
Теперь посмотрим, что сервер сохранил в своих системных таблицах. Для этого выполните следующий запрос:
В колонке text вы увидите только бессмысленные символы. Для любой другой процедуры здесь будет ее текст, а для зашифрованной будут данные, которые не несут полезной информации.
Давайте посмотрим на запрос, который мы использовали для получения информации о процедуре. Здесь у нас выбираются данные из двух таблиц sysobjects и syscomments. В первой таблице находятся имена всех объектов базы данных, а в таблице syscomments находятся параметры объекта. Для хранимой процедуры здесь можно увидеть текст самой процедуры в поле «text», если он не зашифрован.