Đây là một bản sao của Can you create a CLR UDT to allow for a shared Table type across databases?
Về cơ bản, người dùng định nghĩa các loại Bảng không thể chia sẻ trên cơ sở dữ liệu. UDTs dựa trên CLR có thể được chia sẻ trên cơ sở dữ liệu, nhưng chỉ khi một số điều kiện đã được đáp ứng, chẳng hạn như cùng một Assembly được nạp vào cả hai cơ sở dữ liệu và một vài thứ khác (chi tiết trong câu hỏi trùng lặp nêu trên).
Đối với trường hợp cụ thể này, có cách để chuyển thông tin từ DB1
đến DB2
, mặc dù đây không phải là giải pháp thanh lịch. Để sử dụng Kiểu Bảng, ngữ cảnh cơ sở dữ liệu hiện tại của bạn cần phải là cơ sở dữ liệu trong đó Kiểu Bảng tồn tại. Điều này được thực hiện thông qua câu lệnh USE
, nhưng điều đó chỉ có thể được thực hiện trong SQL động nếu cần phải được thực hiện trong một thủ tục được lưu trữ.
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
CẬP NHẬT
Sử dụng sp_executesql
, hoặc trong một nỗ lực để tránh những bảng tạm thời địa phương bằng cách đơn giản đi qua trong UDTT như một TVP, hoặc đơn giản là một phương tiện để thực hiện một truy vấn tham số, không thực sự làm việc (mặc dù nó chắc chắn trông giống như nó nên). Có nghĩa là, như sau:
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;
sẽ thất bại trên "@ TableTypeDB2 có một kiểu dữ liệu hợp lệ", mặc dù nó đúng sẽ hiển thị rằng DB2
là "hiện tại" Cơ sở dữ liệu.Nó có một cái gì đó để làm với cách sp_executesql
xác định kiểu dữ liệu biến kể từ khi lỗi được gọi là "#là" biến # 2 ", mặc dù nó được tạo cục bộ chứ không phải là tham số đầu vào.
Thực tế, sp_executesql
sẽ báo lỗi nếu một biến duy nhất được khai báo (thông qua tham số nhập tham số danh sách sp_executesql
), ngay cả khi nó không bao giờ được tham chiếu, hãy để một mình sử dụng. Có nghĩa là, các mã sau đây sẽ gặp phải lỗi tương tự không thể tìm định nghĩa cho UDTT điều đó xảy ra với các truy vấn ngay lập tức trên:
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
(Nhờ @ Mark Sowul đề cập đến rằng sp_executesql
không làm việc khi đi qua các biến)
BAO GIỜ, vấn đề này có thể được giải quyết (tốt, miễn là bạn không cố gắng truyền vào TVP để tránh bảng tạm thời - 2 truy vấn ở trên) bằng cách thay đổi cơ sở dữ liệu thực hiện của sp_executesql
để quá trình này sẽ là cục bộ cho DB trong đó TVP kia tồn tại. Một điều tốt đẹp về sp_executesql
là, không giống như EXEC
, nó là một thủ tục lưu trữ, và một hệ thống lưu trữ thủ tục tại đó, do đó, nó có thể được hoàn toàn đủ điều kiện. Việc sử dụng thực tế này cho phép sp_executesql
hoạt động, điều này cũng có nghĩa là không cần phải có câu lệnh USE [DB2];
trong SQL động. Mã sau đây không hoạt động:
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
có thể trùng lặp của [Bảng thông số Tham số có giá trị để lưu trữ trên các cơ sở dữ liệu khác nhau] (http://stackoverflow.com/questions/9531769/passing-table-valued-parameter-to- –
"vì vậy loại của tôi là trên 2 cơ sở dữ liệu" - không, hai cơ sở dữ liệu của bạn xảy ra để có các loại bảng được xác định với tên và cấu trúc giống nhau. Không có khái niệm nào về chúng cùng loại. Và bạn không thể xác định một biến của một kiểu cơ sở dữ liệu khác nhau, vì vậy bạn thậm chí không thể tạo một biến kiểu đúng và sao chép dữ liệu trên. –