在 MS SQL Server 的存储过程中使用 xQuery 时插入 XML 之外的值

Inserting a value that comes outside of XML while using xQuery in stored procedure in MS SQL Server

我正在使用 xQuery which helps parse xml files in a stored procedure like here 解析 xml 输入,然后将它们插入 table。我能够将 XML 中的值正确地插入到 table.

但是,我想插入一个新创建的 UUID 列作为我进行插入的 table 的第一列,只有其余列的值需要来自 XML.由于 xQuery 批量插入,我创建了一个临时 table 来保存 UUID,并尝试将其与从 XML 解析的其余值一起插入。但是,它给了我一个错误。

--SP
CREATE PROCEDURE dbo.ParseXML
   @XML XML
AS
BEGIN
    DECLARE @applicationId NVARCHAR(36);
    DECLARE @dashboardcount INT;
    DECLARE @dashboardscount INT;
    DECLARE @applicationcount INT;

    select @applicationId = NEWID();
    select @dashboardcount = Book.value('count(/application/dashboards/dashboard)', 'NVARCHAR(100)') FROM @XML.nodes('application/dashboards/dashboard')Catalog(Book)    

    drop table if exists #MyList
    create table #MyList (
    id nvarchar( 36 ) not null
    )
    DECLARE @LoopCounter INT = 1
    WHILE ( @LoopCounter <= @dashboardcount)
    BEGIN
        insert #MyList values ( NEWID() ) 
        SET @LoopCounter  = @LoopCounter  + 1
    END
    select * from #MyList

    --insert into applications (id, alias, title, description) (select @applicationId as id, Book.value('alias[1]','NVARCHAR(100)') as alias, Book.value('title[1]','NVARCHAR(100)') as title, Book.value('description[1]','NVARCHAR(100)') as description FROM @XML.nodes('application')Catalog(Book) )
    insert into dashboards (id, alias, title, description, version, application_id) (select * from #MyList as id, Book.value('alias[1]','NVARCHAR(100)') as alias, Book.value('title[1]','NVARCHAR(100)') as title, Book.value('description[1]','NVARCHAR(100)') as description, Book.value('version[1]','NVARCHAR(100)') as version, @applicationId as application_id FROM @XML.nodes('application/dashboards/dashboard')Catalog(Book))
RETURN;
END;

这是我得到的错误。

Msg 156, Level 15, State 1, Procedure ParseXML, Line 27 [Batch Start Line 5] Incorrect syntax near the keyword 'FROM'.

您可以运行使用此输入的上述存储过程

--run
DECLARE @string NVARCHAR(MAX);
DECLARE @xmlstring XML;
SET @string = 
    '<application> <alias>appAlias1</alias> <title>appTitle1</title> <description>appDesc1</description> <dashboards class="list"> <dashboard> <id>dashboard1</id> <alias>alias1</alias> <version>version1</version> <title>title1</title> <description>desc1</description> </dashboard> <dashboard> <id>dashboard2</id> <alias>alias2</alias> <version>version2</version> <title>title2</title> <description>desc2</description> </dashboard> <dashboard> <id>dashboard3</id> <alias>alias3</alias> <version>version3</version> <title>title3</title> <description>desc3</description> </dashboard> <dashboard> <id>dashboard4</id> <alias>alias4</alias> <version>version4</version> <title>title4</title> <description>desc4</description> </dashboard> <dashboard> <id>dashboard5</id> <alias>alias5</alias> <version>version5</version> <title>title5</title> <description>desc5</description> </dashboard> </dashboards> </application>'  
SET @xmlstring = @string;
EXEC dbo.ParseXML @xmlstring;
SELECT @xmlstring;

请告诉我如何添加一列以及通过在存储过程中使用 xQuery 解析 XML 获得的其余值。


编辑:感谢@Mikael Eriksson 和@Roger Wolf 回答和审查我的程序。

只是为了完成答案,比方说,我想插入一个 table,其中一列的值来自 table,它已经存在于我的 sql 中] 服务器,以及来自 XML 的其他人,这怎么能做到。我试过类似的方法,但失败了。

