EXECUTE (Transact-SQL)

在 Transact-SQL 批次執行命令字串或字元字串,或下列一個模組:系統預存程序、使用者定義預存程序、純量值使用者定義函數或擴充預存程序。

安全性注意事項安全性注意事項

在您利用字元字串呼叫 EXECUTE 之前,請先驗證該字元字串。千萬不要執行從未經驗證的使用者輸入所建構的命令。如需詳細資訊,請參閱<SQL 資料隱碼>。

SQL Server 會擴充 EXECUTE 陳述式,讓它可用來將傳遞命令傳送到連結伺服器。另外,執行字串或命令所在的內容,也可以明確設定。

主題連結圖示Transact-SQL 語法慣例

語法

Execute a stored procedure or function
[ { EXEC | EXECUTE } ]
    { 
      [ @return_status = ]
      { module_name [ ;number ] | @module_name_var } 
        [ [ @parameter = ] { value 
                           | @variable [ OUTPUT ] 
                           | [ DEFAULT ] 
                           }
        ]
      [ ,...n ]
      [ WITH RECOMPILE ]
    }
[;]

Execute a character string
{ EXEC | EXECUTE } 
        ( { @string_variable | [ N ]'tsql_string' } [ + ...n ] )
    [ AS { LOGIN | USER } = ' name ' ]
[;]

Execute a pass-through command against a linked server
{ EXEC | EXECUTE }
        ( { @string_variable | [ N ] 'command_string [ ? ]' } [ + ...n ]
        [ { , { value | @variable [ OUTPUT ] } } [ ...n ] ]
        ) 
    [ AS { LOGIN | USER } = ' name ' ]
    [ AT linked_server_name ]
[;]

