如何在1个存储过程中选择xml并将所选节点作为参数传递到另一个过程

时间:2010-09-07 14:33:35

标签: sql xml sql-server-2005

我有一个存储过程,插入“人”。我有一个xml文档,其中包含一些我要插入的人。我想调用我的存储过程如下所示,并期望为xml中的每个人调用存储过程。它告诉我存储的proc“期望参数@Id”并且失败了。 @Id是第一个参数,似乎我的语法是不允许的。有没有办法在不迭代游标中的每个人的情况下执行此操作?我正在使用SQL Server 2005。

EXEC Stored_Procedure_That_Inserts_People
SELECT Node.value('Id[1]', 'Int') AS Id
,Node.value('FirstName[1]', 'varchar(50)') AS FirstName
,Node.value('LastName[1]', 'varchar(50)') AS LastName
,Node.value('MI[1]', 'char(1)') AS MI
FROM @PeopleXML.nodes('/ArrayOfPeople/Person') TempXML (Node)

对于任何感兴趣的人,这就是我根据Tom的答案实现我的解决方案的方式:

CREATE PROCEDURE [dbo].[ccIU_PersonBulkImport] 
(   
    @PersonXML as xml
)
AS
BEGIN

    SET NOCOUNT ON

    DECLARE 
    @LastName AS varchar(50),
    @FirstName AS varchar(50),
    @MI AS char(1)

        DECLARE People CURSOR FORWARD_ONLY STATIC READ_ONLY FOR 
                SELECT 
                Node.value('FirstName[1]', 'varchar(50)') AS FirstName
                ,Node.value('LastName[1]', 'varchar(50)') AS LastName
                ,Node.value('MI[1]', 'char(1)') AS MI
                FROM @PersonXML.nodes('/ArrayOfPeople/Person') TempXML (Node)

        OPEN People;
        FETCH NEXT FROM People INTO @FirstName,@LastName,@MI
        WHILE (@@FETCH_STATUS = 0)
        BEGIN
            EXEC domIU_People @FirstName,@LastName,@MI -- second stored proc that inserts or updates the person
            FETCH NEXT FROM People INTO @FirstName,@LastName,@MI;
        END
    CLOSE People;
    DEALLOCATE People;

END

2 个答案:

答案 0 :(得分:2)

没有。

您无法迭代存储过程,因为通常它们只能将对象作为参数,异常是表对象。

在此示例中,SQL将尝试调用SP,然后将select作为单独的事件运行,这就是您收到有关缺少参数的错误的原因。

您的选择是遍历XML并为每条记录调用SP,重构SP以使用XML作为单独的参数工作,并在插入人员过程中将其分解或将sp中的代码重构为XML处理逻辑程序。

答案 1 :(得分:1)

如果存储过程是简单插入People表,那么您可以创建一个新的存储过程,例如:

CREATE PROCEDURE dbo.Insert_People_From_XML
    @people_xml XML
AS
BEGIN
    INSERT INTO dbo.People
    (
        id,
        first_name,
        last_name,
        middle_initial
    )
    SELECT
        Node.value('Id[1]', 'Int'),
        Node.value('FirstName[1]', 'varchar(50)'),
        Node.value('LastName[1]', 'varchar(50)'),
        Node.value('MI[1]', 'char(1)')
    FROM
        @people_xml.nodes('/ArrayOfPeople/Person') TempXML (Node)

END

如果您有业务逻辑(或其他您不想复制的逻辑),那么您可能希望按原样重用插入存储过程。在这种情况下,您将不得不遍历XML节点。尽管我试图避免使用游标,但现在是时候使用游标了:

DECLARE
    @id                INT,
    @first_name        VARCHAR(50),
    @last_name         VARCHAR(50),
    @middle_initial    CHAR(1)

DECLARE people_cursor CURSOR FOR
SELECT
    Node.value('Id[1]', 'Int'),
    Node.value('FirstName[1]', 'varchar(50)'),
    Node.value('LastName[1]', 'varchar(50)'),
    Node.value('MI[1]', 'char(1)')
FROM
    @people_xml.nodes('/ArrayOfPeople/Person') TempXML (Node)

OPEN people_cursor

FETCH NEXT FROM people_cursor INTO @id, @first_name, @last_name, @middle_initial

WHILE (@@FETCH_STATUS = 0)
BEGIN
    EXEC Your_Proc
        @id = @id,
        @first_name = @first_name,
        @last_name = @last_name,
        @middle_initial = @middle_initial

    FETCH NEXT FROM people_cursor INTO @id, @first_name, @last_name, @middle_initial
END

CLOSE people_cursor

DEALLOCATE people_cursor

注意:这一切都是我的头脑。我不太多使用XML,因此可能需要更正语法,您需要添加错误处理等。