sql-server - 您能否创建 CLR UDT 以允许跨数据库共享表类型?

标签 sql-server sql-server-2008 tsql sqlclr user-defined-types

如果我有这样的 SQL 语句:

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. 如何在 C# CLR 中定义一个 UDT,其中 UDT 本质上是一个 UDT“AS TABLE”

最佳答案

I know you can create CLR types, register the assembly to SQL Server, and then access the custom type universally.

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

Using UDTs Across Databases
UDTs are by definition scoped to a single database. Therefore, a UDT defined in one database cannot be used in a column definition in another database. In order to use UDTs in multiple databases, you must execute the CREATE ASSEMBLY and CREATE TYPE statements in each database on identical assemblies. Assemblies are considered identical if they have the same name, strong name, culture, version, permission set, and binary contents.

Once the UDT is registered and accessible in both databases, you can convert a UDT value from one database for use in another. Identical UDTs can be used across databases in the following scenarios:

  • Calling stored procedure defined in different databases.
  • Querying tables defined in different databases.
  • Selecting UDT data from one database table UDT column and inserting it into a second database with an identical UDT column.

In these situations, any conversion required by the server occurs automatically. You are not able to perform the conversions explicitly using the Transact-SQL CAST or CONVERT functions.

回答您的具体问题:

1) Is there a way without using the CLR to create global scope in SQL 2008 R2 for a table variable, and if not...

表类型和用户定义类型都不能跨数据库访问,在一种情况下接受 CLR UDT,如上文在 MSDN 文档中所述。

2) How can I define a UDT in C# CLR, in which the UDT is essentially a UDT "AS TABLE"

你不能,因为它们是两个独立的事物(即“类型”与“表类型”),而不是两种不同的实现方式(即 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

关于sql-server - 您能否创建 CLR UDT 以允许跨数据库共享表类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8036713/

相关文章:

sql server 2008 按问题排序

sql-server - SQL Server 大型日志文件

tsql - 循环遍历数据库时出现不一致的游标结果

sql-server - sql server 可选参数 : syntax for between clause

sql-server - SQL 上的 String.Join 等效项是什么?

php - 尽量减少 SQL 语句? - 堆栈 SQL 查询?

sql - 如何检查光标是否存在(打开状态)

java - parseInt SQL 计数(*)

sql - 使用查询和静态值插入从 sql 查询中选择

sql-server - T-SQL 从字符串中返回每隔一个字符