简体   繁体   English

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

[英]passing list of name/value pairs to stored procedure

I have a name/value pair in a List<T> and needing to find the best way to pass these to a stored procedure. 我在List<T>有一个名称/值对,需要找到将它们传递给存储过程的最佳方法。

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

What is the best way to accomplish this? 做到这一点的最佳方法是什么?

One way to handle this in SQL Server 2005 (prior to the availability of table valued parameters) was to pass a delimited list and use a Split function. 在SQL Server 2005中解决此问题的一种方法(在使用表值参数之前)是传递定界列表并使用Split函数。 If you are using a two-column array, you would want to use two different delimiters: 如果使用的是两列数组,则需要使用两个不同的定界符:

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
    )

Another way to handle this without table-valued parameters is to pass Xml as an nvarchar(max): 没有表值参数的另一种处理方法是将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) )

Take a look at Arrays and Lists in SQL Server 2008 to get some ideas 查看SQL Server 2008中的数组和列表,以获取一些想法

SQL Server 2008 also supports this multi row values syntax SQL Server 2008还支持此多行值语法

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

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

select * from #bla

我最终使用foreach <insert>

This could done through three ways. 这可以通过三种方式完成。

  1. User Defined Table Type 用户定义表类型
  2. Json Object Parsing Json对象解析
  3. XML Parsing XML解析

I tried with the first option and passed a list of pairs in User Defined Table Type. 我尝试了第一个选项,并在“用户定义的表类型”中传递了对的列表。 This works for me. 这对我有用。 I am posting here, it might help someone else. 我在这里发布,可能会对其他人有所帮助。

The first challenge for me was to pass the list of key value pair data structure and second to loop through the list and insert the record in a table. 对我来说,第一个挑战是传递键值对数据结构的列表,第二个遍历该列表并将记录插入表中。

Step 1 : Create a User Defined Table Type. 步骤1:创建用户定义的表类型。 I have created with a name 'TypeMetadata'. 我创建了一个名为“ TypeMetadata”的文件。 As it is custom type, I created two attributes of type nvarchar. 由于是自定义类型,因此创建了两个类型为nvarchar的属性。 You can create one of type integer and second of type 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

Step 2 : Then I created a stored procedure with name 'createfiled' 步骤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

Step 3: finally I executed the stored procedure like; 第三步:最后我执行了类似的存储过程;

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM