質問

私は、文字列のキーと値のペアの簡単な辞書を表し、SQL ServerのXML列から値を抽出するためのユーザー定義関数を書いています。私はそれがうまく行った唯一の方法は、これまで過度に複雑なようです。あなたは以下のDictValue機能のための任意の簡素化提案やヒントを持っていますか?

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[DictValue]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[DictValue]
go

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[TableWithXmlColumn]') AND type in (N'U'))
DROP TABLE [dbo].[TableWithXmlColumn]
go

create table TableWithXmlColumn (
    Id int identity primary key
    ,Dict xml
    )
go

create function DictValue(
    @id int
    ,@key nvarchar(max)
    ) returns nvarchar(max) as begin

    declare @d xml -- string Dictionary
    select @d = Dict from TableWithXmlColumn where Id = @id
    declare @value xml
    select 
            @value = d.Pair.value('data(.)', 'nvarchar(max)')
        from 
            @d.nodes('/StringDictionary/Pair') as d(Pair)
        where 
            @key = d.Pair.value('./@Key', 'nvarchar(max)')

    return convert(nvarchar(max), @value)
    end
go

declare @xmlId int
insert TableWithXmlColumn (Dict) values (
    N'<?xml version="1.0" encoding="utf-16"?>
    <StringDictionary>
      <Pair Key="color">red</Pair>
      <Pair Key="count">123</Pair>
    </StringDictionary>')
set @xmlId = scope_identity()

select 
    dbo.DictValue(@xmlId, 'color') as color
    ,dbo.DictValue(@xmlId, 'count') as [count]
役に立ちましたか?

解決

私が理解しやすい次の変数結合のXQueryアプローチを見つけます

create function DictValue(
  @id int,
  @key nvarchar(max)
) 
returns nvarchar(max) as 
begin
  declare @value nvarchar(max)
  select 
    @value = Dict.value(
      '(StringDictionary/Pair[@Key=sql:variable("@key")])[1]', 
      'nvarchar(max)'
    ) 
    from TableWithXmlColumn
    where Id = @id
  return @value
end

私はそれを検証しませんでしたが、それはT-SQLとXQueryエンジンでコンテキストスイッチを回避し、一つだけXQueryを必要とするため、これは、あまりにも、少し良く実行することがあります。

私はちょうどあなたが1つのIDのためのdict XMLは、同じキーを持つ複数のペア要素が含まれている可能性があるかどうかを指定していないことに気づきます:

insert TableWithXmlColumn (Dict) values (
  N'<?xml version="1.0" encoding="utf-16"?>
    <StringDictionary>
      <Pair Key="color">red</Pair>
      <Pair Key="color">blue</Pair>
      <Pair Key="count">123</Pair>
    </StringDictionary>')
その場合は、

、彼らが存在する場合、複数の値を列挙して結合するFLWOR XQueryを使用して、このわずかに変更された機能を、考えます。 @idが見つからない場合、この場合には機能だけでペア要素@key一致がないではない場合は、NULLを返すこと、しかし、注意します。

create function DictValue(
  @id int,
  @key nvarchar(max)
) 
returns nvarchar(max) as 
begin
  declare @value nvarchar(max)
  select 
    @value = Cast(
      Dict.query('
        for $i in StringDictionary/Pair[@Key=sql:variable("@key")] 
        return string($i)
      ') as nvarchar(max)) 
    from TableWithXmlColumn
    where Id = @id
  return @value
end

グッドラック!

他のヒント

個人的に私はあなたが、結果が第1セットを取得するためにあなたは非常に読みやすい方法で構成されている、とあなたはXMLを照会しているコードは、その後、値をつかん行うことができます多くは表示されません。

あなたは@d変数の使用を回避することができるかもしれません、しかし、私は、コードの可読性が大幅に苦しむことになると信じています。

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[XMLTable](@x XML)  
RETURNS TABLE 
AS RETURN 
WITH cte AS (  
SELECT 
        1 AS lvl,  
        x.value('local-name(.)','NVARCHAR(MAX)') AS Name,  
        CAST(NULL AS NVARCHAR(MAX)) AS ParentName, 
        CAST(1 AS INT) AS ParentPosition, 
        CAST(N'Element' AS NVARCHAR(20)) AS NodeType,  
        x.value('local-name(.)','NVARCHAR(MAX)') AS FullPath,  
        x.value('local-name(.)','NVARCHAR(MAX)')  
        + N'[' 
        + CAST(ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS NVARCHAR)  
        + N']' AS XPath,  
        ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS Position, 
        x.value('local-name(.)','NVARCHAR(MAX)') AS Tree,  
        x.value('text()[1]','NVARCHAR(MAX)') AS Value,  
        x.query('.') AS this,         
        x.query('*') AS t,  
        CAST(CAST(1 AS VARBINARY(4)) AS VARBINARY(MAX)) AS Sort,  
        CAST(1 AS INT) AS ID  
FROM @x.nodes('/*') a(x)  
UNION ALL 
SELECT 
        p.lvl + 1 AS lvl,  
        c.value('local-name(.)','NVARCHAR(MAX)') AS Name,  
        CAST(p.Name AS NVARCHAR(MAX)) AS ParentName, 
    CAST(p.Position AS INT) AS ParentPosition, 
        CAST(N'Element' AS NVARCHAR(20)) AS NodeType,  
        CAST(p.FullPath + N'/' + c.value('local-name(.)','NVARCHAR(MAX)') AS NVARCHAR(MAX)) AS FullPath,  
        CAST(p.XPath + N'/'+ c.value('local-name(.)','NVARCHAR(MAX)')+ N'['+ CAST(ROW_NUMBER() OVER(PARTITION BY c.value('local-name(.)','NVARCHAR(MAX)') 
        ORDER BY (SELECT 1)) AS NVARCHAR)+ N']' AS NVARCHAR(MAX)) AS XPath,  
        ROW_NUMBER() OVER(PARTITION BY c.value('local-name(.)','NVARCHAR(MAX)')
        ORDER BY (SELECT 1)) AS Position, 
        CAST( SPACE(2 * p.lvl - 1) + N'|' + REPLICATE(N'-', 1) + c.value('local-name(.)','NVARCHAR(MAX)') AS NVARCHAR(MAX)) AS Tree,  
        CAST( c.value('text()[1]','NVARCHAR(MAX)') AS NVARCHAR(MAX) ) AS Value, c.query('.') AS this,  
        c.query('*') AS t,  
        CAST(p.Sort + CAST( (lvl + 1) * 1024 + (ROW_NUMBER() OVER(ORDER BY (SELECT 1)) * 2) AS VARBINARY(4)) AS VARBINARY(MAX) ) AS Sort,  
        CAST((lvl + 1) * 1024 + (ROW_NUMBER() OVER(ORDER BY (SELECT 1)) * 2) AS INT)  
FROM cte p  
CROSS APPLY p.t.nodes('*') b(c)), cte2 AS (  
                                            SELECT 
                                            lvl AS Depth,  
                                            Name AS NodeName,  
                                            ParentName, 
                                            ParentPosition, 
                                            NodeType,  
                                            FullPath,  
                                            XPath,  
                                            Position, 
                                            Tree AS TreeView,  
                                            Value,  
                                            this AS XMLData,  
                                            Sort, ID  
                                            FROM cte  
UNION ALL 
SELECT 
        p.lvl,  
        x.value('local-name(.)','NVARCHAR(MAX)'),  
        p.Name, 
        p.Position, 
        CAST(N'Attribute' AS NVARCHAR(20)),  
        p.FullPath + N'/@' + x.value('local-name(.)','NVARCHAR(MAX)'),  
        p.XPath + N'/@' + x.value('local-name(.)','NVARCHAR(MAX)'),  
        1, 
        SPACE(2 * p.lvl - 1) + N'|' + REPLICATE('-', 1)  
        + N'@' + x.value('local-name(.)','NVARCHAR(MAX)'),  
        x.value('.','NVARCHAR(MAX)'),  
        NULL,  
        p.Sort,  
        p.ID + 1  
FROM cte p  
CROSS APPLY this.nodes('/*/@*') a(x)  
)  
SELECT 
        ROW_NUMBER() OVER(ORDER BY Sort, ID) AS ID,  
        ParentName, ParentPosition,Depth, NodeName, Position,   
        NodeType, FullPath, XPath, TreeView, Value, XMLData 
FROM cte2
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top