为什么在xml中使用value函数,其中condition在tsql中返回null值

时间:2016-10-04 14:05:40

标签: sql xml tsql

我需要在tsql中解析以下XML

问题出在哪里。只有第一条记录在where条件中得到验证。如果我将GLNominalAccount值更改为[2],则验证第二个节点。有没有办法可以使用where条件遍历所有节点。我只查找与整个节点中的where条件匹配的GLNominalAccount值。感谢

<JournalEntry xmlns="http://schema.mycompany.com/Info/2"
<JELine sequence="1">
<Amount currencyID="USD">-100.000</Amount>
<FunctionalAmount currencyID="USD">-100.000</FunctionalAmount>
<ReportingCurrencyAmount     currencyID="USD">100.000</ReportingCurrencyAmount>
<GLAccount>
    <GLNominalAccount>1005690</GLNominalAccount>
    <AccountingChartReference>
        <ID accountingEntity="T00">T00</ID>
    </AccountingChartReference>
</GLAccount>
</JELine>
<JELine sequence="2">
<Amount currencyID="USD">100.000</Amount>
<FunctionalAmount currencyID="USD">100.000</FunctionalAmount>
<ReportingCurrencyAmount     currencyID="USD">100.000</ReportingCurrencyAmount>
<GLAccount>
    <GLNominalAccount>34180050</GLNominalAccount>
    <AccountingChartReference>
        <ID accountingEntity="T00">T00</ID>
    </AccountingChartReference>
</GLAccount>
</JELine>
</JournalEntry>

下面是我的tsql代码

WITH XMLNAMESPACES(DEFAULT 'http://schema.mycompany.com/Info/2')
SELECT ParamValues.SSD.value('GLNominalAccount[1]', 'varchar(8)') 
FROM @xmlData.nodes('//JournalEntry/JELine/GLAccount') AS ParamValues(SSD) 

WHERE @xmldata.value(N'(/JournalEntry/JELine/GLAccount/GLNominalAccount)[1]' ,'varchar(max)') LIKE '2%'


OR @xmldata.value('(//JournalEntry/JELine/GLAccount/GLNominalAccount)[1]' , 'varchar(8)') LIKE '3%'
OR @xmldata.value('(//JournalEntry/JELine/GLAccount/GLNominalAccount)[1]' , 'varchar(8)') LIKE '4%'
OR @xmldata.value('(//JournalEntry/JELine/GLAccount/GLNominalAccount)[1]' , 'varchar(8)') LIKE '6%'
OR @xmldata.value('(//JournalEntry/JELine/GLAccount/GLNominalAccount)[1]' , 'varchar(8)') LIKE '7%'
OR @xmldata.value('(//JournalEntry/JELine/GLAccount/GLNominalAccount)[1]' , 'varchar(8)') LIKE '8%'

2 个答案:

答案 0 :(得分:0)

顺便说一句:您的示例XML缺少结束> ...

无需循环或迭代。 .nodes() - 函数将所有同级节点作为行返回:

试试这样:

DECLARE @xml XML=
'<JournalEntry xmlns="http://schema.mycompany.com/Info/2">
  <JELine sequence="1">
    <Amount currencyID="USD">-100.000</Amount>
    <FunctionalAmount currencyID="USD">-100.000</FunctionalAmount>
    <ReportingCurrencyAmount currencyID="USD">100.000</ReportingCurrencyAmount>
    <GLAccount>
      <GLNominalAccount>1005690</GLNominalAccount>
      <AccountingChartReference>
        <ID accountingEntity="T00">T00</ID>
      </AccountingChartReference>
    </GLAccount>
  </JELine>
  <JELine sequence="2">
    <Amount currencyID="USD">100.000</Amount>
    <FunctionalAmount currencyID="USD">100.000</FunctionalAmount>
    <ReportingCurrencyAmount currencyID="USD">100.000</ReportingCurrencyAmount>
    <GLAccount>
      <GLNominalAccount>34180050</GLNominalAccount>
      <AccountingChartReference>
        <ID accountingEntity="T00">T00</ID>
      </AccountingChartReference>
    </GLAccount>
  </JELine>
</JournalEntry>';

- 查询

