Questo è un duplicato di Can you create a CLR UDT to allow for a shared Table type across databases?
In sostanza, Tipi di tabella definiti dall'utente non possono essere condivisi tra i database. Gli UDT basati su CLR possono essere condivisi tra i database,, ma solo se sono state soddisfatte determinate condizioni, ad esempio lo stesso assembly viene caricato in entrambi i database e alcune altre cose (i dettagli sono nella domanda duplicata sopra riportata).
Per questa particolare situazione, c'è un modo per passare le informazioni da DB1
a DB2
, anche se non è una soluzione elegante. Per utilizzare un tipo di tabella, il contesto del database corrente deve essere il database in cui esiste il tipo di tabella. Questo viene fatto tramite l'istruzione USE
, ma ciò può essere fatto solo in SQL dinamico se è necessario farlo all'interno di una stored procedure.
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
Utilizzando sp_executesql
, sia nel tentativo di evitare la tabella temporanea locale semplicemente passando l'UDTT come TVP, o semplicemente come un mezzo per fare una query con parametri, non fa funziona davvero (anche se certamente sembra che dovrebbe). Significato, il seguente:
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;
falliranno su "@ TableTypeDB2 ha un tipo di dati non valido", anche se è visualizzato correttamente che DB2
è il database "corrente".Ha qualcosa a che fare con il modo in cui sp_executesql
determina i tipi di dati variabili poiché l'errore si riferisce a @TableTypeDB2
come "variabile # 2", anche se viene creato localmente e non come parametro di input.
Infatti, sp_executesql
errore se viene dichiarata una singola variabile (tramite il parametro di input della lista parametri su sp_executesql
), anche se non viene mai fatto riferimento, per non parlare di utilizzato. Cioè, il seguente codice verrà eseguito nello stesso errore di non riuscire a trovare la definizione per l'UDTT che accade con la query immediatamente sopra:
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
(Grazie a @ Mark Sowul per ricordare che sp_executesql
non fa lavoro quando si passa in variabili)
TUTTAVIA, questo problema può essere risolto (beh, se non si sta tentando di passare in TVP per evitare la tabella temporanea - 2 query sopra) cambiando il database di esecuzione di sp_executesql
in modo che il processo sia locale al DB in cui esiste l'altro TVP. Una cosa bella di sp_executesql
è che, a differenza di EXEC
, si tratta di una stored procedure e di una stored procedure di sistema, quindi può essere pienamente qualificato. Facendo uso di questo fatto, è possibile utilizzare sp_executesql
, il che significa anche che non è necessaria l'istruzione USE [DB2];
all'interno di SQL dinamico. Il seguente codice funziona:
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
possibile duplicato del [Passando tabella dei parametri con valori di stored procedure attraverso diversi database] (http://stackoverflow.com/questions/9531769/passing-table-valued-parameter-to- stored-procedure-across-different-databases) –
"così il mio tipo è su 2 database" - no, due dei tuoi database hanno tipi di tabella definiti con nomi e strutture identici. Non c'è il concetto che siano dello stesso tipo. E non puoi definire una variabile di un tipo di database diverso, quindi non puoi nemmeno creare una variabile del tipo giusto e copiare i dati attraverso. –