将名称/值对列表传递给存储过程

时间:2010-08-10 20:17:33

标签: asp.net sql sql-server-2008 stored-procedures

我在List<T>中有一个名称/值对,需要找到将这些传递给存储过程的最佳方法。

Id   Name
1    abc
2    bbc
3    cnn
....
...

实现这一目标的最佳方法是什么?

4 个答案:

答案 0 :(得分:2)

在SQL Server 2005中处理此问题的一种方法(在表值参数可用之前)是通过分隔列表并使用Split函数。如果您使用的是两列数组,则需要使用两个不同的分隔符:

Declare @Values varchar(max)
Set @Values = '1,abc|2,bbc|3,cnn'

With SplitItems As
    (
    Select S.Value As [Key]
        , S2.Value
        , Row_Number() Over ( Partition By S.Position Order By S2.Position ) As ElementNum
    From dbo.Split(@Values,'|') As S
        Outer Apply dbo.Split(S.Value, ',') As S2
    )
Select [Key]
    , Min( Case When S.ElementNum = 1 Then S.Value End ) As ListKey
    , Min( Case When S.ElementNum = 2 Then S.Value End ) As ListValue
From SplitItems As S
Group By [Key]

Create Function [dbo].[Split]
(   
    @DelimitedList nvarchar(max)
    , @Delimiter nvarchar(2) = ','
)
RETURNS TABLE 
AS
RETURN 
    (
    With CorrectedList As
        (
        Select Case When Left(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
            + @DelimitedList
            + Case When Right(@DelimitedList, Len(@Delimiter)) <> @Delimiter Then @Delimiter Else '' End
            As List
            , Len(@Delimiter) As DelimiterLen
        )
        , Numbers As 
        (
        Select Row_Number() Over ( Order By c1.object_id ) As Value
        From sys.columns As c1
            Cross Join sys.columns As c2
        )
    Select CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen As Position
        , Substring (
                    CL.List
                    , CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen     
                    , CharIndex(@Delimiter, CL.list, N.Value + 1)                           
                        - ( CharIndex(@Delimiter, CL.list, N.Value) + CL.DelimiterLen ) 
                    ) As Value
    From CorrectedList As CL
        Cross Join Numbers As N
    Where N.Value < Len(CL.List)
        And Substring(CL.List, N.Value, CL.DelimiterLen) = @Delimiter
    )

在没有表值参数的情况下处理此问题的另一种方法是将Xml作为nvarchar(max)传递:

Declare @Values nvarchar(max)
Set @Values = '<root><Item Key="1" Value="abc"/>
<Item Key="2" Value="bbc"/>
<Item Key="3" Value="cnn"/></root>'

Declare @docHandle int
exec sp_xml_preparedocument @docHandle output, @Values

Select *
From OpenXml(@docHandle, N'/root/Item', 1) 
    With( [Key] int, Value varchar(10) )

答案 1 :(得分:1)

看看Arrays and Lists in SQL Server 2008以获得一些想法

SQL Server 2008还支持此多行值语法

create table #bla (id int, somename varchar(50))

insert #bla values(1,'test1'),(2,'Test2')

select * from #bla

答案 2 :(得分:0)

我最终使用foreach <insert>

答案 3 :(得分:0)

这可以通过三种方式完成。

  1. 用户定义的表类型
  2. Json对象解析
  3. XML解析

我尝试了第一个选项,并在“用户定义的表类型”中传递了成对列表。这对我有用。我在这里发布,可能会对其他人有所帮助。

对我来说,第一个挑战是传递键值对数据结构的列表,第二个遍历列表并将记录插入表中。

步骤1::创建用户定义的表格类型。我创建了一个名为“ TypeMetadata”的文件。由于是自定义类型,因此创建了两个类型为nvarchar的属性。您可以创建整数类型之一,并创建nvarchar类型第二个。

    -- Type: metadata ---
IF EXISTS(SELECT * FROM SYS.TYPES WHERE NAME = 'TypeMetadata')
    DROP TYPE TypeMetadata
GO
CREATE TYPE TypeMetadata AS TABLE (
    mkey nvarchar (50), 
    mvalue nvarchar (50)
    );
GO

第2步:然后,我创建了一个名为'createfiled'的存储过程

    -- Procedure: createtext --
CREATE PROCEDURE [dbo].[createfield] 
    @name nvarchar(50),
    @text nvarchar(50),
    @order int, 
    @type nvarchar(50),
    @column_id int , 
    @tid int,   
    @metadataList TypeMetadata readonly
AS
BEGIN  

--loop through metadata and insert records -- 
DECLARE @mkey nvarchar(max);
DECLARE @mvalue nvarchar(max);

DECLARE mCursor CURSOR LOCAL FAST_FORWARD
FOR
    SELECT mkey, mvalue
        FROM @metadataList;
        OPEN mCursor;

        FETCH NEXT FROM mCursor INTO @mkey, @mvalue; -- Initial fetch attempt

        WHILE @@FETCH_STATUS = 0
        BEGIN
           INSERT INTO template_field_metadata (name, value, template_field_id, isProperty) values (@mkey, @mvalue, 1, 0) 
           PRINT 'A new metadata created with id : ' + cast(SCOPE_IDENTITY() as nvarchar); 
           FETCH NEXT FROM mCursor INTO @mkey, @mvalue;  -- Attempt to fetch next row from cursor
        END;

        CLOSE mCursor;
DEALLOCATE mCursor;

END
GO

第3步:最后,我像执行存储过程一样;

DECLARE @metadataToInsert TypeMetadata;
INSERT INTO @metadataToInsert VALUES ('value', 'callVariable2');
INSERT INTO @metadataToInsert VALUES ('maxlength', '30');

DECLARE @fid INT;
EXEC [dbo].[createfield] @name = 'prefagent', @text = 'Pref Agent', @order = 1 , @type= 'prefagent', @column_id = 0, @tid = 49, @metadataList =@metadataToInsert;