insert into dashboards (id, alias, title, description, version, application_id) (select top 3 id from applications, select Retriever.value('alias[1]','NVARCHAR(100)') as alias, Retriever.value('title[1]','NVARCHAR(100)') as title, Retriever.value('description[1]','NVARCHAR(100)') as description, Retriever.value('version[1]','NVARCHAR(100)') as version, @applicationId as application_id FROM @XML.nodes('application/dashboards/dashboard') TableAlias(Retriever))

也试过

insert into dashboards (id, alias, title, description, version, application_id) (select top 3 id from applications, Retriever.value('alias[1]','NVARCHAR(100)') as alias, Retriever.value('title[1]','NVARCHAR(100)') as title, Retriever.value('description[1]','NVARCHAR(100)') as description, Retriever.value('version[1]','NVARCHAR(100)') as version, @applicationId as application_id FROM @XML.nodes('application/dashboards/dashboard') TableAlias(Retriever))

都给我

Incorrect syntax near the keyword 'select'.

您可以直接在插入语句中使用 newid()。不需要循环。

这对你的程序来说已经足够了。

declare @applicationId NVARCHAR(36);
select @applicationId = NEWID();

insert into dashboards (id, alias, title, description, version, application_id) 
select newid() as id, 
       Book.value('alias[1]','NVARCHAR(100)') as alias, 
       Book.value('title[1]','NVARCHAR(100)') as title, 
       Book.value('description[1]','NVARCHAR(100)') as description, 
       Book.value('version[1]','NVARCHAR(100)') as version, 
       @applicationId as application_id 
from @XML.nodes('application/dashboards/dashboard') Catalog(Book)

TL;DR - 这不是集合在 SQL 中的连接方式。

以下代码更正了这个错误以及其他一些错误和低效问题。评论解释了我的更改:

CREATE PROCEDURE dbo.ParseXML
   @XML XML
AS

-- You can save a bit on initialisation this way
DECLARE @applicationId uniqueidentifier = newid(),
    @dashboardcount INT, @dashboardscount INT, @applicationcount INT;

-- SELECT is not necessary, SET is enough and it is faster
set @dashboardcount = @XML.value('count(/application/dashboards/dashboard)', 'int');

drop table if exists #MyList;
create table #MyList (
    -- Should the data type be a uniqueidentifier, instead?
    id nvarchar( 36 ) not null
);

-- "Catalog" is a reserved keyword, it is better to avoid using it as an alias
/*
insert into applications (id, alias, title, description)
select @applicationId as id,
    c.b.value('alias[1]','NVARCHAR(100)') as alias,
    c.b.value('title[1]','NVARCHAR(100)') as title,
    c.b.value('description[1]','NVARCHAR(100)') as description
FROM @XML.nodes('/application') c(b);
*/

insert into dbo.dashboards (id, alias, title, [description], [version], application_id)
-- This is how you catch inserted values when they are generated on the fly
output inserted.id into #MyList (id)
select newid() as Id, -- No need to pre-cache
    c.b.value('alias[1]','NVARCHAR(100)') as alias,
    c.b.value('title[1]','NVARCHAR(100)') as title,
    c.b.value('description[1]','NVARCHAR(100)') as [description],
    c.b.value('version[1]','NVARCHAR(100)') as [version],
    @applicationId as application_id
FROM @XML.nodes('application/dashboards/dashboard') c(b);

-- Now you can return the list of inserted GUIDs
select * from #MyList;

RETURN;
go

我决定保持你的 #MyList temp table 不变,因为它可以是一个简化的例子,之后你可能需要插入的值。但是,如果存储 pre-generated GUID 是它的唯一目的,您可以安全地完全摆脱它。