Dette er en kopi af Kan du oprette en CLR UDT for at tillade en delt tabeltype på tværs af databaser?
Grundlæggende kan brugerdefinerede tabeltyper ikke deles på tværs af databaser. CLR-baserede UDT'er kan deles på tværs af databaser, men kun hvis visse betingelser er opfyldt, såsom at den samme samling er indlæst i begge databaser og et par andre ting (detaljerne findes i det dobbelte spørgsmål, der er nævnt ovenfor).
Til denne særlige situation er der en måde at videregive oplysningerne fra DB1
til DB2
, selvom det ikke er en elegant løsning. For at bruge en tabeltype skal din aktuelle databasekontekst være den database, hvori tabeltypen findes. Dette gøres via USE
sætning, men det kan kun gøres i dynamisk SQL, hvis det skal gøres inden for en lagret procedure.
BRUG [DB1];GOCREATE PROCEDURE [dbo].[selectData] @psCustomList CustomList READONLYASBEGIN -- opret en midlertidig tabel, som den kan refereres til i dynamisk SQL CREATE TABLE #TempCustomList ( [ID] [INT], [Vis] [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
OPDATERING
Brug af sp_executesql
, enten i et forsøg på at undgå den lokale midlertidige tabel ved blot at indsætte UDTT'en som en TVP, eller blot som et middel til at lave en parameteriseret forespørgsel, virker faktisk ikke (selvom det bestemt ser ud som det skal). Det betyder følgende:
BRUG [DB1];GOCREATE PROCEDURE dbo.CrossDatabaseTableTypeA( @TheUDTT dbo.TestTable1 LÆSEKUNST)AKTIVET NOCOUNT ON;EXEC sp_executesql N' USE [DB2]; VÆLG DB_NAME() SOM [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;GODECLARE @tmp dbo.TestTable1;INSERT INTO @tmp ([Col1]) VALUES (1), (3);SELECT * FROM @tmp;EXEC dbo.CrossDatabaseTableTypeA @TheUDTT =@tmp;
mislykkes på "@TableTypeDB2 har en ugyldig datatype", selvom den viser den korrekte DB2
er den "aktuelle" database. Det har noget at gøre med hvordan sp_executesql
bestemmer variable datatyper siden fejlen refererede til @TableTypeDB2
som "variabel # 2", selvom den er oprettet lokalt og ikke som en inputparameter.
Faktisk sp_executesql
vil fejle, hvis en enkelt variabel er erklæret (via parameterlistens inputparameter til sp_executesql
), selvom det aldrig er refereret, endsige brugt. Det betyder, at følgende kode vil løbe ind i den samme fejl, som ikke er i stand til at finde definitionen for UDTT, der sker med forespørgslen umiddelbart ovenfor:
USE [DB1];GOCREATE PROCEDURE dbo.CrossDatabaseTableTypeCASSET NOCOUNT ON;EXEC sp_executesql N' USE [DB2]; VÆLG DB_NAME() SOM [CurrentDB]; DECLARE @TableTypeDB2 dbo.TestTable2; ', N'@SomeVar INT', @SomeVar =1;GO
(Tak til @Mark Sowul for at nævne at sp_executesql
virker ikke, når du sender variabler)
MEN, dette problem kan løses (vel, så længe du ikke forsøger at sende TVP'en ind for at undgå temp-tabellen -- 2 forespørgsler ovenfor) ved at ændre udførelsesdatabasen for sp_executesql så processen vil være lokal for den DB, hvori den anden TVP findes. En god ting ved
sp_executesql
er det, i modsætning til EXEC
, det er en lagret procedure og en systemlagret procedure, så den kan kvalificeres fuldt ud. Ved at bruge dette faktum tillader sp_executesql
at arbejde, hvilket også betyder, at der ikke er behov for USE [DB2];
sætning i den dynamiske SQL. Følgende kode virker:
BRUG [DB1];GOCREATE PROCEDURE dbo.CrossDatabaseTableTypeD( @TheUDTT dbo.TestTable1 READONLY)ASSET NOCOUNT ON;-- opret en midlertidig tabel, som den kan refereres til i dynamisk SQLCREATE TABLE #TempList( [ID] [ INT]);INSERT INTO #TempList ([ID]) VÆLG [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] FRA #TempList tmp; EXEC dbo.CrossDatabaseTableTypeB @TableTypeDB2; ', N'@SomeVariable INT', @SomeVariable =1111;GO