WITH XMLNAMESPACES(DEFAULT 'http://schema.mycompany.com/Info/2')
SELECT j.value('@sequence','int') AS JELine_Sequence
      ,j.value('(Amount/@currencyID)[1]','nvarchar(max)') AS Amount_CurrencyID
      ,j.value('(Amount)[1]','decimal(14,4)') AS Amount
      ,j.value('(FunctionalAmount/@currencyID)[1]','nvarchar(max)') AS FunctionalAmount_CurrencyID
      ,j.value('(FunctionalAmount)[1]','decimal(14,4)') AS FunctionalAmount
      ,j.value('(ReportingCurrencyAmount/@currencyID)[1]','nvarchar(max)') AS ReportingCurrencyAmount_CurrencyID
      ,j.value('(ReportingCurrencyAmount)[1]','decimal(14,4)') AS ReportingCurrencyAmount
      ,j.value('(GLAccount/GLNominalAccount)[1]','bigint') AS GLNominalAccount
      ,j.value('(GLAccount/AccountingChartReference/ID/@accountingEntity)[1]','nvarchar(max)') AS accountingEntity
      ,j.value('(GLAccount/AccountingChartReference/ID)[1]','nvarchar(max)') AS AccountID

FROM @xml.nodes('JournalEntry/JELine') AS A(j)

结果

+-----------------+-------------------+-----------+-----------------------------+------------------+------------------------------------+-------------------------+------------------+------------------+-----------+
| JELine_Sequence | Amount_CurrencyID | Amount    | FunctionalAmount_CurrencyID | FunctionalAmount | ReportingCurrencyAmount_CurrencyID | ReportingCurrencyAmount | GLNominalAccount | accountingEntity | AccountID |
+-----------------+-------------------+-----------+-----------------------------+------------------+------------------------------------+-------------------------+------------------+------------------+-----------+
| 1               | USD               | -100.0000 | USD                         | -100.0000        | USD                                | 100.0000                | 1005690          | T00              | T00       |
+-----------------+-------------------+-----------+-----------------------------+------------------+------------------------------------+-------------------------+------------------+------------------+-----------+
| 2               | USD               | 100.0000  | USD                         | 100.0000         | USD                                | 100.0000                | 34180050         | T00              | T00       |
+-----------------+-------------------+-----------+-----------------------------+------------------+------------------------------------+-------------------------+------------------+------------------+-----------+

更新MyQuery as CTE

我理解您的尝试如下:号码必须以2开头,或者以3开头,或者以4开头....除了0,1,5和9之外的任何数字。这更容易放入NOT IN() -clause

通过此操作,您可以将查询作为派生表获取,您可以使用* normal WHERE - 子句来过滤:

WITH XMLNAMESPACES(DEFAULT 'http://schema.mycompany.com/Info/2')
,myCTE AS
(
    SELECT j.value('@sequence','int') AS JELine_Sequence
          ,j.value('(Amount/@currencyID)[1]','nvarchar(max)') AS Amount_CurrencyID
          ,j.value('(Amount)[1]','decimal(14,4)') AS Amount
          ,j.value('(FunctionalAmount/@currencyID)[1]','nvarchar(max)') AS FunctionalAmount_CurrencyID
          ,j.value('(FunctionalAmount)[1]','decimal(14,4)') AS FunctionalAmount
          ,j.value('(ReportingCurrencyAmount/@currencyID)[1]','nvarchar(max)') AS ReportingCurrencyAmount_CurrencyID
          ,j.value('(ReportingCurrencyAmount)[1]','decimal(14,4)') AS ReportingCurrencyAmount
          ,j.value('(GLAccount/GLNominalAccount)[1]','bigint') AS GLNominalAccount
          ,j.value('(GLAccount/AccountingChartReference/ID/@accountingEntity)[1]','nvarchar(max)') AS accountingEntity
          ,j.value('(GLAccount/AccountingChartReference/ID)[1]','nvarchar(max)') AS AccountID

    FROM @xml.nodes('JournalEntry/JELine') AS A(j)
)
SELECT * FROM MyCTE
WHERE LEFT(GLNominalAccount,1) NOT IN('0','1','5','9')

一般来说,最好尽早设置过滤器。这是.nodes() - 函数,以便不返回不适合过滤器的节点。但在这种情况下,我认为最好返回所有节点并在之后过滤它们(如此处所做)。如果XML包含很多<JELine> - 节点,那么更改它可能会更好......

答案 1 :(得分:0)

您只需将WHERE条件更改为:

<br>

这是一个完全有效的解决方案(请注意我的评论)

WHERE ParamValues.SSD.value('GLNominalAccount[1]', 'varchar(8)') LIKE '[2-46-8]%'