如何通过SQL替换XML变量

时间:2015-10-06 18:27:30

标签: sql sql-server xml

chtml

ntext列:

<root>
    <Phys>
          <name>Doctor1</name>
          <gender>M</gender>
          <langF1><a title="English" href="/default.aspx?id=23">English</a></langF1>
    </Phys>
</root>
<root>
    <Phys>
         <name>Doctor2</name>
         <gender>F</gender>
         <langF1><a title="French" href="/default.aspx?id=56">French</a></langF1>
    </Phys>
</root>

临时表(tableStage):

Name        Gender      Language 1
Doctor1     F           French
Doctor2     M           Spanish

存储过程,用于从登台表中的值更新表中的chtml列:

ALTER PROCEDURE [dbo].[Pro]
(
    @ProviderName varchar(200), -- "Doctor1" for example
    @genderVal varchar(10),
    @langID varchar(10),
    @langTitle varchar(60),
    @langUrl varchar(255),
    @anchorLang varchar(255),
    @langLinkXML xml,
)
AS
BEGIN
    DECLARE @xml xml

    Select @xml = cast([chtml] as xml) --cast the chtml column which is of ntext type
    From [myDb].[dbo].[myTable] --to xml so we can update the nodes
    Where [content_title] = @ProviderName

    --Update gender val (if exists, update, otherwise insert)
    Select @genderVal = t1.[Gender] From [myDb].[dbo].[tableStage] t1 --replace Value2 and table to the table which is updated through SSIS
    Where t1.Name = @ProviderName
    PRINT @genderVal

    If @xml IS NOT NULL
    BEGIN
        Set @xml.modify('replace value of (/root/Physicians/gender/text())[1] with sql:variable("@genderVal")');
    END
    Else
    BEGIN
        PRINT 'NOT WORK'
    END

    /* ERROR for above is:  "XQuery: Replacing the value of a node with an empty sequence is allowed only if '()' is used as the new value expression. The new value expression evaluated to an empty sequence but it is not '()'." instead of changing the gender to "F" */

--Update language one field (if exist, delete and add, otherwise just delete)
    --get the language id from the temp language table which matches the language for the provider
    Select @langID = t1.content_id From [myDb].[dbo].[zTempLanguageTable] t1
    INNER JOIN [myDb].[dbo].[tableStage] t2 On t2.[Language 1] = t1.content_title
    Where t2.Name = @ProviderName

    If @langID != ''
    BEGIN
        --get the language title from the language id
        Select @langTitle = t1.content_title From [myDb].[dbo].[zTempLanguageTable] t1
        Where @langID = t1.content_id

        --set the Url (which will be part static and part dynamic with the id)
        Set @langUrl = '/default.aspx?id=' + @langID + '';

        --delete the anchor entry
        Set @xml.modify('delete /root/Physicians/langF1/a');
        --create the XML for the node
        Set @langLinkXML = (
            Select @langTitle as 'a/@title',
                @langUrl as 'a/@href',
                '_blank' as 'a/@target',
                @langTitle as 'a'
                for xml path(''), type
            );

        -- insert the new/updated anchor node
        Set @xml.modify('insert sql:variable("@langLinkXML") into (/root/Physicians/langF1)[1]');
    END
    Else
    BEGIN
        --delete the anchor entry
        Set @xml.modify('delete /root/Physicians/langF1/a');
    END

    /* THE ABOVE CHANGE `chtml` to:  "<root><Physicians><name>Doctor1</name><gender>M</gender></langF1></Phys></root>" instead of <root><Physicians><name>Doctor1</name><gender>M</gender><langF1><a title="French" href="/default.aspx?id=67">French</a></langF1></Phys></root> */

/* once all the node has been "temporarily" changed, update the table columns for the provider */
Update [myDb].[dbo].[myTable]
Set [chtml] = cast(cast(@xml as nvarchar(max)) as ntext) //change the type to `ntext` data type for the table.
Where [content_title] = @ProviderName

END

如何解决我遇到的两个问题:

  • / *上面的错误是:“XQuery:用。替换节点的值 仅当'()'用作新值时才允许空序列 表达。新值表达式计算为空序列 但它不是'()'。“而不是将性别改为”F“* /

  • / *上述更改chtml: “Doctor1M” 代替 Doctor1MFrench * /

1 个答案:

答案 0 :(得分:2)

实际上我不知道你做了什么(和为什么)。这似乎很复杂......

您可以按如下方式解决错误:

只需将其粘贴到一个空的查询窗口中,然后将该想法转移到您的代码中即可。这一点是评论的第二个DECLARE @genderVal。将注释更改为其他DECLARE,您可以重现它。如果这是NULL,您将收到您描述的错误。这意味着:检查变量的值。它似乎是NULL。

请注意,我更正了错误的结束标签“Phys”并删除了内部“root”-tags ...

declare @xml XML=
'<root>
  <Physicians>
    <name>Doctor1</name>
    <gender>M</gender>
    <langF1>
      <a title="English" href="/default.aspx?id=23">English</a>
    </langF1>
  </Physicians>
  <Physicians>
    <name>Doctor2</name>
    <gender>F</gender>
    <langF1>
      <a title="French" href="/default.aspx?id=56">French</a>
    </langF1>
  </Physicians>
</root>';
select @xml;

--This will search for the physician with the name "Doctor1"... Dont' know if you need this... Your example could be meant with one XML-for each physician...
DECLARE @ProviderName varchar(200)='Doctor1';

--DECLARE @genderVal varchar(10)=NULL;
DECLARE @genderVal varchar(10)='F';

--Update Doctor1 with new @genderVal=NULL --> The error you described
SET @xml.modify('replace value of (/root/Physicians[name=sql:variable("@ProviderName")]/gender/text())[1] with sql:variable("@genderVal")');
select @xml;

编辑:更改语言

如果我理解正确,你不必费心,是否存在语言。你无论如何都要删除它

SET @xml.modify('delete (/root/Physicians[name=sql:variable("@ProviderName")]/langF1/a)[1]');
select @xml;

现在为“a”构建内部xml:

DECLARE @langTitle varchar(100)='French';
DECLARE @langLink varchar(100)='/default.aspx?id=56';
DECLARE @newLang XML='<a title="' + @langTitle + '" href="' +  @langLink + '">' + @langTitle + '</a>';

可以将此内部xml插入现有节点:

SET @xml.modify('insert sql:variable("@newLang") into (/root/Physicians[name=sql:variable("@ProviderName")]/langF1)[1]');
select @xml;