zoukankan      html  css  js  c++  java
  • SQLServer2005 XML在T-SQL查询中的典型应用

    /*
    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(10primary 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.290.32 ,   0.11,    0.08
    insert @t select N'李四',    0.01 , 0.61 , 0.210.73 ,   0.21,    0.12
    insert @t select N'张五',    0.31 , 0.21 , 0.230.33 ,   0.91,    0.65
    insert @t select N'张六',    0.59 , 0.110.260.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


  • 相关阅读:
    JDBC 实例--JDBC通过工具类DBUtil连接到数据库,让我们不再恐惧操作数据库
    揭开JDBC的神秘面纱,让JDBC数据库的连接参数不再神秘
    实验六 最小代价生成树
    实验五 背包问题和带时限的作业排序
    实验四 图的遍历算法设计与实现
    实验三 跳表算法设计与实现
    实验二 伸展树算法设计与实现
    算法实例一 算法问题求解基础--欧几里得递归算法和递归算法
    2013年 蓝桥杯预赛 java 本科A 题目
    java常用开发工具类之 图片水印,文字水印,缩放,补白工具类
  • 原文地址:https://www.cnblogs.com/zhuawang/p/2158399.html
Copyright © 2011-2022 走看看