2011-11-07 76 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以及常見的訪問類型,正如您所瞭解的那樣。所以,很高興你有一些工作:-)。 –

相關問題