引數

  • @return\_status
    這是儲存模組傳回狀態的選擇性整數變數。這個變數必須先在批次、預存程序或函數中宣告之後,才能用在 EXECUTE 陳述式。

    當您利用 @return\_status 變數叫用純量值使用者定義函數時,該變數可以是任何純量資料類型。

  • module_name
    這是您要呼叫的預存程序或純量值使用者定義函數的完整或不完整名稱。模組名稱必須符合識別碼的規則。無論伺服器定序為何,擴充預存程序的名稱一定有大小寫區分。

    已在另一個資料庫建立的模組,如果執行它的使用者擁有它,或者具有適當的權限可以在該資料庫執行它,那麼這個模組就可以執行。如果執行某個模組的使用者,具有適當的權限可以使用該伺服器 (遠端存取),以及在該資料庫中執行該模組,就可以在另一個執行 SQL Server 的伺服器上執行該模組。如果指定了伺服器名稱,但沒有指定資料庫名稱,則 SQL Server Database Engine 會在該使用者的預設資料庫中尋找該模組。

  • ; number
    這是用來將同名程序分組的選擇性整數。這個參數不用於擴充預存程序。

    [!附註]

    未來的 Microsoft SQL Server 版本將移除這項功能。請避免在新的開發工作中使用這項功能,並規劃修改目前使用這項功能的應用程式。

    如需有關程序群組的詳細資訊,請參閱<CREATE PROCEDURE (Transact-SQL)>。

  • @module\_name\_var
    這是在本機定義的變數名稱,它代表模組名稱。

  • @parameter
    這是 module_name 的參數,在模組中定義。參數名稱前面必須加上 @ 記號 (@)。搭配 @parameter\_name=value 格式使用時,參數名稱和常數不必以它們在模組中定義的順序來提供。不過,只要有任何參數採用 @parameter\_name=value 格式,所有後續的參數就必須採用該格式。

    依預設,參數可為 Null。

  • value
    這是要傳遞到模組或傳遞命令的參數值。如果未指定參數名稱,參數值就必須依照模組所定義的順序來提供。

    在對連結伺服器執行傳遞命令時,參數值的順序會隨著連結伺服器的 OLE DB 提供者而不同。大部分的 OLE DB 提供者,都會將值由左到右繫結到參數。

    如果參數值是物件名稱、字元字串或者由資料庫名稱或結構描述名稱所限定,則必須以單引號括住整個名稱。如果參數值是關鍵字,則必須以雙引號括住關鍵字。

    如果預設值是在模組中定義,使用者就可以直接執行該模組,不必指定參數。

    預設值也可以是 NULL。通常,模組定義會指定當參數值為 NULL 時,應該採取什麼動作。

  • @variable
    這是儲存參數或傳回參數的變數。

  • OUTPUT
    指定讓模組或命令字串傳回參數。模組或命令字串中的相符參數,也必須先利用 OUTPUT 關鍵字加以建立。當您把資料指標變數當做參數使用時,請使用這個關鍵字。

    如果 value 被定義為針對連結伺服器執行之模組的 OUTPUT,則對 OLE DB 提供者執行之對應 @parameter 所做的變更,會在模組執行結束時複製回變數。

    如果 OUTPUT 參數正在使用中,且其目的是在呼叫批次或模組的其他陳述式中使用傳回值,則參數值必須被當做變數加以傳遞,例如,@parameter = @variable。您不可以針對未在模組中定義為 OUTPUT 參數的參數指定 OUTPUT,來執行模組。您不可以使用 OUTPUT,將常數傳遞到模組;傳回參數需要一個變數名稱。在執行該程序之前,必須先宣告該變數的資料類型,並且指定一值。

    當 EXECUTE 針對遠端預存程序使用時,或者針對連結伺服器執行傳遞命令時,OUTPUT 參數就不能是任何一種大型物件 (LOB) 資料類型。

    傳回參數可以是 LOB 資料類型以外的任何資料類型。

  • DEFAULT
    提供模組所定義的參數預設值。如果該模組所預期的參數值並沒有定義的預設值,而且不是遺漏一個參數,就是指定了 DEFAULT 關鍵字,此時就會發生錯誤。

  • WITH RECOMPILE
    在執行模組之後,強制編譯、使用和捨棄新計畫。如果該模組有現有的查詢計畫,這個計畫便會保留在快取中。

    如果您所提供的參數不合規則,或者如果資料已經大幅變更,請使用這個選項。這個選項不用於擴充預存程序。我們建議您少用這個選項,因為它的成本很高。

    [!附註]

    呼叫使用 OPENDATASOURCE 語法的預存程序時,您無法使用 WITH RECOMPILE。指定物件名稱四部分時,會忽略 WITH RECOMPILE 選項。

  • @string\_variable
    這是區域變數的名稱。@string_variable 可以是任何 char、varchar、nchar 或 nvarchar 資料類型。其中包含 (max) 資料類型在內。

  • [N] 'tsql_string'
    這是常數字串。tsql_string 可以是任何 nvarchar 或 varchar 資料類型。如果包含 N,則字串解譯為 nvarchar 資料類型。

  • AS <context_specification>
    指定執行陳述式的內容。如需詳細資訊,請參閱<瞭解執行內容>。

  • LOGIN
    指定您要模擬的內容是登入。模擬範圍是伺服器。

  • USER
    指定您要模擬的內容是目前資料庫中的使用者。模擬範圍僅限於目前資料庫。通往資料庫使用者的內容切換,不會繼承該使用者的伺服器層級權限。

    重要注意事項重要事項

    如果通往資料庫使用者的內容切換在使用中,任何人想要存取資料庫以外的資源,都會導致陳述式失敗。其中包括 USE database 陳述式、分散式查詢以及使用三部分或四部分識別碼來參考另一個資料庫的查詢。若要擴充目前資料庫以外的內容切換範圍,請參閱<使用 EXECUTE AS 擴充資料庫模擬>。

  • 'name'
    有效的使用者或登入名稱。name 必須是 sysadmin 固定伺服器角色的成員,或者以主體形式分別存在於 sys.database_principalssys.server_principals 中。

    name 不可以是內建帳戶,例如 NT AUTHORITY\LocalService、NT AUTHORITY\NetworkService 或 NT AUTHORITY\LocalSystem。

    如需詳細資訊,請參閱本主題稍後的「指定使用者或登入名稱」。

  • [N] 'command_string'
    這是包含要傳遞到連結伺服器之命令的常數字串。如果包含 N,則字串解譯為 nvarchar 資料類型。

  • [?]
    指出為其在 EXEC('…', <arg-list>) AT <linkedsrv> 陳述式所使用之通過命令 <arg-list> 中提供值的參數。

  • AT linked_server_name
    指定 command_string 是對 linked_server_name 執行,並且將結果 (如果有的話) 傳回用戶端。linked_server_name 必須參考本機伺服器中現有的連結伺服器定義。連結伺服器是利用 sp_addlinkedserver 所定義。

