在SQL Server中通过XML插入或更新行(批量)

时间:2011-10-06 14:04:06

标签: sql-server tsql sql-server-2008

您好我似乎无法解决如何解析Xml文档并决定是否需要插入或更新。

我有一个像这样的现有程序:

CREATE PROCEDURE [dbo].[SavePrice]
-- Add the parameters for the stored procedure here
@Groupid varchar(150), @Price varchar(150), @CustomerID varchar(150)
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

IF (EXISTS(SELECT * FROM dbo.Prices WHERE groupid = @Groupid AND CustomerID = @CustomerID))
    UPDATE 
        dbo.Prices
    SET 
        price = @Price
    WHERE
        groupid = @Groupid 
    AND
        CustomerID = @CustomerID;

ELSE
    INSERT INTO 
        dbo.Prices
    (
        price,
        groupid,
        customerid
    )
    VALUES
    (
        @price,
        @groupid,
        @customerid
    );
End

现在我希望这可以优先从XML Argument

批量运行

XML

<ArrayOfPrice xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Price>
  <Undergroup>111</Undergroup> 
  <Gain>10</Gain> 
  <CustomerID>14001099</CustomerID> 
  </Price>
  </ArrayOfPrice>

像这样的东西

foreach(Row r in XmlDoc)
{    
    Procedure(r)
}

我很抱歉,但我真的很厌烦SQL(这就是上面用伪C#编写的原因),所以我真的希望你能帮助我。 有什么想法吗?

关心肯尼思

修改

解决方案不是使用XML来传递批量数据,而是使用TableParameter

TABLETYPE

CREATE TYPE [dbo].[PriceDataType] As Table
(
--This type has structure similar to the DB table 
GroupID varchar(50) Not Null,
Price varchar(50) Not Null,
CustomerID varchar(50) Not Null
)

存储过程

ALTER PROCEDURE [dbo].[SavePrice]
    -- Add the parameters for the stored procedure here
    @Dt PriceDataType READONLY
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

MERGE Prices AS Prices
    USING (SELECT * FROM @Dt) AS Source
    ON (Prices.GroupId = Source.GroupId) AND (Prices.CustomerId= Source.CustomerId)
    WHEN MATCHED THEN 
        UPDATE SET Prices.Price = Source.Price
    WHEN NOT MATCHED THEN   
        INSERT (Price, GroupId, CustomerId)
        VALUES (Source.Price, Source.GroupId, Source.CustomerId);
End

C#

        public void SavePrices(Price[] prices)
        {


            SqlCommand cmd = new SqlCommand("SavePrice", conn);
            cmd.CommandType = CommandType.StoredProcedure;

            conn.Open();


            cmd.Parameters.Add(new SqlParameter("@Dt", SqlDbType.Structured));
            cmd.Parameters["@Dt"].Value = GetTableFromList(prices);

            cmd.ExecuteScalar();


            conn.Close();
            cmd.Dispose();


        }


        private DataTable GetTableFromList(Price[] ps)
        {
            DataTable tbl = new DataTable("PriceDataType");
            tbl.Columns.Add("GroupID", typeof(string));
            tbl.Columns.Add("Price", typeof(string));
            tbl.Columns.Add("CustomerID", typeof(string));

            foreach (Price p in ps)
                tbl.Rows.Add(p.Undergroup, p.Gain, p.CustomerID);
            return tbl;
        }

感谢您的帮助

1 个答案:

答案 0 :(得分:2)

由于您使用的是SQL Server 2008,因此可以使用MERGE语句执行INSERT或UPDATE,而不是使用if块构建存储过程,具体取决于是否存在记录。使用该声明时有MSDN documentation

修改

以下是MERGE语句的示例:

MERGE Prices AS Prices
    USING (SELECT @GroupId, @CustomerId) AS Source
    ON (Prices.GroupId = Source.GroupId) AND (Prices.CustomerId= Source.CustomerId)
    WHEN MATCHED THEN 
        UPDATE SET Prices.Price = @Price
    WHEN NOT MATCHED THEN   
        INSERT (Price, GroupId, CustomerId)
        VALUES (@Price, @GroupId, @CustomerId)

此外,如果您想真正批量插入记录,可以考虑使用table valued parameter。如果要将XML文档中的5个“行”插入到数据库中,则可以通过传入单个值(如您当前所做的那样)调用存储过程5次。通过使用表值参数,您可以通过处理表参数来调用存储过程一次,然后在存储过程中使用该表。