سؤال

I can find information on creating procedures with table-valued parameters, and information on table literals, but I can’t find any mention of the two combined.

Suppose I have a procedure defined something like:

create type info as table(stuff int, more text);

create procedure test(@id int,@data info) as
begin
    -- etc
end;

I would like to execute the procedure using a table literal instead of assigning values into a variable. I would like to be able to do something like this:

execute test 42,(values((1,'one'),(2,'deux'),(3,'drei')) as (stuff,more));

It doesn’t seem to work.

I know I can create a variable and do it that way, and that is the method generally used in examples.

Is there a way to use a a syntax similar to the above? If so, how?

I want to this partly for the exercise, but more importantly, it seems to me that since table literals are part of the language, it should be possible to use them wherever tables are required.

In this regard I think there are gaps in the implementation. Finally, I think that using a literal is sometimes simpler and more intuitive, so creating a variable just to pass information through is a kludge.

هل كانت مفيدة؟

المحلول

No, you must create a table variable, insert the records into that table variable, then pass the table variable to the procedure.

The way that people used to do what you are describing is with pipe delimited text strings. For example, passing '1|Tyler|Smith|2|Jack|Blade|3|Someother|Guy' and then having the stored procedure unpack it. But that methodology has completely fallen out of favor compared to using table valued parameters.

نصائح أخرى

A few other details to consider:

  1. Regarding:

    it seems to me that since table literals are part of the language, it should be possible to use them wherever tables are required.

    That does seem reasonable. However, the problem / confusion here is that a bad assumption is being inferred: that the existence of Table-Valued Parameters (TVPs) implies that it is a table that is being passed in. But this is not what is happening. If it were, other forms of tables would work:

    • Actual Tables and Views: dbo.TableOrViewName
    • Temporary Tables: #TempTable
    • Derived Tables: (SELECT Something FROM dbo.Somewhere)
    • Table-Valued Functions: dbo.SomeTVF(Param)
  2. Even if Tables were allowed as input parameters, the Table Value Constructor (TVC) might not work, depending on how Microsoft implements it. When used as the VALUES clause of an INSERT ... VALUES statement, there is a limit of 1000 rows (thanks to Michael B for clarifying this). This could easily be worked-around by doing an INSERT ... SELECT FROM (VALUES...) such that the TVC is a derived table (which has no row limit), but it would really be up to the SQL Server programmers to determine how to accomplish this request. For more details / testing of the TVC, please see: Maximum Number of Rows for the Table Value Constructor.

  3. If you want to pass in a small amount of data as rows without needing to create a TVP, then you can pass in that "table" marked up as XML or JSON (depending on the version of SQL Server):

    • When marking up as XML (available starting with SQL Server 2005), use the .nodes function to iterate through the rows:

      CREATE PROCEDURE dbo.TestXML(@ID INT, @Data XML)
      AS
      BEGIN
         SET NOCOUNT ON;
      
         SELECT tbl.col.value(N'./@stuff', 'INT') AS [Stuff],
                tbl.col.value(N'./@more', 'VARCHAR(MAX)') AS [More]
         FROM   @Data.nodes(N'/tbl/row') tbl(col);
      
        ... other stuff
      END;
      

      And then test with:

      EXEC dbo.TestXML
             @ID = 42,
             @Data = N'<tbl><row stuff="1" more="one" /><row stuff="2" more="deux" />
        <row stuff="3" more="drei" /></tbl>';
      
    • When marking up as JSON (available starting with SQL Server 2016), use the OPENJSON function to iterate through the rows:

      CREATE PROCEDURE dbo.TestJSON(@ID INT, @Data NVARCHAR(MAX))
      AS
      BEGIN
         SET NOCOUNT ON;
      
         SELECT [Stuff],
                [More]
         FROM   OPENJSON(@Data)
         WITH (
            [Stuff] INT          '$.stuff',
            [More]  VARCHAR(MAX) '$.more'
         );
      
        ... other stuff
      END;
      

      And then test with:

      EXEC dbo.TestJSON
             @ID = 42,
             @Data = N'[{"stuff":"1","more":"one"},{"stuff":"2","more":"deux"},
        {"stuff":"3","more":"drei"}]';
      
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى dba.stackexchange
scroll top