当前位置: 首页 > 图文教程 > 数据库 > MSSQL > SQLServer2005 XML在T-SQL中的应用

MSSQL
sql server的保留关键字
SQL2000 关于 Java JDBC 驱动的安装和设定
SQL Server2005数据库查询中使用CTE
如何整理SQL Server输入数据
SQL优化34条
怎样用SQL服务器调节器收集重要信息
黑客经验谈 MSSQLSA权限入侵的感悟
SQL Server企业管理器和查询分析器简介
SQL Server开发人员应聘常被问的问题
限制系统管理员对SQL Server进行访问
升级到SQL Server 2005之后转换登录
SQL Server 2000中监控失败的登录尝试
MSSQL移动到新服务器出现不匹配问题
让你见识一下SQL Server口令的脆弱性
全面调整SQL Server的硬件性能计划
SQL SERVER数据导成INSERT
SQL Server中保护数据的安全选项
防范SQL注入攻击的新办法
SQL Server数据库安全管理机制详解
妙用SQL子查询来从子表里删除数据

MSSQL 中的 SQLServer2005 XML在T-SQL中的应用


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-17   浏览: 51 ::
收藏到网摘: n/a

以下为引用的内容:

*
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