Take the 2-minute tour ×
Database Administrators Stack Exchange is a question and answer site for database professionals who wish to improve their database skills and learn from others in the community. It's 100% free, no registration required.

MS SQL 2008 supports TVP: a useful feature for bulk uploading data to a stored proceedure for processing.

Rather than create a user-defined type, is it possible to leverage an existing table definition? For example, is it possible to create a stored proceedure with the following signature?

CREATE PROCEDURE usp_InsertProductionLocation
@TVP **LocationTable** READONLY

The documentation seems to suggest that this is not possible.

SAMPLE CODE

/*
Sample code from:
http://msdn.microsoft.com/en-us/library/bb510489.aspx
*/

USE AdventureWorks2008R2;
GO

/* Create a table type. */
CREATE TYPE LocationTableType AS TABLE 
( LocationName VARCHAR(50)
, CostRate INT );
GO

/* Create a procedure to receive data for the table-valued parameter. */
CREATE PROCEDURE usp_InsertProductionLocation
    @TVP LocationTableType READONLY
    AS 
    SET NOCOUNT ON
    INSERT INTO [AdventureWorks2008R2].[Production].[Location]
           ([Name]
           ,[CostRate]
           ,[Availability]
           ,[ModifiedDate])
        SELECT *, 0, GETDATE()
        FROM  @TVP;
        GO

/* Declare a variable that references the type. */
DECLARE @LocationTVP 
AS LocationTableType;

/* Add data to the table variable. */
INSERT INTO @LocationTVP (LocationName, CostRate)
    SELECT [Name], 0.00
    FROM 
    [AdventureWorks2008R2].[Person].[StateProvince];

/* Pass the table variable data to a stored procedure. */
EXEC usp_InsertProductionLocation @LocationTVP;
GO

/*
The following is not part of the original source code:
*/

CREATE TABLE LocationTable(
 LocationName VARCHAR(50)
, CostRate INT );
GO
share|improve this question
add comment

3 Answers

up vote 10 down vote accepted

No, you can't leverage an existing table definition, you need to define an explicit type. This was asked for back in 2007 and was closed as "won't fix" but I still strongly encourage you to up-vote and leave a comment describing your use case and how this will help your business be more productive. You could even point to this question to demonstrate how tedious it can be to try and automate this.

Connect #294130

You can do this today, dynamically, though... for example for your simple definition:

-- you would pass these two in as parameters of course:
DECLARE
  @TableName SYSNAME = N'LocationTable',
  @TypeName  SYSNAME = N'LocationTypeTable';

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql = @sql + N',' + CHAR(13) + CHAR(10) + CHAR(9) 
    + QUOTENAME(c.name) + ' '
    + s.name + CASE WHEN LOWER(s.name) LIKE '%char' THEN 
        '(' + CONVERT(VARCHAR(12), (c.max_length/
        (CASE LOWER(LEFT(s.name, 1)) WHEN N'n' THEN 2 ELSE 1 END)) + ')' 
        ELSE '' END
        -- need much more conditionals here for other data types
    FROM sys.columns AS c
    INNER JOIN sys.types AS s
    ON c.system_type_id = s.system_type_id
    AND c.user_type_id = s.user_type_id
    WHERE c.[object_id] = OBJECT_ID(@TableName);

SELECT @sql = N'CREATE TYPE ' + @TypeName
    + ' AS TABLE ' + CHAR(13) + CHAR(10) + (' + STUFF(@sql, 1, 1, '')
    + CHAR(13) + CHAR(10) + ');';

PRINT @sql;
-- EXEC sp_executesql @sql;

Results:

CREATE TYPE LocationTypeTable AS TABLE 
(
    [LocationName] varchar(50),
    [CostRate] int
);

Disclaimer: This does not deal with all kinds of other things like MAX types, precision and scale for numerics, etc. The final solution would have to be more robust to account for all potential column definitions but this should give you a start.

In SQL Server 2012 there are new DMVs and stored procedures that will make it much easier to derive column metadata from existing tables (or stored procedures or even ad hoc queries) without having to mess with all the conditional logic against sys.types and sys.columns. I blogged briefly about these enhancements in December. It's still tedious, but it's somewhere between the awful unmaintainable spaghetti above and the ability to just say " as copy of [table x]"...

share|improve this answer
    
Thank you for taking the time to reply to my inquiry, much appreciated. I had hoped for a different answer :( –  Pressacco Feb 10 '12 at 14:33
    
Thanks for the CONNECT link, went there and voted for it. –  Andrei Rinea Feb 27 '12 at 9:37
    
Giving syntax error –  user960567 Dec 22 '13 at 13:17
add comment

Erland Sommarskog has an extensive article describing how to use TVP.

Have a look, it's worth it!

In short, you cannot use an existing type, just like Aaron Bertrand's earlier answer. But at least it's a bulk transfer..

share|improve this answer
add comment

I dealt with this issue by creating following stored procedure to create a type with same schema existing table may have.

Create PROCEDURE [dbo].[Sp_DefineTypeOutOfTableSchema]
@TableNames NVARCHAR(500)
AS
BEGIN

DECLARE @TableName NVARCHAR(100)
DECLARE @strSQL NVARCHAR(max)
DECLARE @strSQLCol NVARCHAR(1000)
DECLARE @ColName NVARCHAR(100)
DECLARE @ColDataTaype NVARCHAR(50)
DECLARE @ColDefault NVARCHAR(50)
DECLARE @ColIsNulable NVARCHAR(50)
DECLARE @ColCharMaxlen NVARCHAR(50)
DECLARE @ColNumPrec NVARCHAR(50)
DECLARE @ColNumScal NVARCHAR(50)


IF LEN(@TableNames) > 0 SET @TableNames = @TableNames + ',' 

WHILE LEN(@TableNames) > 0 
    BEGIN

        SELECT @TableName = LTRIM(SUBSTRING(@TableNames, 1, CHARINDEX(',', @TableNames) - 1))

        DECLARE schemaCur CURSOR FOR 
        SELECT COLUMN_NAME,DATA_TYPE,IS_NULLABLE,COLUMN_DEFAULT,CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE  FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =@TableName

        OPEN schemaCur

        SELECT @strSQL=''

        FETCH NEXT FROM schemaCur
        INTO @ColName,@ColDataTaype,@ColIsNulable,@ColDefault,@ColCharMaxlen,@ColNumPrec,@ColNumScal

        WHILE @@FETCH_STATUS = 0
        BEGIN
            SELECT @strSQLCol=''
            SELECT @strSQLCol= '['+@ColName+'] '+'[' + @ColDataTaype +'] '

            IF @ColDataTaype='nvarchar' or @ColDataTaype='char'  or @ColDataTaype='varchar' or @ColDataTaype='vchar'
                BEGIN
                    SELECT @strSQLCol=@strSQLCol+ '(' + @ColCharMaxlen +') '
                END 
            ELSE IF @ColDataTaype='numeric' or @ColDataTaype='decimal' 
                BEGIN
                    SELECT @strSQLCol=@strSQLCol +'(' + @ColNumPrec +',' +@ColNumScal + ') '
                END 

            IF @ColIsNulable='YES'
                BEGIN
                    SELECT @strSQLCol=@strSQLCol+ 'NULL '
                END 
            ELSE
                BEGIN
                    SELECT @strSQLCol=@strSQLCol+ ' NOT NULL '
                END 
            IF @ColDefault IS NOT NULL
                BEGIN
                    SELECT @strSQLCol=@strSQLCol+ ' DEFAULT(' +@ColDefault + '),'
                END 
            ELSE
                BEGIN
                    SELECT @strSQLCol=@strSQLCol+ ' ,'
                END

            SELECT @strSQL=@strSQL+@strSQLCol
                --print @strSQL
            FETCH NEXT FROM schemaCur
            INTO @ColName,@ColDataTaype,@ColIsNulable,@ColDefault,@ColCharMaxlen,@ColNumPrec,@ColNumScal

        END

        CLOSE schemaCur
        DEALLOCATE schemaCur

        --print @strSQL
        SELECT @strSQL=left( @strSQL, len(@strSQL)-1)
        --print @strSQL

        IF EXISTS (SELECT * FROM sys.types WHERE IS_TABLE_TYPE = 1 AND name = 't_' +@TableName)
        BEGIN           
            EXEC('DROP TYPE t_' +@TableName )
        END

        SELECT @strSQL =  'CREATE TYPE t_' + @TableName + ' AS TABLE (' +  @strSQL + ')'
        --print @strSQL
        EXEC (@strSQL)
        SELECT @TableNames = SUBSTRING(@TableNames, CHARINDEX(',', @TableNames) + 1, LEN(@TableNames))
END
END

you can use it like this

Exec Sp_DefineTypeOutOfTableSchema 'Table1name,Table2name'

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.