備註

您可以利用 value 或 @parameter\_name = value. 來提供參數。參數不是交易的一部分;因此,如果交易中的參數變更之後再回復,參數值並不會還原為之前的值。傳回呼叫者的值,一定是模組傳回時的值。

當一個模組呼叫另一個模組,或者參考 Common Language Runtime (CLR) 模組、使用者定義類型或彙總,來執行 Managed 程式碼時,就會產生巢狀結構。當被呼叫的模組或 Managed 程式碼參考開始執行時,巢狀層級便開始累加;而當被呼叫的模組或 Managed 程式碼參考完成時,就開始遞減。如果超過 32 個巢狀層級上限時,完整的呼叫鏈便會失敗。目前巢狀層級是儲存在 @@NESTLEVEL 系統函數中。

由於遠端預存程序和擴充預存程序不在交易範圍內 (除非在 BEGIN DISTRIBUTED TRANSACTION 陳述式中發出,或者搭配各種組態選項使用),因此透過呼叫它們來執行的命令,是無法回復的。如需詳細資訊,請參閱<系統預存程序 (Transact-SQL)>和<BEGIN DISTRIBUTED TRANSACTION (Transact-SQL)>。

當您使用資料指標變數時,如果您執行的程序所傳遞的資料指標變數,配置了一個資料指標,此時就會發生錯誤。

在執行模組時,如果陳述式是批次中的第一個陳述式,則不必指定 EXECUTE 關鍵字。

搭配預存程序使用 EXECUTE

當您執行預存程序時,如果陳述式是批次中的第一個陳述式,則不必指定 EXECUTE 關鍵字。

SQL Server 系統預存程序是以 sp_ 字元開頭。它們實際上是儲存在 Resource 資料庫中,但在邏輯上是顯示在每個系統和使用者定義資料庫的 sys 結構描述中。當您在批次或模組內 (例如,使用者定義的預存程序或函數) 執行系統預存程序時,我們建議您以 sys 結構描述名稱,來限定預存程序名稱。

SQL Server 系統擴充預存程序是以 xp_ 字元開頭,而且這些字元包含在 master 資料庫的 dbo 結構描述中。當您在批次或模組內 (例如,使用者定義的預存程序或函數) 執行系統擴充預存程序時,我們建議您以 master.dbo 來限定預存程序的名稱。

當您在批次或模組內 (例如,使用者定義的預存程序或函數) 執行使用者定義的預存程序時,我們建議您以結構描述名稱,來限定預存程序名稱。我們不建議您以和系統預存程序相同的名稱,為使用者定義預存程序命名。如需有關執行預存程序的詳細資訊,請參閱<執行預存程序 (Database Engine)>。

搭配字元字串使用 EXECUTE

在舊版的 SQL Server 中,字元字串不能超過 8,000 位元組。若要進行動態執行,就必須串連大型字串。在 SQL Server 中,您可以指定 varchar(max) 和 nvarchar(max) 資料類型,讓它接受最多達 2 GB 資料的字元字串。

您對資料庫內容所做的變更,只會維持到 EXECUTE 陳述式結束為止。例如,當下面這個陳述式中的 EXEC 執行之後,資料庫內容為 master。

USE master; EXEC ('USE AdventureWorks; SELECT EmployeeID, Title FROM HumanResources.Employee;');

內容切換

您可以使用 AS { LOGIN | USER } = ' name ' 子句,來切換動態陳述式的執行內容。當內容切換被指定為 EXECUTE ('string') AS <context_specification> 時,內容切換的持續時間就限於目前所執行的查詢範圍內。如需詳細資訊,請參閱<瞭解內容切換>。

