2013-01-24 36 views
5

我在SQL Server中的一個數據庫中有一個用戶定義的表類型(我們稱之爲DB1)。在SQL Server數據庫之間傳遞用戶定義的表類型

我的類型的定義非常簡單,只包括2列。創建我喜歡的類型下面的腳本是:

CREATE TYPE [dbo].[CustomList] AS TABLE 
(
    [ID] [int] , 
    [Display] [NVARCHAR] (100) 
) 

我也對另一個數據庫運行相同的腳本,所以我喜歡的類型是2個數據庫(我們稱之爲第二個數據庫DB2)。

我現在從我的C#應用​​程序中調用DB1中的存儲過程,並傳遞給我的CustomList用戶定義類型的參數。

DB1中的程序現在需要調用通過此CustomList傳遞的DB2上的過程。

所以,在DB1的程序是這樣的:

ALTER PROCEDURE [dbo].[selectData] 
    @psCustomList CustomList ReadOnly 
AS 
BEGIN 
    EXEC DB2.dbo.selectMoreData @psCustomList 
END 

而且在DB2的程序是這樣的(我只顯示參數列表因爲這是所有需要):

ALTER PROCEDURE [dbo].[selectMoreData] 
    @psCustomList CustomList ReadOnly 
AS 
BEGIN 
...... 

當我運行此我收到以下錯誤:

Operand type clash: CustomList is incompatible with CustomList

任何人有任何想法我做錯了什麼?

我使用SQL Server 2008的

在此先感謝

+0

