Sun*_*Sun 7 sql-server user-defined-types sql-server-2008
我在SQL Server的一个数据库中有一个用户定义的表类型(让我们调用它DB1
).
我的类型的定义非常简单,只包含2列.创建我的类型的脚本如下:
CREATE TYPE [dbo].[CustomList] AS TABLE
(
[ID] [int] ,
[Display] [NVARCHAR] (100)
)
Run Code Online (Sandbox Code Playgroud)
我也在另一个数据库上运行相同的脚本,所以我的类型在2个数据库上(让我们调用第二个数据库DB2
).
我现在DB1
从我的C#app 调用存储过程传入我的CustomList
用户定义类型的参数.
DB1
现在的过程需要调用一个DB2
传递过程的过程CustomList
.
所以,程序DB1
看起来像这样:
ALTER PROCEDURE [dbo].[selectData]
@psCustomList CustomList ReadOnly
AS
BEGIN
EXEC DB2.dbo.selectMoreData @psCustomList
END
Run Code Online (Sandbox Code Playgroud)
过程DB2
就像这样(我只显示参数列表,因为这就是所需要的):
ALTER PROCEDURE [dbo].[selectMoreData]
@psCustomList CustomList ReadOnly
AS
BEGIN
......
Run Code Online (Sandbox Code Playgroud)
当我运行这个时,我收到以下错误:
操作数类型冲突:CustomList与CustomList不兼容
任何人都有任何想法我做错了什么?
我正在使用SQL Server 2008.
提前致谢
这是重复的是否可以创建CLR UDT以允许跨数据库的共享表类型?
实质上,用户定义的表类型不能跨数据库共享.基于CLR的UDT 可以跨数据库共享,但仅在满足某些条件时才会共享,例如同一个程序集被加载到两个数据库中,以及其他一些事项(详细信息在上面提到的重复问题中).
对于这种特殊情况,有一种方法可以将信息传递DB1
给DB2
,尽管它不是一个优雅的解决方案.要使用表类型,您当前的数据库上下文必须是表类型所在的数据库.这是通过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
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
将失败"@ TableTypeDB2具有无效的数据类型",即使它正确显示DB2
"当前"数据库.它与如何sp_executesql
确定变量数据类型有关,因为错误被@TableTypeDB2
称为"变量#2",即使它是在本地创建而不是作为输入参数.
事实上,sp_executesql
如果声明单个变量(通过参数列表输入参数to 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
Run Code Online (Sandbox Code Playgroud)
(感谢@Mark Sowul提到sp_executesql
在传递变量时不起作用)
但是,这个问题可以解决(好吧,只要你不试图传入TVP以避免临时表 - 上面的2个查询)通过更改执行数据库,sp_executesql
以便进程将是另一个TVP所在的DB的本地.一个很好的事情sp_executesql
是,与EXEC
它不同,它是一个存储过程,以及一个系统存储过程,因此它可以完全合格.利用这个事实可以sp_executesql
工作,这也意味着不需要USE [DB2];
动态SQL中的语句.以下代码确实有效:
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
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
11031 次 |
最近记录: |