指定使用者或登入名稱

AS { LOGIN | USER } = ' name ' 中所指定的使用者或登入名稱,必須以主體形式分別存在於 sys.database_principals 或 sys.server_principal 中,否則陳述式就會失敗。此外,還必須授與主體的 IMPERSONATE 權限。除非呼叫端是資料庫擁有者,或是 sysadmin 固定伺服器角色的成員,否則主體必須存在,即使當使用者透過 Windows 群組成員資格在存取資料庫或 SQL Server 的執行個體時也一樣。例如,假設有下列情況:

  • CompanyDomain\SQLUsers 群組擁有 Sales 資料庫的存取權。

  • CompanyDomain\SqlUser1 是 SQLUsers 的成員,因此對 Sales 資料庫具有隱含的存取權。

雖然 CompanyDomain\SqlUser1 擁有透過 SQLUsers 群組中的成員資格,對資料庫進行存取的權限,但是 EXECUTE @string\_variable AS USER = 'CompanyDomain\SqlUser1' 陳述式會失敗,因為 CompanyDomain\SqlUser1 並未以主體形式存在於資料庫中。

最佳作法

指定一個登入或使用者,它具有執行在陳述式或模組中定義的作業時所需要的最低權限。例如,如果只需要資料庫層級權限,就不要指定具有伺服器層級權限的登入名稱;或者除非需要其權限,否則不要指定資料庫擁有者帳戶。

權限

執行 EXECUTE 陳述式不需要任何權限。不過,您必須對 EXECUTE 字串內所參考的安全性實體具備權限。例如,如果字串包含 INSERT 陳述式,EXECUTE 陳述式的呼叫者就必須有目標資料表的 INSERT 權限。發現 EXECUTE 陳述式時,會檢查權限,即使模組內包含 EXECUTE 陳述式也一樣。

模組的 EXECUTE 權限預設會授與模組的擁有者,這位擁有者可以將這些權限轉讓給其他使用者。當您執行某個執行字串的模組時,會檢查執行模組之使用者內容中的權限,不過不會檢查建立模組之使用者內容中的權限。然而,如果同一位使用者擁有呼叫模組,而該模組正被呼叫時,第兩個模組就不會再檢查一次 EXECUTE 權限。如需詳細資訊,請參閱<擁有權鏈結>。

如果模組要存取其他資料庫物件,只要您具有該模組的 EXECUTE 權限,而且下列一項為真,就可以順利執行:

  • 模組被標示為 EXECUTE AS USER 或 SELF,而且模組擁有者具有參考物件的對應權限。

  • 模組被標示為 EXECUTE AS CALLER,而且您具有物件的對應權限。

  • 模組被標示為 EXECUTE AS user_name,而且 user_name 具有物件的對應權限。

內容切換權限

若要指定某項登入的 EXECUTE AS 權限,則這位呼叫者必須具有指定登入名稱的 IMPERSONATE 權限。若要指定資料庫使用者的 EXECUTE AS 權限,則這位呼叫者必須具有指定使用者名稱的 IMPERSONATE 權限。如果未指定任何執行內容,或者沒有指定 EXECUTE AS CALLER,就不需要 IMPERSONATE 權限。

範例

A. 使用 EXECUTE 來傳遞單一參數

uspGetEmployeeManagers 預存程序預期需要一個參數 (@EmployeeID)。下列範例會將 Employee ID 6 作為參數值,來執行 uspGetEmployeeManagers 預存程序。

USE AdventureWorks;
GO
EXEC dbo.uspGetEmployeeManagers 6;
GO

變數可以在執行作業中明確命名:

EXEC dbo.uspGetEmployeeManagers @EmployeeID = 6;
GO

如果下列陳述式是某個批次、osqlsqlcmd 指令碼中的第一個陳述式,則不需要 EXEC。

dbo.uspGetEmployeeManagers 6;
GO
--Or
dbo.uspGetEmployeeManagers @EmployeeID = 6;
GO

B. 使用多個參數

