So here is how you can build the DECLARE TABLE
statement dynamically:
DECLARE @sql NVARCHAR(MAX);
SET @sql = N'';
SELECT @sql = @sql + ',
' + c.name + ' ' + t.name
+ CASE
WHEN t.name LIKE '%char' OR t.name LIKE '%binary' THEN
'(' + CASE WHEN c.max_length = -1 THEN 'MAX' ELSE
CONVERT(VARCHAR(4), c.max_length/CASE WHEN t.name LIKE 'n%'
THEN 2 ELSE 1 END) END + ')'
WHEN t.name IN ('float') THEN
'(' + CONVERT(VARCHAR(4), c.precision) + ')'
WHEN t.name IN ('decimal', 'numeric') THEN
'(' + CONVERT(VARCHAR(4), c.precision) + ','
+ CONVERT(VARCHAR(4), c.scale) + ')'
ELSE ''
END
FROM sys.columns AS c
INNER JOIN sys.types AS t
ON c.system_type_id = t.system_type_id
AND c.user_type_id = t.user_type_id
WHERE c.[object_id] = OBJECT_ID('dbo.Employees')
ORDER BY c.column_id;
SET @sql = 'DECLARE @people TABLE (' + STUFF(@sql, 1, 1, '') + '
);';
SELECT @sql;
But now what? You can't insert into it from outside the scope of dynamic SQL:
EXEC sp_executesql @sql;
INSERT @people(id, name) SELECT 1,'foo';
Yields this error:
Msg 1087, Level 15, State 2, ...
Must declare the table variable "@people".
Once again, a scoping issue - @people
only exists in the dynamic SQL and ceases to exist as soon as it's finished. So while you could proceed and append to the @sql
variable:
SET @sql = @sql + 'INSERT @people ...; SELECT id, name FROM @people;';
...this will get out of hand very quickly. And I still have no idea how your C# code can be aware of all the columns and data types involved, but it's too hard to write the SQL to do so... you know you can drag the columns node from Object Explorer onto a query window and it will produce a nice comma-separated list of column names for you, right?