Поделиться через


Хранимая процедура sp_executesql (Transact-SQL)

Выполняет инструкцию Transact-SQL или пакет инструкций, которые могут выполняться много раз или создаваться динамически. Инструкция Transact-SQL или пакет инструкций могут содержать параметры.

Примечание по безопасностиПримечание по безопасности

Компиляция инструкций Transact-SQL во время выполнения открывает путь для атак злоумышленников, например, методом SQL injection.

Значок ссылки на разделСинтаксические обозначения в Transact-SQL

Синтаксис

sp_executesql [ @statement = ] statement
[ 
    { , [ @params = ] N'@parameter_name data_type [ OUT | OUTPUT ][ ,...n ]' } 
     { , [ @param1 = ] 'value1' [ ,...n ] }
]

Аргументы

  • [ @statement = ] statement
    Строка в Юникоде, содержащая инструкцию или пакет Transact-SQL. Аргумент statement должен представлять собой константу в Юникоде или переменную в этом же формате. Более сложные выражения Юникода, например объединение двух строк с помощью оператора +, недопустимы. Символьные константы недопустимы. Если константа в Юникоде указывается, она должна начинаться с префикса N. Например, константа Юникода N'sp_who' допустима, а символьная константа 'sp_who' нет. Размер строки ограничивается только доступной серверу баз данных памятью. В 64-разрядных версиях сервера размер строки ограничен 2 ГБ — максимальным размером типа nvarchar(max).

    ПримечаниеПримечание

    Текст аргумента stmt может содержать параметры, называющиеся аналогично именам переменных, например: N'SELECT * FROM HumanResources.Employee WHERE EmployeeID = @IDParameter'

    Каждый параметр, включенный в аргумент stmt, должен иметь соответствующую запись в списке определений параметров @params и в списке значений параметров.

  • [ @params = ] N'@parameter_namedata_type [ ,... n ] '
    Строка, содержащая определения всех параметров, внедренных в stmt. Строка должна представлять собой константу в Юникоде либо переменную в этом же формате. Каждое определение параметра состоит из имени параметра и типа данных. n — заполнитель, означающий определения дополнительных параметров. Каждый параметр, указанный в аргументе statement, должен быть определен в аргументе @params. Если инструкция или пакет инструкций языка Transact-SQL в аргументе stmt не содержат параметров, @params может отсутствовать. Этот аргумент по умолчанию принимает значение NULL.

  • [ @param1 = ] 'value1'
    Значение для первого параметра, определенного в строке параметров. Это значение может быть константой или переменной в Юникоде. Каждому параметру, указанному в stmt, должно соответствовать значение. Если инструкция или пакет инструкций Transact-SQL в stmt не содержат параметров, список значений может отсутствовать.

  • [ OUT | OUTPUT ]
    Показывает, что параметр процедуры является выходным. Параметры типов text, ntext и image могут быть выходными, если процедура не является процедурой CLR. Выходным параметром с ключевым словом OUTPUT может быть заполнитель курсора, если процедура не является процедурой CLR.

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

Значения кода возврата

0 (успешное завершение) или ненулевое значение (неуспешное завершение)

Результирующие наборы

Возвращает результирующие наборы всех заданных инструкций SQL, встроенные в строку SQL.

Замечания

Относительно пакетов инструкций, области имен и контекста базы данных процедура sp_executesql ведет себя аналогично инструкции EXECUTE. Инструкция или пакет инструкций Transact-SQL в параметре stmt процедуры sp_executesql не компилируются до выполнения инструкции sp_executesql. Содержимое stmt затем компилируется и выполняется в качестве отдельного плана выполнения, не зависящего от плана выполнения пакета, вызвавшего процедуру sp_executesql. Пакет, содержащийся в процедуре sp_executesql, не может ссылаться на переменные, объявленные в пакете, вызвавшем sp_executesql. Локальные курсоры или переменные в пакете sp_executesql недоступны пакету, вызвавшему sp_executesql. Изменения в контексте базы данных длятся только до завершения выполнения инструкции sp_executesql.

Процедура sp_executesql может использоваться вместо хранимых процедур для многократного выполнения инструкций Transact-SQL, где единственные различия между инструкциями — значения параметров. Так как инструкция Transact-SQL сама остается неизменной и меняются только значения параметров, оптимизатор запросов SQL Server, вероятнее всего, повторно использует план выполнения, сформированный перед первым выполнением.

ПримечаниеПримечание

Для улучшения производительности используйте полные имена объектов в строке инструкции.

Хранимая процедура sp_executesql поддерживает задание значений параметрам отдельно от строки Transact-SQL, как показано в следующем примере.

DECLARE @IntVariable int;
DECLARE @SQLString nvarchar(500);
DECLARE @ParmDefinition nvarchar(500);

/* Build the SQL string one time.*/
SET @SQLString =
     N'SELECT BusinessEntityID, NationalIDNumber, JobTitle, LoginID
       FROM AdventureWorks2008R2.HumanResources.Employee 
       WHERE BusinessEntityID = @BusinessEntityID';
SET @ParmDefinition = N'@BusinessEntityID tinyint';
/* Execute the string with the first parameter value. */
SET @IntVariable = 197;
EXECUTE sp_executesql @SQLString, @ParmDefinition,
                      @BusinessEntityID = @IntVariable;