下列範例會執行 spGetWhereUsedProductID 預存程序。它會傳遞兩個參數:第一個參數是產品識別碼 (819),第二個參數 @CheckDate, 則是 datetime 值。

USE AdventureWorks;
GO
DECLARE @CheckDate datetime;
SET @CheckDate = GETDATE();
EXEC dbo.uspGetWhereUsedProductID 819, @CheckDate;
GO

C. 搭配變數使用 EXECUTE 'tsql_string'

下列範例會顯示 EXECUTE 如何處理含有變數的動態建立字串。這個範例會建立 tables_cursor 資料指標,來保存一份 AdventureWorks 資料庫中所有使用者定義資料表的清單,然後再利用這份清單,在資料表重建所有的索引。

USE AdventureWorks;
GO
DECLARE tables_cursor CURSOR
   FOR
   SELECT s.name, t.name 
   FROM sys.objects AS t
   JOIN sys.schemas AS s ON s.schema_id = t.schema_id
   WHERE t.type = 'U';
OPEN tables_cursor;
DECLARE @schemaname sysname;
DECLARE @tablename sysname;
FETCH NEXT FROM tables_cursor INTO @schemaname, @tablename;
WHILE (@@FETCH_STATUS <> -1)
BEGIN;
   EXECUTE ('ALTER INDEX ALL ON ' + @schemaname + '.' + @tablename + ' REBUILD;');
   FETCH NEXT FROM tables_cursor INTO @schemaname, @tablename;
END;
PRINT 'The indexes on all tables have been rebuilt.';
CLOSE tables_cursor;
DEALLOCATE tables_cursor;
GO

D. 搭配遠端預存程序使用 EXECUTE

下列範例會在遠端伺服器 SQLSERVER1 中執行 uspGetEmployeeManagers 預存程序,並且儲存傳回狀態,指出 @retstat 是成功還是失敗。

DECLARE @retstat int;
EXECUTE @retstat = SQLSERVER1.AdventureWorks.dbo.uspGetEmployeeManagers @EmployeeID = 6;

E. 搭配預存程序變數使用 EXECUTE

下列範例會建立一個代表預存程序名稱的變數。

DECLARE @proc_name varchar(30);
SET @proc_name = 'sys.sp_who';
EXEC @proc_name;

F. 搭配 DEFAULT 使用 EXECUTE

下列範例會在第一個和第三個參數採用預設值,來建立預存程序。在執行程序時,如果呼叫沒有傳遞任何值,或者如果未指定預設值,就會在第一個和第三個參數插入這些預設值。請注意各種可以使用 DEFAULT 關鍵字的方法。

USE AdventureWorks;
GO
IF OBJECT_ID(N'dbo.ProcTestDefaults', N'P')IS NOT NULL
   DROP PROCEDURE dbo.ProcTestDefaults;
GO
-- Create the stored procedure.
CREATE PROCEDURE dbo.ProcTestDefaults (
@p1 smallint = 42, 
@p2 char(1), 
@p3 varchar(8) = 'CAR')
AS 
   SET NOCOUNT ON;
   SELECT @p1, @p2, @p3
;
GO

您可以利用多種組合執行 Proc_Test_Defaults 預存程序。

-- Specifying a value only for one parameter (@p2).
EXECUTE dbo.ProcTestDefaults @p2 = 'A';
-- Specifying a value for the first two parameters.
EXECUTE dbo.ProcTestDefaults 68, 'B';
-- Specifying a value for all three parameters.
EXECUTE dbo.ProcTestDefaults 68, 'C', 'House';
-- Using the DEFAULT keyword for the first parameter.
EXECUTE dbo.ProcTestDefaults @p1 = DEFAULT, @p2 = 'D';
-- Specifying the parameters in an order different from the order defined in the procedure.
EXECUTE dbo.ProcTestDefaults DEFAULT, @p3 = 'Local', @p2 = 'E';
-- Using the DEFAULT keyword for the first and third parameters.
EXECUTE dbo.ProcTestDefaults DEFAULT, 'H', DEFAULT;
EXECUTE dbo.ProcTestDefaults DEFAULT, 'I', @p3 = DEFAULT;