[跨越不同的數據庫傳遞表值參數存儲過程]的可能重複(http://stackoverflow.com/questions/9531769/passing-table-valued-parameter-to-存儲過程跨不同數據庫) –

+0

「所以我的類型在2個數據庫上」 - 不,你的兩個數據庫碰巧有相同的名稱和結構定義的表類型。沒有他們是同一類型的概念。而且您無法定義不同數據庫類型的變量,因此您甚至無法創建正確類型的變量並將數據複製。 –

回答

7

這是Can you create a CLR UDT to allow for a shared Table type across databases?

重複從本質上講,用戶定義的表類型不能跨數據庫共享。基於CLR的UDT 可以跨數據庫共享,但只有在滿足某些條件(例如將相同的程序集加載到兩個數據庫中)以及其他一些事情(詳細信息位於上述重複問題中)時纔可共享。

對於這種特殊情況,有一種方法可以將信息從DB1傳遞到DB2,儘管它不是一個優雅的解決方案。爲了使用Table Type,您當前的數據庫上下文需要是Table Type所在的數據庫。這是通過USE語句完成的,但只有在需要在存儲過程中完成時才能在動態SQL中完成。

USE [DB1]; 
GO 

CREATE PROCEDURE [dbo].[selectData] 
    @psCustomList CustomList READONLY 
AS 
BEGIN 
    -- create a temp table as it can be referenced in dynamic SQL 
    CREATE TABLE #TempCustomList 
    (
     [ID] [INT], 
     [Display] [NVARCHAR] (100) 
    ); 

    INSERT INTO #TempCustomList (ID, Display) 
     SELECT ID, Display FROM @psCustomList; 

    EXEC(' 
     USE [DB2]; 

     DECLARE @VarCustomList CustomList; 

     INSERT INTO @VarCustomList (ID, Display) 
      SELECT ID, Display FROM #TempCustomList; 

     EXEC dbo.selectMoreData @VarCustomList; 
    '); 
END 

UPDATE

使用sp_executesql,無論是在試圖通過簡單地在UDTT傳遞作爲TVP,以避免局部臨時表,或簡稱爲做一個參數化查詢的手段,不實際上工作(雖然它看起來應該)。這意味着,執行以下操作:

USE [DB1]; 
GO 
CREATE PROCEDURE dbo.CrossDatabaseTableTypeA 
(
    @TheUDTT dbo.TestTable1 READONLY 
) 
AS 
SET NOCOUNT ON; 

EXEC sp_executesql N' 
    USE [DB2]; 
    SELECT DB_NAME() AS [CurrentDB]; 

    DECLARE @TableTypeDB2 dbo.TestTable2; 
    INSERT INTO @TableTypeDB2 ([Col1]) 
    SELECT tmp.[Col1] 
    FROM @TableTypeDB1 tmp; 

    --EXEC dbo.CrossDatabaseTableTypeB @TableTypeDB2; 
    ', 
    N'@TableTypeDB1 dbo.TestTable1 READONLY', 
    @TableTypeDB1 = @TheUDTT; 
GO 


DECLARE @tmp dbo.TestTable1; 
INSERT INTO @tmp ([Col1]) VALUES (1), (3); 
SELECT * FROM @tmp; 

EXEC dbo.CrossDatabaseTableTypeA @TheUDTT = @tmp; 

將於失敗「@ TableTypeDB2有一個無效數據類型」,儘管它正確顯示DB2是「當前」數據庫。它與sp_executesql如何確定變量數據類型有關,因爲將錯誤稱爲@TableTypeDB2爲「變量#2」,即使它是本地創建的而不是輸入參數。

實際上,如果聲明單個變量(通過參數列表輸入參數到sp_executesql),即使從未引用它,也不會使用sp_executesql。含義,下面的代碼會碰上不能夠找到與查詢立即發生上述UDTT定義的同樣的錯誤:

USE [DB1]; 
GO 
CREATE PROCEDURE dbo.CrossDatabaseTableTypeC 
AS 
SET NOCOUNT ON; 

EXEC sp_executesql N' 
    USE [DB2]; 
    SELECT DB_NAME() AS [CurrentDB]; 

    DECLARE @TableTypeDB2 dbo.TestTable2; 
    ', 
    N'@SomeVar INT', 
    @SomeVar = 1; 
GO 

(感謝@馬克Sowul用於提的是,sp_executesql不工作時傳遞變量)

然而,這個問題可以解決(只要你不試圖通過TVP,以避免臨時表-2上面的查詢)通過改變執行數據庫sp_executesql,以便該進程將在其他TVP所在的DB本地。關於sp_executesql的一個好處是,與EXEC不同,它是一個存儲過程,並且是一個系統存儲過程,因此它可以完全限定。利用這個事實允許sp_executesql工作,這也意味着動態SQL中不需要USE [DB2];語句。下面的代碼不工作:

USE [DB1]; 
GO 
CREATE PROCEDURE dbo.CrossDatabaseTableTypeD 
(
    @TheUDTT dbo.TestTable1 READONLY 
) 
AS 
SET NOCOUNT ON; 

-- create a temp table as it can be referenced in dynamic SQL 
CREATE TABLE #TempList 
(
    [ID] [INT] 
); 

INSERT INTO #TempList ([ID]) 
    SELECT [Col1] FROM @TheUDTT; 

EXEC [DB2].[dbo].sp_executesql N' 
    SELECT DB_NAME() AS [CurrentDB]; 

    DECLARE @TableTypeDB2 dbo.TestTable2; 
    INSERT INTO @TableTypeDB2 ([Col1]) 
    SELECT tmp.[ID] 
    FROM #TempList tmp; 

    EXEC dbo.CrossDatabaseTableTypeB @TableTypeDB2; 
    ', 
    N'@SomeVariable INT', 
    @SomeVariable = 1111; 
GO 
+1

請注意,如果您正在使用'sp_executesql',顯然如果您嘗試使用我測試的參數塊 –

+0

@MarkSowul,則無法正常工作並查看您的意思。我更新以添加該信息。謝謝! –

+0

不完全 - 使用*任何*參數到'sp_executesql'就可以做到。我還在使用臨時表;我只是在傳遞一些無害的東西。然後你會在動態SQL裏面看到奇怪的錯誤,抱怨使用了表類型(即使你用'USE'切換了dbs) –

相關問題