Bluedog67

Random Thoughts About SQL Server and My Dog Blue

About Bluedog67

My name is Stephen Horne. I am a well-trained owner of an Australian Cattle Dog named Blue. I also develop software mainly using SQL Server, ASP.NET, and C#. I love data, databases, T-SQL, and turning raw data into actionable information. My plan for this blog is to write about SQL Server and sometimes my dog Blue. Please contact me at stephen at bluedog67 dot com. Follow me on Twitter at bluedog67.

Possible Workaround: Query => SP With TVP

@Kenny recently tweeted the following: "it really is unfortunate that you can't supply a query as a parameter to a func/sproc that accepts a table parameter #sqlserver" Sounded like an interesting problem. I suggested creating a wrapper stored procudure where you passed in the query that you wanted to populate the TVP.

Following is a kludge that might work. Seems to work, but not sure if it is exactly what @Kenny was looking for. Interesting problem for sure!

The code is heavily based upon the sample included in the SQL 2008 BOL for Table-Valued Parameters (Database Engine). The code is definitely on the quick and dirty side! Tested only on SQL Server 2008 Dev Ed.

USE AdventureWorks;
GO

DELETE [AdventureWorks].[Production].[Location]
WHERE LocationID NOT IN (SELECT LocationID FROM [AdventureWorks].[Production].[ProductInventory])

IF EXISTS (SELECT * FROM SYSOBJECTS WHERE NAME = 'usp_InsertProductionLocation')
DROP PROCEDURE usp_InsertProductionLocation;

IF EXISTS (SELECT * FROM SYSOBJECTS WHERE NAME = 'usp_TEST_TVP')
DROP PROCEDURE usp_TEST_TVP;

IF EXISTS (SELECT * FROM SYSTYPES WHERE NAME = 'LocationTableType')
DROP TYPE LocationTableType;

/* Create a table type. */
CREATE TYPE LocationTableType AS TABLE
( LocationName VARCHAR(50)
, CostRate SMALLMONEY); -- changed from int to match table
GO

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

-- NEW STUFF Follows:
-- wrapper sp
CREATE PROCEDURE usp_TEST_TVP
@SQL NVARCHAR(4000)
AS
BEGIN -- start of new sp
  
  SET NOCOUNT ON;
  
  -- must match table type
  CREATE TABLE #temp
  (LocationName VARCHAR(50),
  CostRate SMALLMONEY);
  
  DECLARE @EXECSQL nvarchar(4000);
  SET @EXECSQL = 'INSERT INTO #temp (LocationName, CostRate) ' + @SQL;
  EXECUTE(@EXECSQL);
  
  /* Declare a variable that references the type. */
  DECLARE @LocationTVP
  AS LocationTableType;
  
  /* Add data to the table variable. */
  INSERT INTO @LocationTVP (LocationName, CostRate)
  SELECT LocationName, CostRate
  FROM #temp;
  
  DROP TABLE #temp;
  
  /* Pass the table variable data to a stored procedure. */
  EXEC usp_InsertProductionLocation @LocationTVP;
  
END -- end of new sp
GO

-- TEST CODE
-- Note: For this example the SELECT clause must match table
-- type and #temp Table structure - datatype, size and order.

-- BEFORE - should be empty
SELECT *
FROM [AdventureWorks].[Production].[Location]
WHERE CostRate = 7.77;

DECLARE @SQL nvarchar(4000);
-- Change as necessary
SET @SQL = 'SELECT DISTINCT [Name], 7.77 FROM [AdventureWorks].[Person].[CountryRegion];'
EXEC [dbo].[usp_TEST_TVP] @SQL;
GO

-- AFTER - should return values (238 rows on my system).
SELECT *
FROM [AdventureWorks].[Production].[Location]
WHERE CostRate = 7.77;

Categories: SQL Server
Permalink | Comments (1) | Post RSSRSS comment feed

Comments

Kenneth Younger United States

Friday, December 04, 2009 10:30 PM

Kenneth Younger

Wow. Way to take a random tweet and work through it! You definitely did find a method to "use a query as a parameter".

If you could specify something like this it would be pretty cool:

declare @i int;
set @i = dbo.fnReturnsIntAcceptsTableParam((select col1 from table1))

If that were possible, you could do all sorts of neat stringing together of TVFs that accept and return "tables" (result sets). Hopefully MS is working on this for the future.