5

SO: XML data type method “value” must be a stringliteral を読みましたが、私の問題は少し異なります。変数に少しのxmlがあり、バラバラにしたいのですが、パスが与えられています。もともと私はこれを試しました:

declare @x xml
select @x = '....'
select @x.value('(' + @path + ')[1]', 'varchar(max)')

しかし、もちろん、それは失敗します。次に、 sql:variable を見つけて、これを試しました:

select @x.value('(sql:variable("@path"))[1]', 'varchar(max)')

しかし、それは不思議なことに @path の値を返します (なぜ?)。私はそれをいじっていますが、正しいことをさせることができません。

誰か考えますか?

4

3 に答える 3

3

selectはリテラル値を返す@pathための値を返します。したがって、実際には、SQLサーバーにドキュメントからsql:variable()リテラル値を選択するように要求しています。@path私があなたが望むことをすることを知っている唯一の方法は、次のように動的SQLを使用することです。

declare @xml xml = '
<root>
    <element attr="test">blah</element>
</root>';

declare @p nvarchar(max) = '(//element/text())[1]';
declare @sql nvarchar(max) 
    = 'select @x.value(''' + @p + ''', ''nvarchar(max)'')';

exec sp_executesql @sql, @parameters = N'@x xml', @x = @xml;

ただし、これはあまり良い方法ではないことを警告する必要があります(SQLインジェクション、入力の検証などについて考えてください)。

于 2012-09-13T11:12:59.873 に答える
2

Microsoft サイトのwBobの助けを借りて、今ではクリーンなソリューションを手に入れました。もちろん、単一のパスのためにドキュメント全体がマップされるため、パフォーマンスは懸念事項ですが、改善点は読者への提案の可能性として残されています:)

if object_id('VMConfigVal') is not null
drop function VMConfigVal
go
create function VMConfigVal(@x xml, @path varchar(max))
returns nvarchar(max)
as
begin
    declare @ret nvarchar(max)

    ;with cte as
    (
    select  value = x.c.value('.', 'varchar(50)')
    ,       path = cast ( null as varchar(max) )
    ,       node = x.c.query('.')
    from    @x.nodes('/*') x(c)
    union all
    select  n.c.value('.', 'varchar(50)')
    ,       isnull( c.path + '/', '/' )
        +       n.c.value('local-name(.)', 'varchar(max)')
    ,       n.c.query('*')
    from    cte c
    cross   apply c.node.nodes('*') n(c)
    )
    select @ret = value from cte where path = @path
    return @ret
    end
go

だから私は今のようなことをすることができます:

select dbo.VMConfigVal(MyXMLConfig, '/hardware/devices/IDE/ChannelCount')
from someTable

甘い!

于 2012-09-19T23:21:59.957 に答える
1

名前だけで子要素を検索する必要があり、XPath リテラルから名前を抽象化したい場合は、いくつかのオプションがあります。

// Returns the /root/node/element/@Value with @Name contained in @AttributeName SQL variable.
SELECT @Xml.value('(/root/node/element[@Name=sql:variable("@AttributeName")]/@Value)[1]', 'varchar(100)')

// Returns the text of the child element of /root/node with the name contained in @ElementName SQL variable.
SELECT @Xml.value('(/root/node/*[name(.)=sql:variable("@ElementName")]/text())[1]', 'varchar(100)')

// Searching the xml hierarchy for elements with the name contained in @ElementName and returning the text().
SELECT @Xml.value('(//*[name(.)=sql:variable("@ElementName")]/text())[1]', 'varchar(100)')

これらを実行するには、@ElementName または @AttributeName SQL 変数を宣言する必要があります。最初のステートメントはテストしましたが、他の 2 つのステートメントは明示的にテストしていません。参考までに。

于 2013-02-12T22:23:03.153 に答える