這是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
[跨越不同的數據庫傳遞表值參數存儲過程]的可能重複(http://stackoverflow.com/questions/9531769/passing-table-valued-parameter-to-存儲過程跨不同數據庫) –
「所以我的類型在2個數據庫上」 - 不,你的兩個數據庫碰巧有相同的名稱和結構定義的表類型。沒有他們是同一類型的概念。而且您無法定義不同數據庫類型的變量,因此您甚至無法創建正確類型的變量並將數據複製。 –