I know you can create CLR types, register the assembly to SQL Server,
and then access the custom type universally.
Are you sure about this? User-Defined Types are database-level objects, not server-level. The only way to access them "universally" is by loading the Assembly into each of the databases and creating the User-Defined Type in each database. This much is stated in the MSDN documentation for Registering User-Defined Types in SQL Server:
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.
To answer your specific questions:
1) Is there a way without using the CLR to create global scope in SQL 2008 R2 for a table variable, and if not...
Neither Table Types nor User-Defined Types are accessible across databases, accept in the one case for CLR UDTs as noted above in the MSDN documenation.
2) How can I define a UDT in C# CLR, in which the UDT is essentially a UDT "AS TABLE"
You cannot as those are two separate things (i.e. a "Type" vs a "Table Type") as opposed to being just two different means of implementation (i.e. T-SQL UDF / Stored Proc vs SQLCLR UDF / Stored Proc).
EDIT:
On a purely technical level, it is possible to use Types (Table Types and User-Defined Types) across databases, but only by switching the current context via the USE
command which is only usable in ad hoc / dynamic SQL. Hence, this usage has limited applicability on a practical level, but nonetheless it is still possible as the following example shows:
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