G. 搭配 AT linked_server_name 使用 EXECUTE

下列範例會傳遞一個命令字串到遠端伺服器。它會建立一個連結伺服器 SeattleSales,指向 SQL Server 的另一個執行個體,然後對該連結伺服器執行 DDL 陳述式 (CREATE TABLE)。

EXEC sp_addlinkedserver 'SeattleSales', 'SQL Server'
GO
EXECUTE ( 'CREATE TABLE AdventureWorks.dbo.SalesTbl 
(SalesID int, SalesName varchar(10)) ; ' ) AT SeattleSales;
GO

H. 使用 EXECUTE WITH RECOMPILE

下列範例會執行 Proc_Test_Defaults 預存程序,並在執行模組之後,強制編譯、使用和捨棄新的查詢計畫。

EXECUTE dbo.Proc_Test_Defaults @p2 = 'A' WITH RECOMPILE;
GO

I. 搭配使用者定義函數使用 EXECUTE

下列範例會執行 ufnGetSalesOrderStatusText 純量使用者定義函數。它會使用變數 @returnstatus 來儲存該函數傳回的值。該函數會預期接受一個輸入參數 @Status。它定義為 tinyint 資料類型。

USE AdventureWorks;
GO
DECLARE @returnstatus nvarchar(15);
SET @returnstatus = NULL;
EXEC @returnstatus = dbo.ufnGetSalesOrderStatusText @Status = 2;
PRINT @returnstatus;
GO

J. 使用 EXECUTE 來查詢連結伺服器上的 Oracle 資料庫

下列範例會執行遠端 Oracle 伺服器上的若干 SELECT 陳述式。這個範例一開始就加入 Oracle 伺服器作為連結伺服器,並且建立連結伺服器登入。

-- Setup the linked server.
EXEC sp_addlinkedserver  
        @server='ORACLE',
        @srvproduct='Oracle',
        @provider='OraOLEDB.Oracle', 
        @datasrc='ORACLE10';

EXEC sp_addlinkedsrvlogin 
    @rmtsrvname='ORACLE',
    @useself='false', 
    @locallogin=null, 
    @rmtuser='scott', 
    @rmtpassword='tiger';
 
EXEC sp_serveroption 'ORACLE', 'rpc out', true;
GO
 
-- Execute several statements on the linked Oracle server.
EXEC ( 'SELECT * FROM scott.emp') AT ORACLE;
GO
EXEC ( 'SELECT * FROM scott.emp WHERE MGR = ?', 7902) AT ORACLE;
GO
DECLARE @v INT; 
SET @v = 7902;
EXEC ( 'SELECT * FROM scott.emp WHERE MGR = ?', @v) AT ORACLE;
GO

K. 使用 EXECUTE AS USER 將內容切換到另一位使用者

下列範例會執行 Transact-SQL 字串來建立一個資料表,以及指定 AS USER 子句,將陳述式的執行內容,從呼叫者切換到 User1。在執行陳述式時,Database Engine 會檢查 User1 的權限。User1 在資料庫中必須以使用者的身分存在,而且必須有權在 Sales 結構描述中建立資料表,否則陳述式就會失敗。

USE AdventureWorks;
GO
EXECUTE ('CREATE TABLE Sales.SalesTable (SalesID int, SalesName varchar(10));')
AS USER = 'User1';
GO

L. 對 EXECUTE 和 AT linked_server_name 使用參數

下列範例會使用問號 (?) 預留位置代表參數,將命令字串傳遞至遠端伺服器。它會建立一個連結伺服器 SeattleSales,指向 SQL Server 的另一個執行個體,然後對該連結伺服器執行 SELECT 陳述式。SELECT 陳述式會使用問號當做 ProductID 參數 (952) 的預留位置,而這會提供在陳述式之後。

-- Setup the linked server.
EXEC sp_addlinkedserver 'SeattleSales', 'SQL Server'
GO
-- Execute the SELECT statement.
EXECUTE ('SELECT ProductID, Name 
    FROM AdventureWorks.Production.Product
    WHERE ProductID = ? ', 952) AT SeattleSales;
GO