• SQLXML


    /*
    SQLServer2005 XML在T-SQL查询中的典型应用
    
    整理:fcuandy
    时间:2008.11.7
    
    前言:
        此文只讲xml数据类型及相应的一些操作方法在解决日常T-SQL编程中的一些应用,而避开xml modify,
    xml schema,xml索引,命名空间等这些语法性或者生硬的一些问题(这些语法您可以查联机丛书),即此文主要
    讲以xml的一些操作特性及xquery去解决编程问题.
    
    Tags:
        xquery ,FLWOR迭带 ,sql:column ,sql:variable ,nodes ,value ,query ,xpath ,xquery function, if, 聚合函数, xs:function等
    
    典型应用举例:
    */
    
    
    --(1)
    --====================================================================
    --拆分
    DECLARE @s VARCHAR(100)
    SET @s='a,b,c,dd,ee,f,aa,a,aa,f'
    
    --常规做法(sql2000常用),以一split函数拆分串为表类型结构,如
    --SELECT * FROM dbo.split(@s,',') a
    --当然,也可能是循环去拆分,或者以一输助表的identity列利用charindex等函数拿identity列值与','的位置匹配实现拆分
    --这些做法,roy_88及本人以前都整理过,不再累赘,可见推荐贴。即便 是xml法,也贴过多次,下面一笔带过
    
    --XML做法:
    SELECT b.v FROM
        (SELECT CAST('<r>' + REPLACE(@s,',','</r><r>') + '</r>' AS XML) x) a   --将字串","换换为"</r><r>"并前后拼上<r>,</r>以用来构造xml串
    CROSS APPLY
        (SELECT v=t.x.value('.','VARCHAR(10)') FROM a.x.nodes('//r') AS t(x) ) b  --使用 xml.nodes函数将xml串拆分为行
    /*
    a
    b
    c
    dd
    ee
    f
    aa
    a
    aa
    f
    */
    
    
    --(2)
    --====================================================================
    --去重,@s中出现的元素,重复的只要一个,希望结果为 'a,b,c,dd,ee,f'
    --常规做法,循环或函数,或临时表拆后distinct
    --XML做法:
    --a.在(1)的基础上进行
    
    ;WITH fc AS   --定义cte命名,将@s转换为一个表结构
    (
        SELECT DISTINCT b.v v
                FROM
                    (SELECT CAST('<r>' + REPLACE(@s,',','</r><r>') + '</r>' AS XML) x) a
                CROSS APPLY
                    (SELECT v=t.x.value('.','VARCHAR(10)') FROM a.x.nodes('//r') AS t(x) ) b
    )
    --对这个表利用xml方法进行行值拼接
    SELECT STUFF(b.v.value('/r[1]','varchar(100)'),1,1,'')
        FROM
        (SELECT v=(SELECT ',' + v FROM fc FOR XML PATH(''),ROOT('r'),TYPE)) b
    /*
    a,aa,b,c,dd,ee,f
    */
    
    --b FLWOR语句 + T-SQL组合:
    SELECT STUFF(v,1,1,'') FROM
        (SELECT CAST('<r>' + REPLACE(@s,',','</r><r>') + '</r>' AS XML) x) a
    CROSS APPLY
        (SELECT x=(SELECT t.x.value('.','varchar(10)') v,idx=ROW_NUMBER() OVER(ORDER BY GETDATE()) FROM a.x.nodes('//r') AS t(x) FOR XML PATH('r'),TYPE)) b --利用row_number得到唯一idx
    CROSS APPLY
        (SELECT v=CAST(b.x.query('for $r in //r where count(//r[v=$r/v and idx<$r/idx])=0 return concat(",",xs:string($r/v[1]))') AS VARCHAR(MAX))) c  --类似count计数法,取得v相同的节点集idx值最小的节点,原型为:
    --SELECT * FROM tb a WHERE 1>(SELECT COUNT(*) FROM tb WHERE v=a.v AND id<a.id)
    /*
    a ,b ,c ,dd ,ee ,aa ,f
    */
    
    
    --c distinct-values
    SELECT REPLACE(v,' ',',') FROM
        (SELECT CAST('<r>' + REPLACE(@s,',','</r><r>') + '</r>' AS XML) x) a
    CROSS APPLY
        (SELECT CAST(a.x.query('distinct-values(//r)') AS VARCHAR(MAX)) v) b  --直接调用distinct-values函数来操作
    /*
    a,b,c,dd,ee,f,aa
    */
    
    
    -- 导入去重, last() , position()
    
    DECLARE   @doc  xml
    SET   @doc   ='<?xml version="1.0" encoding="gb2312" ?>
    <employees>
        <employee>
            <empid>e0001</empid>
            <name>萧峰</name>
        </employee>
        <employee>
            <empid>e0002</empid>
            <name>段誉</name>
        </employee>
        <employee>
            <empid>e0003</empid>
            <name>王语嫣</name>
        </employee>
        <employee>
            <empid>e0003</empid>
            <name>张无忌</name>
        </employee>
    </employees>
    '
    create table people2 
    ( 
        personid varchar(10)  primary key ,
        name varchar(20) 
     )
    
    INSERT people2
    SELECT DISTINCT b.* FROM
        (SELECT x = @doc.query('for $e in //employee  return  //employee[empid = $e/empid][last()]')) a  --FLWOR时,用当前节点去//emploee节点集中找节点集中empid等于当前节点的empid, 在找到的集合中取最后一个利用last()函数
    CROSS APPLY
        (SELECT id=t.x.value('empid[1]','varchar(100)'),name=t.x.value('name[1]','varchar(100)') FROM a.x.nodes('//employee') AS t(x)) b
    
    SELECT * FROM people2
    /*
    e0001    萧峰
    e0002    段誉
    e0003    张无忌
    */
    GO
    drop table people2 
    GO
    --同组一选多,也可应用此方法,不过没有必要,就不再累赘了。
    
    
    --(3)
    --====================================================================
    --列名,列值相关
    --a,按行聚合
    declare @t table(Sname nvarchar(5),  V1 float,    V2 float,    V3 float,      V4 float,    V5 float,      V6 float) 
    insert @t select N'张三',    0.11 , 0.21 , 0.29,  0.32 ,   0.11,    0.08 
    insert @t select N'李四',    0.01 , 0.61 , 0.21,  0.73 ,   0.21,    0.12 
    insert @t select N'张五',    0.31 , 0.21 , 0.23,  0.33 ,   0.91,    0.65 
    insert @t select N'张六',    0.59 , 0.11,  0.26,  0.13,    0.01,    0.15 
    
    select b.* from
        (select x=cast((select * from @t for xml path('r')) as xml)) a
    cross apply
        (
            select name=x.query('./Sname/text()'),v=x.query('max(./*[local-name(.)!="Sname"])') from a.x.nodes('//r') as t(x)  
            --r为二级节点(因为文档本身无根节点,即为每项的顶级节点)即为一个r节点表示一条记录. r下级节点,每个表示一个列,因为列名未知,所以用/*匹配所有节点,因为name为区别列,不参与聚合运算,故用local-name取得来过滤
        ) b
    
    /*
    张三    0.32
    李四    0.73
    张五    0.91
    张六    0.59
    */
    
    --b ,由值引到取列
    if not object_id('T1') is null
        drop table T1
    GO
    Create table T1([tId] int,[tName] nvarchar(4))
    Insert T1
    select 1,N'zhao' union all
    select 2,N'qian' union all
    select 3,N'sun'
    Go
    --> --> 借且(Roy)生成測試數據
     
    if not object_id('T2') is null
        drop table T2
    Go
    Create table T2([tId] int,[zhao] nvarchar(1),[qian] nvarchar(1),[sun] nvarchar(1))
    Insert T2
    select 1,N'a',N'b',N'c' union all
    select 2,N'd',N'e',N'f' union all
    select 3,N'g',N'h',N'i'
    Go
    
    
    SELECT c.tid,c.tName,v FROM t1 c
    CROSS APPLY
        (SELECT x=(SELECT * FROM t2 WHERE tid=c.tid FOR XML PATH('r'),TYPE)) a
    CROSS APPLY
        (SELECT v=t.x.query('./*[local-name(.)=xs:string(sql:column("c.tName")) ]/text()') 
            FROM a.x.nodes('//r') AS t(x)
        ) b
    
    /*
    1    zhao    a
    2    qian    e
    3    sun    i
    */
    
    
    --c, 列名,列值,与系统表 
    
    CREATE TABLE tb(f1 INT,f2 INT,x INT,z INT,d INT,ex INT,dd INT,vv INT) 
    INSERT tb SELECT 1,2,3,5,11,3,2423,33 
    GO 
    SELECT * FROM tb 
    GO 
    SELECT name,v FROM
      ( SELECT name FROM sys.columns WHERE object_id=object_id('tb','u') ) a 
    CROSS JOIN
      (SELECT x=(SELECT * FROM tb FOR XML PATH('r'),TYPE)) b 
    CROSS APPLY
     (SELECT v=t.x.query('./*[local-name(.)=xs:string(sql:column("a.name")) ]/text()') FROM b.x.nodes('//r') AS t(x) ) c 
    /*
    f1    1
    f2    2
    x    3
    z    5
    d    11
    ex    3
    dd    2423
    vv    33
    */
    GO 
    DROP TABLE tb
    GO
    
    --(4)
    --一些综合计算
    --以下表 ta.a值 yyyymmdd-yyyymmdd表连续时间段,","表单个日期
    If object_id('ta','u') is not null 
        Drop table ta
    Go
    Create table ta(a varchar(100))
    Go
    Insert into ta
    select '1 | |20080101-20080911' 
    union all
    select '2 | |20080101,20080201,20080301,20080515,20080808'
    union all
    select '3 | |20080101,20080201,20080301,20080515,20081108'
    Go
    
    declare @s varchar(8)
    select @s= convert(varchar(8),getdate(),112)
    
    select stuff(replace(replace(cast(x as varchar(1000)),'</item><item>',case when type='1' then '-' else ',' end),'</item>',''),1,6,type + ' | |') a
        from
        (
            select left(a,1) type, 
                cast(
                        '<item>' 
                        + 
                        replace(
                            stuff(a,1,5,''),
                            case when left(a,1)=1 then '-' else ',' end,
                            '</item><item>'
                            )
                        + 
                        '</item>'
                    AS XML
                    ) x
            from ta
        ) base
    
        where x.value('
                if (sql:column("base.type")="1") then
                    if(
                        (/item/text())[1]<sql:variable("@s")
                        and
                        (/item/text())[2]>sql:variable("@s")
                    )
                    then 1
                    else 0
                else
                    count(//item[text()>sql:variable("@s")])
                '
                ,
                'int'
                )>0
    go
    
    
    
    
    
    SQL Server中用XQuery分解XML数据
    本文讨论SQL Server 2005的新功能,它允许你将XML数据分解到关系格式中,而不必耗用太多内存。 
    
    在举例说明如何分解上一篇文章中的数据时,我们首先了解一下XQuery和它在SQL Server 2005中为开发者提供的功能。 
    
    XQuery介绍 
    
    XQuery,也称作XML Query,是一种查询XML数据的语言,允许你提取所需的节点和元素。它由W3C定义,可用于今天的大多数主流数据库引擎中,如Oracle、DB2和SQL Server。 
    
    SQL Server 2005 XQuery函数 
    
    下面的四个函数是SQL Server 2005中的XQuery函数。(注意,XML、XQuery语句和下面的函数都区分大小写。例如,SQL编译器接受XML数据中的.exist,但拒绝.EXIST或.Exist。) 
    
    
    xml.exist 
    
    这个方法根据一个XML节点上的搜索表达式返回一个布尔值。例如,列表A中XML代码片段中的语句将返回1(真): 
    
    
    SELECT @x.exist('/christmaslist/person[@gift = "socks"]') 
    
    这个语句返回0(假): 
    
    
    SELECT @x. exist ('/christmaslist/zach') 
    
    由于“Socks”一词被封套,这个语句将返回0(假)。 
    
    
    SELECT @x.exist('/christmaslist/person[@gift = "socks"]')
    
    xml.value 
    
    这个方法接受一个XQuery语句并返回一个单独值。使用列表A中同样的XML代码片段,不可以使用VALUE函数生成“betty”值,如下所示: 
    
    
    SELECT @x.value('/christmaslist[1]/person[1]/@name', 'VARCHAR(20)') 
    
    而XQuery生成“zach”值。 
    
    
    SELECT @x.value('/christmaslist[1]/person[2]/@name', 'VARCHAR(20)')
    
    xml.query 
    
    这个方法接受一个XQuery并返回一个XML数据类型的实例。可以按需要将这些查询简单或复杂化,下面是一个简单的例子: 
    
    
    SELECT @x.query('/christmaslist/person') 
    
    它返回XML文件: 
    
    
    <person name="betty" gift="camera" />
    
    <person name="zach" gift="elmo doll" />
    
    <person name="brad" gift="socks" />
    
    xml.nodes 
    
    在你需要将一个XML数据类型变量中的数据分解到关系数据中时,这个方法十分有用。这个方法接受一个XQuery语句作为参数,并返回一个包含XML变量逻辑标量数据的行集。列表B中的查询利用上面定义的XML变量,并将数据分解到一个结果集中,它显示在XML变量中定义的人物姓名。 
    
    修改OPENXML存储过程 
    
    现在我来说明如何修改上周的OPENXML存储过程,使其可以应用XQuery功能。首先,我往XML变量中加载一些数据。如列表C所示。我们可以建立一个接受XML参数的过程,再应用XQuery函数把XML文件中的数据插入一个表中,而不必应用OPENXML。如列表D所示。 
    
    最初在数据库中应用XML似乎有些难于处理,还要花一些时间习惯使用XQuery和Xpath查询。但是,经过一段时间的学习以后,你就会发现在数据库中应用XML数据相当实用。 
    
    例如,在上述存储过程中应用XML数据,你只需调用一次数据库,而不必像典型存储过程编程那样调用N次数据库。这二者似乎区别不大,但对一个繁忙的系统而言,应用XML数据会有很大益处。而且,应用XQuery而非OPENXML还会显著提高性能,对小型XML文件更是如此。 
    
    
    
    
    对我有用[0]丢个板砖[0]引用举报管理TOP
    精华推荐:[分享]查看索引信息/生成创建索引脚本
    
    fredrickhu
    (小F)
    等 级:
    2
    5
    更多勋章
    #3楼 得分:0回复于:2010-02-02 09:51:09
    SQL code
    select @data.query('//address[@data="+534654765876876"]')
    
    对我有用[0]丢个板砖[0]引用举报管理TOP
    精华推荐:牢记!SQL Server数据库开发的二十一条军规(SQL收藏)
    
    fredrickhu
    (小F)
    等 级:
    2
    5
    更多勋章
    #4楼 得分:0回复于:2010-02-02 09:51:30
    SQL code
    /*
    sql xml 入门:
        --by jinjazz
        --http://blog.csdn.net/jinjazz
        
        1、xml:        能认识元素、属性和值
        
        2、xpath:    寻址语言,类似windows目录的查找(没用过dir命令的话就去面壁)
                    
                    语法格式,这些语法可以组合为条件:
                    "."表示自己,".."表示父亲,"/"表示儿子,"//"表示后代,
                    "name"表示按名字查找,"@name"表示按属性查找
                    
                    "集合[条件]" 表示根据条件取集合的子集,条件可以是
                        数  值:数字,last(),last()-数字 等
                        布尔值:position()<数字,@name='条件',name='条件'
                    条件是布尔值的时候可以合并计算:and or
        
        3、xquery:    基于xpath标的准查询语言,sqlserver xquery包含如下函数
                    exist(xpath条件):返回布尔值表示节点是否存在
                    query(xpath条件):返回由符合条件的节点组成的新的xml文档
                    value(xpath条件,数据类型):返回指定的标量值,xpath条件结果必须唯一
                    nodes(xpath条件): 返回由符合条件的节点组成的一行一列的结果表
    */
    
    declare @data xml
    set @data='
    <bookstore>
    <book category="COOKING">
      <title lang="en">Everyday Italian</title>
      <author>Giada De Laurentiis</author>
      <year>2005</year>
      <price>30.00</price>
    </book>
    <book category="CHILDREN">
      <title lang="jp">Harry Potter</title>
      <author>J K. Rowling</author>
      <year>2005</year>
      <price>29.99</price>
    </book>
    <book category="WEB">
      <title lang="en">XQuery Kick Start</title>
      <author>James McGovern</author>
      <author>Per Bothner</author>
      <author>Kurt Cagle</author>
      <author>James Linn</author>
      <author>Vaidyanathan Nagarajan</author>
      <year>2003</year>
      <price>49.99</price>
    </book>
    <book category="WEB">
      <title lang="cn">Learning XML</title>
      <author>Erik T. Ray</author>
      <year>2003</year>
      <price>39.95</price>
    </book>
    </bookstore>
    '
    
    --测试语句,如果不理解语法请参考上面的xpath规则和xquery函数说明
    
    --1、文档
    select @data
    --2、任意级别是否存在price节点
    select @data.exist('//price')
    --3、获取所有book节点
    select @data.query('//book')
    --4、获取所有包含lang属性的节点
    select @data.query('//*[@lang]') 
    --5、获取第一个book节点
    select @data.query('//book[1]')
    --6、获取前两个book节点
    select @data.query('//book[position()<=2]')
    --7、获取最后一个book节点
    select @data.query('//book[last()]')
    --8、获取price>35的所有book节点
    select @data.query('//book[price>35]')
    --9、获取category="WEB"的所有book节点
    select @data.query('//book[@category="WEB"]')
    --10、获取title的lang="en"的所有book节点
    select @data.query('//book/title[@lang="en"]')
    --11、获取title的lang="en"且 price>35的所有book节点
    select @data.query('//book[./title[@lang="en"] or price>35 ]')
    --12、获取title的lang="en"且 price>35的第一book的(第一个)title
    select @data.query('//book[./title[@lang="en"] and price>35 ]').value('(book/title)[1]','varchar(max)')
    --13、等价于12
    select @data.value('(//book[./title[@lang="en"] and price>35 ]/title)[1]','varchar(max)')
    --14、获取title的lang="en"且 price>35的第一book的(第一个)title的lang属性
    select @data.value('((//book[@category="WEB" and price>35 ]/title)[1]/@lang)[1]','varchar(max)')
    --15、获取第一本书的title
    select Tab.Col.value('(book/title)[1]','varchar(max)') as title
        from @data.nodes('bookstore')as Tab(Col) 
    --16、获取每本书的第一个author
    select Tab.Col.value('author[1]','varchar(max)') as title
        from @data.nodes('//book')as Tab(Col)
    --17、获取所有book的所有信息
    select
     T.C.value('title[1]','varchar(max)') as title,
     T.C.value('year[1]','int') as year,
     T.C.value('title[1]','varchar(max)')as title,
     T.C.value('price[1]','float') as price,
     T.C.value('author[1]','varchar(max)') as author1,
     T.C.value('author[2]','varchar(max)') as author2,
     T.C.value('author[3]','varchar(max)') as author3,
     T.C.value('author[4]','varchar(max)') as author4
    from @data.nodes('//book') as T(C)
    --18、获取不是日语(lang!="jp")且价格大于35的书的所有信息
    select
     T.C.value('title[1]','varchar(max)') as title,
     T.C.value('year[1]','int') as year,
     T.C.value('title[1]','varchar(max)')as title,
     T.C.value('price[1]','float') as price,
     T.C.value('author[1]','varchar(max)') as author1,
     T.C.value('author[2]','varchar(max)') as author2,
     T.C.value('author[3]','varchar(max)') as author3,
     T.C.value('author[4]','varchar(max)') as author4
    from @data.nodes('//book[./title[@lang!="jp"] and price>35 ]') as T(C)
    
    
    http://www.tzwhx.com/newOperate/html/1/13/132/11692.html
  • 相关阅读:
    042.hiveLEFT SEMI JOIN 、 left anti join、inner join、full join
    032.hive rollup 、 with cube 、 grouping sets
    023.linuxshell抽取文本中某几行插入到另一个文
    041.mysql查询mysql元数据来格式化datax同步脚本,查询语句、拼接的json语句dataxmysql到hive
    33.hivecollect_set组合数组(数组内去重) 、array_contains 判断数组内是否又某个值返回布尔类型、concat_ws
    vue vant组件库 card组件 修改 thumb属性的图片 参数后不及时刷新解决
    idea 警告 The IDE is running low on memory and this might affect performance. Please consider increasing available heap. 解决
    尺子控件WinForm控件开发系列
    自定义形状按钮WinForm控件开发系列
    code ERESOLVE, ERESOLVE could not resolve
  • 原文地址:https://www.cnblogs.com/xiaofengfeng/p/1828469.html
Copyright © 2020-2023  润新知