Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Können Sie einen CLR-UDT erstellen, um einen gemeinsam genutzten Tabellentyp über Datenbanken hinweg zu ermöglichen?

Bist du dir sicher? Benutzerdefinierte Typen sind Objekte auf Datenbankebene, nicht auf Serverebene. Die einzige Möglichkeit, auf sie "universal" zuzugreifen, besteht darin, die Assembly in jede der Datenbanken zu laden und den benutzerdefinierten Typ in jeder Datenbank zu erstellen. So viel steht in der MSDN-Dokumentation zum Registrieren benutzerdefinierter Typen in SQL Server :

Um Ihre spezifischen Fragen zu beantworten:

Weder auf Tabellentypen noch auf benutzerdefinierte Typen kann über Datenbanken zugegriffen werden. Akzeptieren Sie in dem einen Fall CLR-UDTs, wie oben in der MSDN-Dokumentation erwähnt.

Sie können dies nicht, da dies zwei getrennte Dinge sind (d. h. ein „Typ“ vs. ein „Tabellentyp“), im Gegensatz zu nur zwei verschiedenen Implementierungsmethoden (d. h. T-SQL UDF/Stored Proc vs. SQLCLR UDF/Stored Proc).

BEARBEITEN:

Auf rein technischer Ebene ist es möglich, Typen (Tabellentypen und benutzerdefinierte Typen) über Datenbanken hinweg zu verwenden, aber nur durch Umschalten des aktuellen Kontexts über USE Befehl, der nur in Ad-hoc-/dynamischem SQL verwendbar ist. Daher ist diese Verwendung auf praktischer Ebene nur begrenzt anwendbar, aber dennoch möglich, wie das folgende Beispiel zeigt:

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