ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

T-SQL——查询输出XML类型

2021-12-09 10:31:10  阅读:185  来源: 互联网

标签:XML 语文 Name -- 查询 李四 SQL SELECT


 

目录

 

志铭-2021年10月23日 10:43:21

0. 将结果集转化为XML格式

  1. 测试数据
IF OBJECT_ID('tempdb..#tempStu') IS NOT NULL
BEGIN
    DROP TABLE #tempStu;
END;

CREATE TABLE #tempStu
(
    [Name] VARCHAR(4),
    [SubjectName] VARCHAR(4),
    [Scores] INT
);
INSERT INTO #tempStu
(
    Name,
    SubjectName,
    Scores
)
VALUES
('张三', '语文', 90),
('李四', '语文', 100),
('王五', '语文', 80);
  1. FOR XML AUTO
  • 表名作为节点名称
  • 一行作为一个节点,字段列作为节点属性
--AUTO则默认节点的名称为表名称
SELECT * FROM #tempStu WHERE Name = '李四' FOR XML AUTO;


--结果:(这里使用的是临时表,前面的_x0023_是数据库默认生成的)
--<_x0023_tempStu Name="李四" SubjectName="语文" Scores="100" />
  1. FOR XML RAW
  • 通过RAW() 参数设置节点名称,无参默认节点名称为row
  • 一行作为一个节点,字段列作为节点属性
--无参默认的使用row作为节点名称
SELECT * FROM	#tempStu FOR XML RAW
--结果:
--<row Name="李四" SubjectName="语文" Scores="100" />

--使用参数设置节点名称
SELECT * FROM #tempStu WHERE Name = '李四' FOR XML RAW('Stu');
--结果:
--<Stu Name="李四" SubjectName="语文" Scores="100" />
  1. ELEMENTS
  • 一行作为一个父节点,每一个字段作为一个子节点
SELECT Name,
       SubjectName,
       Scores
FROM #tempStu
FOR XML AUTO, ELEMENTS;

-- --结果:
-- <_x0023_tempStu>
--      <Name>张三</Name>
--      <SubjectName>语文</SubjectName>
--      <Scores>90</Scores>
-- </_x0023_tempStu>
-- <_x0023_tempStu>
--      <Name>李四</Name>
--      <SubjectName>语文</SubjectName>
--      <Scores>100</Scores>
-- </_x0023_tempStu>
-- <_x0023_tempStu>
--      <Name>王五</Name>
--      <SubjectName>语文</SubjectName>
--      <Scores>80</Scores>
-- </_x0023_tempStu>

  1. FOR XML PATH
  • 一行一个父节点,每一个字段作为一个子节点
  • PATH() 参数为父节点名称,无参则父节点名称默认为row
  • 可以认为是FOR XML RAW ,ELEMENT的快捷方法
SELECT Name,
       SubjectName,
       Scores
FROM #tempStu
FOR XML PATH

-- 结果:
-- <Student>
--   <Name>张三</Name>
--   <SubjectName>语文</SubjectName>
--   <Scores>90</Scores>
-- </Student>
-- <Student>
--   <Name>李四</Name>
--   <SubjectName>语文</SubjectName>
--   <Scores>100</Scores>
-- </Student>
-- <Student>
--   <Name>王五</Name>
--   <SubjectName>语文</SubjectName>
--   <Scores>80</Scores>
-- </Student>

  1. 创建根节点:ROOT
SELECT * FROM	#tempStu FOR XML RAW('Stu'),ROOT('Students')
--结果:
-- <Students>
--   <Stu Name="张三" SubjectName="语文" Scores="90" />
--   <Stu Name="李四" SubjectName="语文" Scores="100" />
--   <Stu Name="王五" SubjectName="语文" Scores="80" />
-- </Students>


1. 列值拼接为字符串

即实现某一列的列值累加为字符串,这个需求的实现方法有多种,可以参考我之前的博文T-SQL——透视PIVOT动态获取待扩展元素集

该文中就是动态的将列值拼接为使用逗号隔开的字符串,

这里通过使用FOR XML PATH('')和STUFF()函数实现列值的拼接

DECLARE @subjectStr VARCHAR(100);
WITH cteStudent AS 
(
    SELECT '张三' AS Name,'语文'AS  SubjectName,90 AS Scores
    UNION ALL
    SELECT '张三' AS Name,'数学'AS  SubjectName,90 AS Scores
    UNION ALL
    SELECT '李四' AS Name,'语文'AS  SubjectName,100 AS Scores
    UNION ALL
    SELECT '李四' AS Name,'数学'AS  SubjectName,100 AS Scores
    UNION ALL
    SELECT '王五' AS Name,'语文'AS  SubjectName,80 AS Scores  
)
,Temp AS 
(
SELECT	DISTINCT SubjectName FROM cteStudent
)
SELECT @subjectStr =STUFF((SELECT ','+SubjectName  FROM Temp FOR XML PATH('')),1,1,'')
SELECT @subjectStr
--结果:
--数学,语文


