2011-11-07 44 views
3

如果我有一个SQL语句,像这样的:您可以创建CLR UDT以允许跨数据库共享表类型吗?

CREATE TYPE [dbo].[typeRateLimitVariables] AS TABLE(
      [vchColumnName] [varchar](250) NULL, 
      [decColumnValue] [decimal](25, 10) NULL 
) 

而且我用它作为表变量的UDF在数据库中,我有足够的范围。假设我想从同一服务器上的另一个数据库中调用标量UDF,那么最终会出现未知类型的错误。

我试着在调用数据库上创建类型,但obv。那么我得到一个类型不匹配,因为虽然每个UDT都有相同的名称,但它们有不同的作用域,因此是不同的类型。

我知道你可以创建CLR类型,将程序集注册到SQL Server,然后通用访问自定义类型。我的想法是创建一个类型为“TABLE”的CLR UDT,但是我看不出如何实现这一点,因为我知道它必须是CLR类型“SqlDbType.Structured”;

我的问题是:

  1. 有不使用CLR在SQL创建全球范围内2008 R2的表变量的方式,如果不...
  2. 我如何定义一个UDT在C#CLR,其中UDT本质上是一个UDT“正如表”
+0

似乎题外话大多数UDT讨论,但对于问题#1 - 它必须是一个表变量?变量(包括表变量)对调用上下文是本地的 - 即命令。您可以使用完整符号([数据库]。[角色]。[对象])编写多数据库操作,只要它们存在于一个查询中,就可以将数据戳入和导出表变量。 #temp表也可能工作。 – jklemmack

+0

是的,在这种特殊情况下,我希望有这种类型可以随身携带,这就是为什么它需要成为UDT;解决方案非常大 - 所以是的; #temp通常是一个很好的解决方案,但是在这个特别的解决方案中,我们在整个演出中都使用了UDT,而不是简单地使用即席查询。 –

回答

4

我知道你可以创建CLR类型,注册程序集到SQL Server, 然后访问自定义类型普遍。

您确定吗?用户定义的类型是数据库级别的对象,而不是服务器级别的。 “普遍”访问它们的唯一方法是将程序集加载到每个数据库中,并在每个数据库中创建用户定义类型。这多少是MSDN文档中陈述了Registering User-Defined Types in SQL Server

使用UDT的跨数据库
的UDT是通过作用域为一个单一的 数据库定义。因此,在一个数据库中定义的UDT不能用于另一个数据库中的 列定义。为了使用 多个数据库中的UDT,必须在相同组件的每个数据库中执行CREATE ASSEMBLY和CREATE TYPE语句。如果组件 具有相同的名称,强名称, 文化,版本,权限集和二进制内容,则认为它们完全相同。

一旦UDT在两个数据库中注册并可访问,您可以将 转换为一个数据库中的UDT值以便在另一个数据库中使用。相同 的UDT可跨数据库在下列情况下使用:在不同的数据库中定义

  • 调用存储过程。
  • 查询在不同数据库中定义的表。
  • 从一个数据库表UDT列中选择UDT数据,并将其插入具有相同UDT列的第二个数据库中。

在这些情况下,服务器所需的任何转换都会自动发生 。您无法使用Transact-SQL CAST或CONVERT函数明确执行转换 。

为了回答您的具体问题:

1)是否有不使用CLR创建于2008年SQL全球范围内对R2表变量的方式,如果不是......

不论是表类型还是用户定义类型都可以跨数据库访问,在一种情况下,接受CLR UDTs,如上面在MSDN文档中所述。

2)我如何定义在C#CLR一个UDT,其中UDT本质上是一个UDT“正如表”

你不能因为这是两个不同的东西(即“类型” vs“Table Type”),而不仅仅是两种不同的实现方式(即T-SQL UDF/Stored Proc与SQLCLR UDF/Stored Proc)。

编辑:

在一个纯粹的技术水平,它可以使用跨数据库类型(表类型和用户定义类型),但仅通过经由USE命令切换当前上下文,其仅适用于临时/动态SQL。因此,这种用法有一个实用水平有限的适用性,但尽管如此它仍然是可能的,因为下面的例子显示:

SET ANSI_NULLS ON; 
SET QUOTED_IDENTIFIER ON; 
SET NOCOUNT ON; 
GO 

USE [msdb]; 
GO 

PRINT 'Creating [GlobalTableDef] Table Type in [msdb]...'; 
CREATE TYPE dbo.GlobalTableDef 
AS TABLE 
(
    [ID] INT NOT NULL IDENTITY(17, 22), 
    [CreateDate] DATETIME NOT NULL DEFAULT (GETDATE()), 
    [Something] NVARCHAR(2000) NULL 
); 
GO 

