使用 XQuery 命名空间循环 XML 数据并将其插入 MS SQL Server 表时出错

问题描述 投票:0回答:1

描述: 我目前正在执行一项任务,涉及解析 XML 文档并将其数据插入 SQL Server 表中。 XML 文档包含发票信息,我需要循环遍历每张发票并将数据插入到两个表中:EDIInboundInvoiceHeader 和 EDIInboundInvoiceLineItems。但是,我在尝试插入数据时遇到了 XQuery 命名空间声明的问题。 问题: 当执行存储过程将XML数据插入表中时,我遇到以下错误:

消息 2229,级别 16,状态 1,过程 InsertEDIInboundInvoiceNew,第 60 行 [批量开始第 8 行] XQuery [query()]:名称“ns0”并不表示名称空间。

存储过程如下

USE [IntegrationStaging]
GO

/****** Object:  StoredProcedure [dbo].[InsertEDIInboundInvoiceNew]    Script Date: 8/9/2023 11:15:34 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[InsertEDIInboundInvoiceNew]
    @InvoiceStatus VARCHAR(50),
    @ProcessStatus VARCHAR(50) = NULL,
    @IntegrationProcess VARCHAR(50) = NULL,
    @InvoiceXML XML,
    @StatusMessage VARCHAR(100) OUTPUT
AS
BEGIN
    BEGIN TRY
    

        DECLARE @InvoiceID VARCHAR(50)
        DECLARE @BusinessUnit VARCHAR(50)
        DECLARE @InvoiceNumber VARCHAR(50)
        DECLARE @InvoiceAmount VARCHAR(100)
        DECLARE @InvoiceDate DATE
        DECLARE @SupplierName VARCHAR(100)
        DECLARE @SupplierNumber VARCHAR(50)
        DECLARE @SupplierSite VARCHAR(50)
        DECLARE @InvoiceCurrency VARCHAR(10)
        DECLARE @PaymentCurrency VARCHAR(10)
        DECLARE @ImportSet VARCHAR(50)
        DECLARE @InvoiceType VARCHAR(50)
        DECLARE @LegalEntity VARCHAR(50)
        DECLARE @CustomerTaxRegistrationNumber VARCHAR(50)
        DECLARE @PaymentTerm VARCHAR(50)
        DECLARE @TermsDate DATE
        DECLARE @GoodsReceivedDate DATE
        DECLARE @InvoiceReceiveDate DATE
        DECLARE @AccountingDate DATE
        DECLARE @PaymentMethod VARCHAR(50)
        DECLARE @PayGroup VARCHAR(50)
        DECLARE @LiabilityDistribution VARCHAR(50)
        DECLARE @CreationDate DATETIME
        DECLARE @Source VARCHAR(50)
        DECLARE @IntegrationName VARCHAR(50)
        DECLARE @Status VARCHAR(50)

        DECLARE @LineNumber INT
        DECLARE @LineType VARCHAR(50)
        DECLARE @Amount VARCHAR(100)
        DECLARE @InvoiceQuantity INT
        DECLARE @UnitPrice VARCHAR(100)
        DECLARE @UOM VARCHAR(50)
        DECLARE @Description VARCHAR(100)
        DECLARE @PONumber VARCHAR(50)
        DECLARE @DistributionCombination VARCHAR(50)
        DECLARE @DistributionSet VARCHAR(50)
        DECLARE @TaxControlAmount VARCHAR(100)
        DECLARE @TaxRegimeCode VARCHAR(50)
        DECLARE @Tax VARCHAR(100)
        DECLARE @TaxStatusCode VARCHAR(50)
        DECLARE @TaxJurisdictionCode VARCHAR(50)
        DECLARE @TaxRateCode VARCHAR(50)
        DECLARE @TaxRate VARCHAR(50)
        DECLARE @WithholdingTaxGroup VARCHAR(50)
                -- Iterate through each invoice in the XML
        DECLARE @InvoiceNodes XML
        
        SET @InvoiceNodes = @InvoiceXML.query('/ns0:InvoiceCanonical')

        DECLARE @InvoiceCount INT
        
        SELECT @InvoiceCount = @InvoiceNodes.value('count(/ns0:InvoiceCanonical)', 'INT')

        DECLARE @CurrentInvoice INT = 1

        WHILE @CurrentInvoice <= @InvoiceCount
        BEGIN
        
            SELECT
                @InvoiceID = InvoiceHeader.value('(ns0:InvoiceID)[1]', 'VARCHAR(50)'),
                @BusinessUnit = InvoiceHeader.value('(ns0:BusinessUnit)[1]', 'VARCHAR(50)'),
                @InvoiceNumber = InvoiceHeader.value('(ns0:InvoiceNumber)[1]', 'VARCHAR(50)'),
                @InvoiceAmount = InvoiceHeader.value('(ns0:InvoiceAmount)[1]', 'VARCHAR(100)'),
                @InvoiceDate = InvoiceHeader.value('(ns0:InvoiceDate)[1]', 'DATE'),
                @SupplierName = InvoiceHeader.value('(ns0:SupplierName)[1]', 'VARCHAR(100)'),
                @SupplierNumber = InvoiceHeader.value('(ns0:SupplierNumber)[1]', 'VARCHAR(50)'),
                @SupplierSite = InvoiceHeader.value('(ns0:SupplierSite)[1]', 'VARCHAR(50)'),
                @InvoiceCurrency = InvoiceHeader.value('(ns0:InvoiceCurrency)[1]', 'VARCHAR(10)'),
                @PaymentCurrency = InvoiceHeader.value('(ns0:PaymentCurrency)[1]', 'VARCHAR(10)'),
                @ImportSet = InvoiceHeader.value('(ns0:ImportSet)[1]', 'VARCHAR(50)'),
                @InvoiceType = InvoiceHeader.value('(ns0:InvoiceType)[1]', 'VARCHAR(50)'),
                @LegalEntity = InvoiceHeader.value('(ns0:LegalEntity)[1]', 'VARCHAR(50)'),
                @CustomerTaxRegistrationNumber = InvoiceHeader.value('(ns0:CustomerTaxRegistrationNumber)[1]', 'VARCHAR(50)'),
                @PaymentTerm = InvoiceHeader.value('(ns0:PaymentTerm)[1]', 'VARCHAR(50)'),
                @TermsDate = InvoiceHeader.value('(ns0:TermsDate)[1]', 'DATE'),
                @GoodsReceivedDate = InvoiceHeader.value('(ns0:GoodsReceivedDate)[1]', 'DATE'),
                @InvoiceReceiveDate = InvoiceHeader.value('(ns0:InvoiceReceiveDate)[1]', 'DATE'),
                @AccountingDate = InvoiceHeader.value('(ns0:AccountingDate)[1]', 'DATE'),
                @PaymentMethod = InvoiceHeader.value('(ns0:PaymentMethod)[1]', 'VARCHAR(50)'),
                @PayGroup = InvoiceHeader.value('(ns0:PayGroup)[1]', 'VARCHAR(50)'),
                @LiabilityDistribution = InvoiceHeader.value('(ns0:LiabilityDistribution)[1]', 'VARCHAR(50)'),
                @CreationDate = InvoiceHeader.value('(ns0:CreationDate)[1]', 'DATETIME'),
                @Source = InvoiceHeader.value('(ns0:Source)[1]', 'VARCHAR(50)'),
                @IntegrationName = InvoiceHeader.value('(ns0:IntegrationName)[1]', 'VARCHAR(50)'),
                @Status = InvoiceHeader.value('(ns0:Status)[1]', 'VARCHAR(50)')
            FROM @InvoiceXML.nodes('/ns0:InvoiceCanonical[' + CAST(@CurrentInvoice AS VARCHAR) + ']/ns0:Header') AS InvoiceHeader(InvoiceHeader)

            -- Insert data into EDIInboundInvoiceHeader
            INSERT INTO EDIInboundInvoiceHeader (
                InvoiceStatus, ProcessStatus, IntegrationProcess, InvoiceID, BusinessUnit, InvoiceNumber, InvoiceAmount, InvoiceDate,
                SupplierName, SupplierNumber, SupplierSite, InvoiceCurrency,
                PaymentCurrency, ImportSet, InvoiceType, LegalEntity,
                CustomerTaxRegistrationNumber, PaymentTerm, TermsDate,
                GoodsReceivedDate, InvoiceReceiveDate, AccountingDate,
                PaymentMethod, PayGroup, LiabilityDistribution, CreationDate,
                Source, IntegrationName, Status
            )
            VALUES (
                @InvoiceStatus, @ProcessStatus, @IntegrationProcess, @InvoiceID, @BusinessUnit, @InvoiceNumber, @InvoiceAmount, @InvoiceDate,
                @SupplierName, @SupplierNumber, @SupplierSite, @InvoiceCurrency,
                @PaymentCurrency, @ImportSet, @InvoiceType, @LegalEntity,
                @CustomerTaxRegistrationNumber, @PaymentTerm, @TermsDate,
                @GoodsReceivedDate, @InvoiceReceiveDate, @AccountingDate,
                @PaymentMethod, @PayGroup, @LiabilityDistribution, @CreationDate,
                @Source, @IntegrationName, @Status
            )

            DECLARE @InvoiceHeaderID INT
            SET @InvoiceHeaderID = SCOPE_IDENTITY()

            -- Insert data into EDIInboundInvoiceLineItems
            INSERT INTO EDIInboundInvoiceLineItems (InvoiceHeaderID, LineNumber, LineType, Amount, InvoiceQuantity, UnitPrice, UOM, Description, PONumber, DistributionCombination, DistributionSet, AccountingDate, TaxControlAmount, TaxRegimeCode, Tax, TaxStatusCode, TaxJurisdictionCode, TaxRateCode, TaxRate, WithholdingTaxGroup)
            SELECT
                @InvoiceHeaderID,
                InvoiceItem.value('(ns0:LineNumber)[1]', 'INT'),
                InvoiceItem.value('(ns0:LineType)[1]', 'VARCHAR(50)'),
                -- ... other attribute extractions ...
                InvoiceItem.value('(ns0:Amount)[1]', 'VARCHAR(100)'),
                InvoiceItem.value('(ns0:InvoiceQuantity)[1]', 'INT'),
                InvoiceItem.value('(ns0:UnitPrice)[1]', 'VARCHAR(100)'),
                InvoiceItem.value('(ns0:UOM)[1]', 'VARCHAR(50)'),
                InvoiceItem.value('(ns0:Description)[1]', 'VARCHAR(100)'),
                InvoiceItem.value('(ns0:PONumber)[1]', 'VARCHAR(50)'),
                InvoiceItem.value('(ns0:DistributionCombination)[1]', 'VARCHAR(50)'),
                InvoiceItem.value('(ns0:DistributionSet)[1]', 'VARCHAR(50)'),
                InvoiceItem.value('(ns0:AccountingDate)[1]', 'DATE'),
                InvoiceItem.value('(ns0:TaxControlAmount)[1]', 'VARCHAR(100)'),
                InvoiceItem.value('(ns0:TaxRegimeCode)[1]', 'VARCHAR(50)'),
                InvoiceItem.value('(ns0:Tax)[1]', 'VARCHAR(100)'),
                InvoiceItem.value('(ns0:TaxStatusCode)[1]', 'VARCHAR(50)'),
                InvoiceItem.value('(ns0:TaxJurisdictionCode)[1]', 'VARCHAR(50)'),
                InvoiceItem.value('(ns0:TaxRateCode)[1]', 'VARCHAR(50)'),
                InvoiceItem.value('(ns0:TaxRate)[1]', 'VARCHAR(50)'),
                InvoiceItem.value('(ns0:WithholdingTaxGroup)[1]', 'VARCHAR(50)')
            FROM @InvoiceXML.nodes('/ns0:InvoiceCanonical[' + CAST(@CurrentInvoice AS VARCHAR) + ']/ns0:Detail') AS InvoiceItem(InvoiceItem)

            SET @CurrentInvoice = @CurrentInvoice + 1
        END

        SET @StatusMessage = 'Success' -- Output message on success
    END TRY
    BEGIN CATCH
        SET @StatusMessage = ERROR_MESSAGE() -- Return error message on failure
    END CATCH
END

XML 输入如下

<ns0:InvoiceCanonical xmlns:ns0="namespace_URL">
  <Header xmlns:ns0="namespace_URL">
    <InvoiceID>INV0001</InvoiceID>
    <BusinessUnit>BU123</BusinessUnit>
    <InvoiceNumber>INV123456</InvoiceNumber>
    <InvoiceAmount>1500.00</InvoiceAmount>
    <InvoiceDate>2023-08-01</InvoiceDate>
    <SupplierName>ABC Supplier</SupplierName>
    <SupplierNumber>SUP001</SupplierNumber>
    <SupplierSite>Main Site</SupplierSite>
    <InvoiceCurrency>USD</InvoiceCurrency>
    <PaymentCurrency>USD</PaymentCurrency>
    <ImportSet>ImportSet_123</ImportSet>
    <InvoiceType>Regular</InvoiceType>
    <LegalEntity>LE001</LegalEntity>
    <CustomerTaxRegistrationNumber>1234567890</CustomerTaxRegistrationNumber>
    <PaymentTerm>Net 30</PaymentTerm>
    <TermsDate>2023-09-01</TermsDate>
    <GoodsReceivedDate>2023-07-25</GoodsReceivedDate>
    <InvoiceReceiveDate>2023-08-02</InvoiceReceiveDate>
    <AccountingDate>2023-08-02</AccountingDate>
    <PaymentMethod>Bank Transfer</PaymentMethod>
    <PayGroup>PG001</PayGroup>
    <LiabilityDistribution>LD001</LiabilityDistribution>
    <CreationDate>2023-08-01T08:00:00</CreationDate>
    <Source>System A</Source>
    <IntegrationName>Integration_ABC</IntegrationName>
    <Status>Approved</Status>
  </Header>
  <Detail xmlns:ns0="namespace_URL">
    <InvoiceID>INV0001</InvoiceID>
    <LineNumber>1</LineNumber>
    <LineType>Item</LineType>
    <Amount>500.00</Amount>
    <InvoiceQuantity>10</InvoiceQuantity>
    <UnitPrice>50.00</UnitPrice>
    <UOM>EA</UOM>
    <Description>Product A</Description>
    <PONumber>PO1234</PONumber>
    <DistributionCombination>DC123</DistributionCombination>
    <DistributionSet>DS001</DistributionSet>
    <AccountingDate>2023-08-02</AccountingDate>
    <TaxControlAmount>50.00</TaxControlAmount>
    <TaxRegimeCode>TAXREG001</TaxRegimeCode>
    <Tax>10.00</Tax>
    <TaxStatusCode>TAXSTAT001</TaxStatusCode>
    <TaxJurisdictionCodeTaxJurisdictionCode>TAXJUR001</TaxJurisdictionCodeTaxJurisdictionCode>
    <TaxRateCode>TAXRATE001</TaxRateCode>
    <TaxRate>10%</TaxRate>
    <WithholdingTaxGroup>WTG001</WithholdingTaxGroup>
  </Detail>
  <Detail xmlns:ns0="namespace_URL">
    <InvoiceID>INV0001</InvoiceID>
    <LineNumber>2</LineNumber>
    <LineType>Item</LineType>
    <Amount>800.00</Amount>
    <InvoiceQuantity>5</InvoiceQuantity>
    <UnitPrice>160.00</UnitPrice>
    <UOM>EA</UOM>
    <Description>Product B</Description>
    <PONumber>PO5678</PONumber>
    <DistributionCombination>DC456</DistributionCombination>
    <DistributionSet>DS002</DistributionSet>
    <AccountingDate>2023-08-03</AccountingDate>
    <TaxControlAmount>80.00</TaxControlAmount>
    <TaxRegimeCode>TAXREG002</TaxRegimeCode>
    <Tax>16.00</Tax>
    <TaxStatusCode>TAXSTAT002</TaxStatusCode>
    <TaxJurisdictionCodeTaxJurisdictionCode>TAXJUR002</TaxJurisdictionCodeTaxJurisdictionCode>
    <TaxRateCode>TAXRATE002</TaxRateCode>
    <TaxRate>20%</TaxRate>
    <WithholdingTaxGroup>WTG002</WithholdingTaxGroup>
  </Detail>
  <Detail xmlns:ns0="namespace_URL">
    <InvoiceID>INV0001</InvoiceID>
    <LineNumber>3</LineNumber>
    <LineType>Item</LineType>
    <Amount>300.00</Amount>
    <InvoiceQuantity>3</InvoiceQuantity>
    <UnitPrice>100.00</UnitPrice>
    <UOM>EA</UOM>
    <Description>Product C</Description>
    <PONumber>PO9090</PONumber>
    <DistributionCombination>DC789</DistributionCombination>
    <DistributionSet>DS003</DistributionSet>
    <AccountingDate>2023-08-03</AccountingDate>
    <TaxControlAmount>30.00</TaxControlAmount>
    <TaxRegimeCode>TAXREG003</TaxRegimeCode>
    <Tax>9.00</Tax>
    <TaxStatusCode>TAXSTAT003</TaxStatusCode>
    <TaxJurisdictionCodeTaxJurisdictionCode>TAXJUR003</TaxJurisdictionCodeTaxJurisdictionCode>
    <TaxRateCode>TAXRATE003</TaxRateCode>
    <TaxRate>9%</TaxRate>
    <WithholdingTaxGroup>WTG003</WithholdingTaxGroup>
  </Detail>
</ns0:InvoiceCanonical>
<ns0:InvoiceCanonical xmlns:ns0="namespace_URL">
  <Header xmlns:ns0="http://Invoice.Common.Schemas.InvoiceCanonical">
    <InvoiceID>INV0002</InvoiceID>
    <BusinessUnit>BU456</BusinessUnit>
    <InvoiceNumber>INV789012</InvoiceNumber>
    <InvoiceAmount>2500.00</InvoiceAmount>
    <InvoiceDate>2023-08-05</InvoiceDate>
    <SupplierName>XYZ Suppliers</SupplierName>
    <SupplierNumber>SUP002</SupplierNumber>
    <SupplierSite>Secondary Site</SupplierSite>
    <InvoiceCurrency>EUR</InvoiceCurrency>
    <PaymentCurrency>EUR</PaymentCurrency>
    <ImportSet>ImportSet_456</ImportSet>
    <InvoiceType>Special</InvoiceType>
    <LegalEntity>LE002</LegalEntity>
    <CustomerTaxRegistrationNumber>9876543210</CustomerTaxRegistrationNumber>
    <PaymentTerm>Net 45</PaymentTerm>
    <TermsDate>2023-09-15</TermsDate>
    <GoodsReceivedDate>2023-08-01</GoodsReceivedDate>
    <InvoiceReceiveDate>2023-08-06</InvoiceReceiveDate>
    <AccountingDate>2023-08-06</AccountingDate>
    <PaymentMethod>Credit Card</PaymentMethod>
    <PayGroup>PG002</PayGroup>
    <LiabilityDistribution>LD002</LiabilityDistribution>
    <CreationDate>2023-08-05T09:30:00</CreationDate>
    <Source>System B</Source>
    <IntegrationName>Integration_XYZ</IntegrationName>
    <Status>Pending Approval</Status>
  </Header>
  <Detail xmlns:ns0="namespace_URL">
    <InvoiceID>INV0002</InvoiceID>
    <LineNumber>1</LineNumber>
    <LineType>Item</LineType>
    <Amount>800.00</Amount>
    <InvoiceQuantity>8</InvoiceQuantity>
    <UnitPrice>100.00</UnitPrice>
    <UOM>EA</UOM>
    <Description>Product X</Description>
    <PONumber>PO9876</PONumber>
    <DistributionCombination>DC987</DistributionCombination>
    <DistributionSet>DS004</DistributionSet>
    <AccountingDate>2023-08-06</AccountingDate>
    <TaxControlAmount>80.00</TaxControlAmount>
    <TaxRegimeCode>TAXREG004</TaxRegimeCode>
    <Tax>10.00</Tax>
    <TaxStatusCode>TAXSTAT004</TaxStatusCode>
    <TaxJurisdictionCodeTaxJurisdictionCode>TAXJUR004</TaxJurisdictionCodeTaxJurisdictionCode>
    <TaxRateCode>TAXRATE004</TaxRateCode>
    <TaxRate>12.5%</TaxRate>
    <WithholdingTaxGroup>WTG004</WithholdingTaxGroup>
  </Detail>
</ns0:InvoiceCanonical>

我希望存储过程能够成功循环遍历 XML 文档中的每张发票,提取必要的属性,并将它们插入到相应的 SQL Server 表中。应正确识别 XQuery 命名空间以避免上述错误。

sql-server stored-procedures xml-parsing namespaces xquery
1个回答
0
投票

您需要先声明命名空间,然后才能使用它们查询 XML。

请看下面。

SQL

SET @InvoiceNodes = @InvoiceXML.query('declare namespace ns0="namespace_URL";
            /ns0:InvoiceCanonical')

        DECLARE @InvoiceCount INT
        
        SELECT @InvoiceCount = @InvoiceNodes.value('declare namespace ns0="namespace_URL";
            count(/ns0:InvoiceCanonical)', 'INT')

但是您的代码将在下面失败并出现以下错误:

Msg 8172, Level 16, State 1, Line ...
The argument 1 of the XML data type method "nodes" must be a string literal.

因为FROM子句不正确:

FROM @InvoiceXML.nodes('/ns0:InvoiceCanonical[' + CAST(@CurrentInvoice AS VARCHAR) + ']/ns0:Header') AS InvoiceHeader(InvoiceHeader)

再次使用命名空间声明的解决方案:

WITH XMLNAMESPACES('namespace_URL' AS ns0)
            SELECT
                @InvoiceID = InvoiceHeader.value('(ns0:InvoiceID)[1]', 'VARCHAR(50)'),
                ...
            FROM @InvoiceXML.nodes('/ns0:InvoiceCanonical[sql:variable("@CurrentInvoice")]/ns0:Header') AS InvoiceHeader(InvoiceHeader)
© www.soinside.com 2019 - 2024. All rights reserved.