2. 字符串转换为列值

将一串使用特定符号分隔的字符,转换为一个表值。

实现这个功能的方法很多,可以参考我之前的博文

这里我们通过XML类型和REPLACE()函数实现字符串的分裂

--需要
DECLARE @str VARCHAR(MAX)='1,2,3,4,';


DECLARE @xmlstr XML;
SET ARITHABORT ON;
SET @xmlstr=CONVERT(XML, '<root><v>'+REPLACE(@str, ',', '</v><v>')+'</v></root>');
--SELECT @xmlstr
DECLARE @tableVar TABLE (F1 VARCHAR(100))
INSERT INTO @tableVar
SELECT F1=N.v.value('.', 'varchar(100)') FROM @xmlstr.nodes('/root/v') N(v);
SELECT * FROM @tableVar;

--结果
F1
--
1
2
3
4
    --因为待分裂的字符串结尾也有一个逗号,所以这里是空字符串

上述操作在实际开发是中可以简单的封装为一个表值函数,便于重复使用

CREATE FUNCTION dbo.funSplitStr
(
    @str varchar(1000),--待分裂的字符串
    @separator varchar(10)--字符串中分隔使用的符号,比如说','
)
RETURNS @tableVar TABLE
(
    F1 VARCHAR(100)
)
AS
BEGIN
    DECLARE @xmlstr XML;
    --SET ARITHABORT ON;
    SET @xmlstr = CONVERT(XML, '<root><v>' + REPLACE(@str, @separator, '</v><v>') + '</v></root>');
    --SELECT @xmlstr;

    INSERT INTO @tableVar
    SELECT F1 = N.v.value('.', 'varchar(100)') FROM @xmlstr.nodes('/root/v') N(v);
	RETURN;
END;
GO

--测试该函数
DECLARE @str VARCHAR(100)='1,2,3,4,'
DECLARE @separator VARCHAR(10)=','

SELECT * FROM  dbo.funSplitStr(@str,@separator)
--结果
F1
-------
1
2
3
4
    --空字符串
  • 示例:分组求和,并将聚合字段值使用“,”保留在一起
---测试数据
DECLARE @test TABLE
(
    [Name] VARCHAR(4),
    [Subject] VARCHAR(4),
    [Grade] INT
);
INSERT INTO @test
VALUES
('张三', '语文', 100),
('张三', '数学', 90),
('李四', '语文', 90),
('李四', '数学', 80),
('李四', '英语', 70);

SELECT * FROM @test


SELECT Name,  
	   Subjects= STUFF( (SELECT ','+Subject FROM  @test WHERE Name=T1.Name FOR XML  PATH ('')),1,1,'') ,
	   SUM(Grade) AS TotalGrade
FROM @test AS T1 
GROUP BY Name  


--结果:
Name    Subjects                  Grade 
-----   ----------------          -----
李四    语文,数学,英语              240
张三    语文,数学                   190


3. 一些说明

现在开发中,除了配置文件使用XML,我已经很少有需要使用XML的地方了,

SQL Server2000中便存在XML类型,2005中扩展了一些针对XML的操作函数。

而在SQL Server2016中已经支持JSON了,添加了许多处理JSON的内置函数。

但是,通过SQL Server中的XML类型处理字符串是及其便利的,如上文中的将字符串串转为列值等。

其用处还体现在一些需要数据库动态生成SQL语句的地方,总而言之就是方便与构造一些字符串

这里在举一个例子,无实际的意义,但是可以开阔一下思维。

示例:数据库层面构造简单的JSON字符串

DECLARE @test TABLE
(
    [Name] VARCHAR(4),
    [Subject] VARCHAR(4),
    [Grade] INT
);
INSERT INTO @test
VALUES
('张三', '语文', 100),
('张三', '数学', 90),
('李四', '语文', 90),
('李四', '数学', 80),
('李四', '英语', 70);

SELECT '['+STUFF((SELECT ',{"name":"'+Name+'","subject":"'+[Subject]+'","grade":"' +CAST(Grade AS  VARCHAR(4))+'"}' FROM	@test FOR XML PATH ('')),1,1,'') +']'

--结果:

-- [
--     {
--         "name": "张三", 
--         "subject": "语文", 
--         "grade": "100"
--     }, 
--     {
--         "name": "张三", 
--         "subject": "数学", 
--         "grade": "90"
--     }, 
--     {
--         "name": "李四", 
--         "subject": "语文", 
--         "grade": "90"
--     }, 
--     {
--         "name": "李四", 
--         "subject": "数学", 
--         "grade": "80"
--     }, 
--     {
--         "name": "李四", 
--         "subject": "英语", 
--         "grade": "70"
--     }
-- ]

参考

 

出处:https://www.cnblogs.com/shanzhiming/p/15441472.html

标签:XML,语文,Name,--,查询,李四,SQL,SELECT
来源: https://www.cnblogs.com/mq0036/p/15665854.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有