Ini adalah duplikat dari Dapatkah Anda membuat CLR UDT untuk memungkinkan jenis Tabel bersama di seluruh database?
Pada dasarnya, Tipe Tabel Buatan Pengguna tidak dapat dibagikan di seluruh database. UDT berbasis CLR bisa dibagikan di seluruh basis data, tetapi hanya jika kondisi tertentu telah terpenuhi, seperti Majelis yang sama dimuat ke kedua basis data, dan beberapa hal lainnya (detailnya ada di pertanyaan duplikat yang disebutkan di atas).
Untuk situasi khusus ini, ada cara untuk meneruskan info dari DB1
ke DB2
, meskipun itu bukan solusi yang elegan. Untuk menggunakan Tipe Tabel, konteks database Anda saat ini harus menjadi database tempat Tipe Tabel berada. Ini dilakukan melalui USE
pernyataan, tetapi itu hanya dapat dilakukan dalam SQL dinamis jika perlu dilakukan dalam Prosedur Tersimpan.
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
PERBARUI
Menggunakan sp_executesql
, baik dalam upaya untuk menghindari tabel sementara lokal dengan hanya meneruskan UDTT sebagai TVP, atau hanya sebagai sarana untuk melakukan kueri berparameter, tidak benar-benar berfungsi (meskipun sepertinya memang seharusnya demikian). Artinya, sebagai berikut:
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;
akan gagal pada "@TableTypeDB2 memiliki tipe data yang tidak valid", meskipun dengan benar menampilkan DB2
itu adalah Database "saat ini". Ini ada hubungannya dengan bagaimana sp_executesql
menentukan tipe data variabel karena kesalahan yang dirujuk ke @TableTypeDB2
sebagai "variabel # 2", meskipun dibuat secara lokal dan bukan sebagai parameter input.
Faktanya, sp_executesql
akan error jika satu variabel dideklarasikan (melalui parameter input daftar parameter ke sp_executesql
), walaupun tidak pernah direferensikan, apalagi digunakan. Artinya, kode berikut akan mengalami kesalahan yang sama karena tidak dapat menemukan definisi untuk UDTT yang terjadi dengan kueri tepat di atas:
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
(Terima kasih kepada @Mark Sowul karena telah menyebutkan sp_executesql
tidak berfungsi saat meneruskan variabel)
NAMUN, masalah ini dapat diselesaikan (baik, selama Anda tidak mencoba untuk melewati TVP untuk menghindari tabel temp -- 2 kueri di atas) dengan mengubah database eksekusi sp_executesql
sehingga prosesnya akan lokal ke DB di mana TVP lain ada. Satu hal yang menyenangkan tentang sp_executesql
apakah itu, tidak seperti EXEC
, itu adalah Prosedur Tersimpan, dan prosedur tersimpan sistem pada saat itu, sehingga dapat sepenuhnya memenuhi syarat. Memanfaatkan fakta ini memungkinkan sp_executesql
untuk bekerja, yang juga berarti bahwa tidak perlu USE [DB2];
pernyataan dalam SQL Dinamis. Kode berikut berfungsi:
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