/* Execute the same string with the second parameter value. */
SET @IntVariable = 109;
EXECUTE sp_executesql @SQLString, @ParmDefinition,
                      @BusinessEntityID = @IntVariable;

Выходные параметры также могут быть использованы sp_executesql. В следующем примере название задания получается из таблицы AdventureWorks2008R2.HumanResources.Employee и возвращается в выходном параметре @max_title.

DECLARE @IntVariable int;
DECLARE @SQLString nvarchar(500);
DECLARE @ParmDefinition nvarchar(500);
DECLARE @max_title varchar(30);

SET @IntVariable = 197;
SET @SQLString = N'SELECT @max_titleOUT = max(JobTitle) 
   FROM AdventureWorks2008R2.HumanResources.Employee
   WHERE BusinessEntityID = @level';
SET @ParmDefinition = N'@level tinyint, @max_titleOUT varchar(30) OUTPUT';

EXECUTE sp_executesql @SQLString, @ParmDefinition, @level = @IntVariable, @max_titleOUT=@max_title OUTPUT;
SELECT @max_title;

Возможность подставлять разные значения параметров в sp_executesql предоставляет следующие преимущества перед использованием инструкции EXECUTE.

  • Так как собственно текст инструкции Transact-SQL в строке sp_executesql не меняется между выполнениями, оптимизатор запросов, вероятнее всего, сопоставит инструкцию Transact-SQL во время второго выполнения с планом выполнения, сформированным во время первого выполнения. Следовательно, компиляция второй инструкции SQL Server не обязательна.

  • Строка Transact-SQL строится только один раз.

  • Целочисленный параметр определен в собственном формате. Приведение к Юникоду не требуется.

Разрешения

Требуется членство в роли public.

Примеры

А. Выполнение простой инструкции SELECT

В следующем примере создается и выполняется простая инструкция SELECT, содержащая внедренный параметр с именем @level.

EXECUTE sp_executesql 
          N'SELECT * FROM AdventureWorks2008R2.HumanResources.Employee 
          WHERE BusinessEntityID = @level',
          N'@level tinyint',
          @level = 109;

Б. Выполнение динамически построенной строки

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

CREATE TABLE May1998Sales
    (OrderID int PRIMARY KEY,
    CustomerID int NOT NULL,
    OrderDate  datetime NULL
        CHECK (DATEPART(yy, OrderDate) = 1998),
    OrderMonth int
        CHECK (OrderMonth = 5),
    DeliveryDate datetime  NULL,
        CHECK (DATEPART(mm, OrderDate) = OrderMonth)
    )

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

ПримечаниеПримечание

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

CREATE PROCEDURE InsertSales @PrmOrderID INT, @PrmCustomerID INT,
                 @PrmOrderDate DATETIME, @PrmDeliveryDate DATETIME
AS
DECLARE @InsertString NVARCHAR(500)
DECLARE @OrderMonth INT

-- Build the INSERT statement.
SET @InsertString = 'INSERT INTO ' +
       /* Build the name of the table. */
       SUBSTRING( DATENAME(mm, @PrmOrderDate), 1, 3) +
       CAST(DATEPART(yy, @PrmOrderDate) AS CHAR(4) ) +
       'Sales' +
       /* Build a VALUES clause. */
       ' VALUES (@InsOrderID, @InsCustID, @InsOrdDate,' +
       ' @InsOrdMonth, @InsDelDate)'

/* Set the value to use for the order month because
   functions are not allowed in the sp_executesql parameter
   list. */
SET @OrderMonth = DATEPART(mm, @PrmOrderDate)

EXEC sp_executesql @InsertString,
     N'@InsOrderID INT, @InsCustID INT, @InsOrdDate DATETIME,
       @InsOrdMonth INT, @InsDelDate DATETIME',
     @PrmOrderID, @PrmCustomerID, @PrmOrderDate,
     @OrderMonth, @PrmDeliveryDate

GO

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

В. Использование параметра OUTPUT

В следующем примере параметр OUTPUT используется для хранения результирующего набора, формируемого инструкцией SELECT в параметре @SQLString.Затем выполняются две инструкции SELECT, использующие значение параметра OUTPUT.

USE AdventureWorks2008R2;
GO
DECLARE @SQLString nvarchar(500);
DECLARE @ParmDefinition nvarchar(500);
DECLARE @SalesOrderNumber nvarchar(25);
DECLARE @IntVariable int;
SET @SQLString = N'SELECT @SalesOrderOUT = MAX(SalesOrderNumber)
    FROM Sales.SalesOrderHeader
    WHERE CustomerID = @CustomerID';
SET @ParmDefinition = N'@CustomerID int,
    @SalesOrderOUT nvarchar(25) OUTPUT';
SET @IntVariable = 22276;
EXECUTE sp_executesql
    @SQLString
    ,@ParmDefinition
    ,@CustomerID = @IntVariable
    ,@SalesOrderOUT = @SalesOrderNumber OUTPUT;
-- This SELECT statement returns the value of the OUTPUT parameter.
SELECT @SalesOrderNumber;
-- This SELECT statement uses the value of the OUTPUT parameter in
-- the WHERE clause.
SELECT OrderDate, TotalDue
FROM Sales.SalesOrderHeader
WHERE SalesOrderNumber = @SalesOrderNumber;

Дополнительные примеры см. в разделе Использование sp_executesql.