Table-valued parameters in SQL 2005

October 20, 2011

Can’t be done? Oh, but it can. Let me show you.

Just quickly, a Table-Valued Parameter is a useful thing introduced in SQL 2008 that lets you have a read-only parameter which is a table type, passed into a stored procedure. To use it you need to have a user-defined table type, so that you can define what is going to be passed in. You can read about them at

The 2008 code looks something like this:

But this wasn’t possible in SQL 2005. We didn’t have user-defined table types, and we certainly didn’t have table-valued parameters.

Except that we could still do something very similar. This was something I’d taken for granted, but when I showed this to someone at the PASS Summit, and then someone else, I got persuaded to write a blog post on it.

If you haven’t seen this idea before, I’m sure you’ll kick yourself. It’s remarkably simple, but I think it’s quite powerful. Like I said – I’d taken it for granted.

The idea is this: make a VIEW with an INSTEAD OF trigger, using the inserted table instead of the table variable.

That INSTEAD OF trigger is essentially where your stored procedure is kept. A trigger is still a procedure, it’s just not stored in the traditional list of stored procedures. But it will act just like one.

As for the view – that can just be a placeholder. Think of it as simply defining the columns you need to handle. You don’t need a FROM clause, and you don’t even need any rows to come back. I like to put a contradiction in there so that I don’t think there’s any real values coming out.

So a trigger doesn’t take a table-valued parameter, but it can leverage the inserted and deleted tables that are available in triggers. For us, we’re just interested in the former. Have a look at the code, and you’ll see what I mean.

This code can run on SQL 2005 (well, it can also run on later versions, but that’s less important).

So there you have it – a useful TVP equivalent in versions prior to SQL 2008. I get that I’m probably writing this post about ten years too late. Sorry about that.

But if you’re not fond of the idea of having to declare and populate a table variable, then perhaps this idea is for you. This method will support any type of inserting, whether it’s row-by-row, or the results of a single SELECT statement. One day though, TVPs won’t be READONLY any more (this doesn’t seem to be the case for SQL Server 2012 unfortunately), and when that happens, you’ll want to definitely be using TVPs.


This Post Has 10 Comments

  1. mjswart

    Hi Rob,
    The biggest value I see in TVPs is to be able to send sets of data to SQL Server from an application efficiently (Where the declaration and population of tables is taken care of).
    I’m curious, do you see any scenarios where this insert-into-view method would get used or is this just a neat little trick?

  2. Frank Hell

    Holy Cow!
    What would Joe Celko say to this trigger abuse? 🙂
    I nice idea, but intransparent – I won’t use in my code…

  3. Atul Thakor

    I remember when reading :
    The author gave a good example of where he used XML to replace a large number of parameters being passed into a stored procedure.
    I imagine a table value parameter would be an even better option to pass a large number of parameters into a stored procedure.
    Also… thinking about stored procedures… people can pass null’s as parameter values which you sometimes need to handle in the sproc.
    Using the TVP you can enforce non-null values being passed in where you absolutely need them!

  4. Rob Farley

    Michael – The obvious scenario is 2005, of course. But also, the fact that you don’t have to declare and populate a table variable could be advantageous for some environments.
    Frank – that’s ok. It’s just putting an idea out there. I realise that code in triggers is not as obvious as code in stored procs, but I would also suggest that DBAs should be aware of all the places that code can exist.
    Atul – yes, there’re lots of reasons why a TVP is a more elegant solution. 🙂

  5. Alexander Kuznetsov

    Very nice. Very very nice.
    Have you benchmarked it against more traditional approaches, like Erland does in his articles?
    When I had to send lots of numbers, like 50K or 100K integers, over to the server, sending an array in binary format as an image worked best for me on SQL 2005.

  6. Brad Schulz

    Just caught up on some of my blog reading and finally read this entry.
    Always love your out-of-the-box thinking.  Very nice.

  7. Dave Green (Sydney ex- RBA)

    Not 10 years too late at all. Some large Australian banks are *still* deploying enterprise-wide applications onto SQL Server 2005.
    I know, I know…
    Anyhoo it’s a nice idea to use the trigger, but I probably stick with passing my varchar(max) csv string as a parameter and splitting it inside the proc via a table function.

  8. Bill

    Nice.  I was going to do something similar, I was going to use a view to call a web service api to update the remote data.  This way lower mortals can use their table skills and access programs to transparently update cloud data.
    Never thought of using it as you described here.  That’s a good idea.
    As for worrying about whether the "view" is interpreted as a proc by a human, then just prefix the view with vsp_, for example vsp_DoIt.

  9. Mr. T

    Very nice article!
    I am actually passing a DataTable from my .net application to SQL Server using table type. Now I need to make that work in 2005. Not sure how to incorporate your idea into this scenario.

Leave a Reply

LobsterPot Blogs

Blog posts by Rob Farley and other LobsterPot Solutions team members.