PRINT 'Creating [TotalBytes] Function in [msdb]...'; 
GO 
CREATE FUNCTION dbo.TotalBytes 
(
    @TableToSummarize dbo.GlobalTableDef READONLY 
) 
RETURNS INT 
AS 
BEGIN 
    DECLARE @TotalBytes INT = 0; 

SELECT @TotalBytes += (4 + 8 + DATALENGTH(COALESCE(tmp.Something, ''))) 
    FROM @TableToSummarize tmp; 

    RETURN @TotalBytes; 
END; 
GO 

PRINT 'Testing the Table Type and Function...'; 
DECLARE @TmpTable dbo.GlobalTableDef; 
INSERT INTO @TmpTable (Something) VALUES (N'this is a test'); 
INSERT INTO @TmpTable (Something) VALUES (NULL); 
INSERT INTO @TmpTable (Something) VALUES (N'still seems to be a test'); 

SELECT * FROM @TmpTable; 

SELECT dbo.TotalBytes(@TmpTable) AS [TotalBytesUsed]; 
GO 

USE [tempdb]; 
GO 
PRINT 'Creating [TypeTest] Proc in [tempdb]...'; 
GO 

CREATE PROCEDURE dbo.TypeTest 
AS 
SET NOCOUNT ON; 

    SELECT 1 AS [Step], DB_NAME() AS [CurrentDB]; 

    EXEC(' 
     SELECT 2 AS [Step], DB_NAME() AS [CurrentDB]; 
     USE [msdb]; 
     SELECT 3 AS [Step], DB_NAME() AS [CurrentDB]; 
     DECLARE @TmpTable dbo.GlobalTableDef; 
     USE [tempdb]; 
     SELECT 4 AS [Step], DB_NAME() AS [CurrentDB]; 

     -- local query to prove context is tempdb 
     SELECT TOP 5 * FROM sys.objects; 

     INSERT INTO @TmpTable (Something) VALUES (N''this is a new test''); 
     INSERT INTO @TmpTable (Something) VALUES (NULL); 
     INSERT INTO @TmpTable (Something) VALUES (N''non-empty value''); 
     INSERT INTO @TmpTable (Something) VALUES (NULL); 
     INSERT INTO @TmpTable (Something) VALUES (N''woo-hoo!!!!!!!!!!!!!!!''); 
     SELECT * FROM @TmpTable; 

     SELECT [msdb].dbo.TotalBytes(@TmpTable) AS [TotalBytesUsed]; 
    '); 

GO 

USE [master]; 
GO 

SELECT 5 AS [Step], DB_NAME() AS [CurrentDB]; 
EXEC tempdb.dbo.TypeTest; 

-------------------------------- 

USE [tempdb]; 
GO 
IF (OBJECT_ID(N'tempdb.dbo.TypeTest') IS NOT NULL) 
BEGIN 
    PRINT 'Dropping [TypeTest] Proc from [tempdb]...'; 
    DROP PROCEDURE dbo.TypeTest; 
END; 
GO 

USE [msdb]; 
GO 
IF (OBJECT_ID(N'dbo.TotalBytes') IS NOT NULL) 
BEGIN 
    PRINT 'Dropping [TotalBytes] Function from [msdb]...'; 
    DROP FUNCTION dbo.TotalBytes; 
END; 
GO 

IF (EXISTS(
     SELECT * 
     FROM sys.table_types stt 
     WHERE stt.name = N'GlobalTableDef' 
    )) 
BEGIN 
    PRINT 'Dropping [GlobalTableDef] Table Type from [msdb]...'; 
    DROP TYPE dbo.GlobalTableDef; 
END; 
GO 
+0

在声明“我知道您可以创建CLR类型,将程序集注册到SQL Server,然后通用访问自定义类型”,我的意思是CLR程序集可以绑定到单个表的范围内。 –

+0

关于这一点的最后一点,我们最终要解决的问题以及我越来越依赖的解决方案是使用模式进行分离而不是整个数据库,除非绝对必要,对相关但分离的数据结构进行分类时。 –

+0

@AndrewLaGrange:关于“普遍访问自定义类型”的声明,我错误地解释了_universally_意味着跨数据库,显然;-)。关于通过Schema vs Database进行分离,按照惯例,两者都有优点和缺点。如果您有大量数据,那么单独的数据库允许单独备份等。但是,具有单独模式的相同数据库允许使用FK以及常见的访问类型,正如您所了解的那样。所以,很高兴你有一些工作:-)。 –

相关问题