在mssql中使用sql输出列作为xml输出标记的优雅方式是什么?
我有一个返回xml的存储过程 样本电话是在mssql中使用sql输出列作为xml输出标记的优雅方式是什么?,sql,sql-server,xml,Sql,Sql Server,Xml,我有一个返回xml的存储过程 样本电话是 get_organization_user_export_data_permission_procedure @organizationId = '64483342-af49-4a04-b25d-ce7346cb5375' , @userId = '5324B48E-B560-4345-B290-12CC72D722FA' 样本输出为 <root> <all>false</all> <an
get_organization_user_export_data_permission_procedure
@organizationId = '64483342-af49-4a04-b25d-ce7346cb5375'
, @userId = '5324B48E-B560-4345-B290-12CC72D722FA'
样本输出为
<root>
<all>false</all>
<analytics>false</analytics>
<none>true</none>
</root>
返回
name permission found
none 0 1
all 1 0
analytics 2 0
name permission found
none 0 1
all 1 0
analytics 2 0
问题是我在存储过程中硬编码了元素标记名。
这是一个存储过程,它显示了我对每个可能的元素标记名都有一个单独的子查询
CREATE PROCEDURE [dbo].[get_organization_user_export_data_permission_procedure]
(
@organizationId uniqueidentifier
, @userId uniqueidentifier
)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
if (
select count(*) from [OrganizationUserDataPermission]
where organizationId = @organizationId
and userId = @userId
) = 0 begin
insert into [OrganizationUserDataPermission] ( id, organizationId, userId, permissionType, createDateTime )
select newId(),@organizationId organizationId, @userId userId, 0 permissionType, getDate()
end
declare @result XML
set @result = (
select '',
(
select case true when 0 then 'false' else 'true' end 'all' from (
select lower([type]) name,
value permission,
count(permissionType) true
from [GroupExportRestrictionTypeConstants_RestrictionType_view] export
left join (
select permissionType from [OrganizationUserDataPermission]
where organizationId = @organizationId
and userId = @userId ) permission
on export.value = permission.permissionType
where value = 1
group by [type], value
) [all]
) 'all'
, (
select case true when 0 then 'false' else 'true' end 'analytics' from (
select lower([type]) name,
value permission,
count(permissionType) true
from [GroupExportRestrictionTypeConstants_RestrictionType_view] export
left join (
select permissionType from [OrganizationUserDataPermission]
where organizationId = @organizationId
and userId = @userId ) permission
on export.value = permission.permissionType
where value = 2
group by [type], value
) [analytics]
) 'analytics'
, (
select case true when 0 then 'false' else 'true' end 'none' from (
select lower([type]) name,
value permission,
count(permissionType) true
from [GroupExportRestrictionTypeConstants_RestrictionType_view] export
left join (
select permissionType from [OrganizationUserDataPermission]
where organizationId = @organizationId
and userId = @userId ) permission
on export.value = permission.permissionType
where value = 0
group by [type], value
) [none]
) 'none'
for xml path(''), root('root')
)
select @result result
END
GO
目前,如果引入了另一个导出许可,我必须更改存储过程和视图。有没有优雅的方式。。。我说的优雅是指不使用动态sql。。。要在事先不知道权限的情况下生成相同的xml结果
支持模式
景色。。。命名使其与相关的c代码结合
CREATE VIEW [dbo].[GroupExportRestrictionTypeConstants_RestrictionType_view] AS
select 'All' [type], 1 [value]
union
select 'Analytics' [type], 2 [value]
union
select 'None' [type], 0 [value]
没有外键的桌子
CREATE TABLE [dbo].[OrganizationUserDataPermission](
[Id] [uniqueidentifier] NOT NULL,
[OrganizationId] [uniqueidentifier] NOT NULL,
[UserId] [uniqueidentifier] NOT NULL,
[PermissionType] [int] NOT NULL,
[CreateDateTime] [datetime] NOT NULL,
CONSTRAINT [PK_OrganizationUserDataPermission] PRIMARY KEY CLUSTERED
(
[Id] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
-一些样本数据
insert into [OrganizationUserDataPermission] ( id, organizationId, userId, permissionType, createDateTime )
select newId(),'64483342-af49-4a04-b25d-ce7346cb5375' organizationId, '5324B48E-B560-4345-B290-12CC72D722FA' userId, 1 permissionType, getDate()
有一件事我可以肯定地告诉你:这太复杂了 您可以轻松更改的一件事是将相同的sub select转换为一个CTE 但是——如果我理解正确的话——这样做会容易得多: 你告诉我 返回
name permission found
none 0 1
all 1 0
analytics 2 0
name permission found
none 0 1
all 1 0
analytics 2 0
假设返回值正常,则可以使用条件聚合:
一个模拟表,用于模拟上面的最终结果
DECLARE @tbl TABLE(name VARCHAR(100),permission INT,found BIT);
INSERT INTO @tbl VALUES
('none',0,1)
,('all',1,0)
,('analytics',2,0);
-询问
SELECT MAX(CASE WHEN(name='all') THEN CASE WHEN found=1 THEN 'true' ELSE 'false' END END) AS [all]
,MAX(CASE WHEN(name='analytics') THEN CASE WHEN found=1 THEN 'true' ELSE 'false' END END) AS [analytics]
,MAX(CASE WHEN(name='none') THEN CASE WHEN found=1 THEN 'true' ELSE 'false' END END) AS [none]
FROM @tbl
GROUP BY name
FOR XML PATH(''),ROOT('root');
结果
<root>
<all>false</all>
<analytics>false</analytics>
<none>true</none>
</root>
我将此作为另一个答案,因为它采用了完全不同的方法: 通常,不可能动态定义列别名。XML中的元素名取自列名,因此这里也适用 但是 从技术上讲,XML是一个字符串。通常我不建议在字符串基础上构建XML,但是-只要您确定元素的名称不会包含任何禁止的字符,这是一个解决方案,它确实是从给定的数据中提取的:
DECLARE @tbl TABLE(name VARCHAR(100),permission INT,found BIT);
INSERT INTO @tbl VALUES
('none',0,1)
,('all',1,0)
,('analytics',2,0);
SELECT CAST('<root>'
+ (
SELECT '<' + name + '>' + CASE WHEN found=1 THEN 'true' ELSE 'false' END + '</' + name + '>'
FROM @tbl
FOR XML PATH(''),TYPE
).value('.','varchar(max)')
+'</root>' AS XML)
XML标记和权限之间是否存在关系?不能将标记存储在带有权限链接的表中吗?您可以共享表和视图定义吗?添加了支持架构和示例数据@underbooks,比我的更简单,并且仍然有硬编码元素名称的麻烦。您的代码比我编写的@Shnugo:-谢谢@KeithJohnHutchison一个刚刚浮现在我脑海中的问题:为什么不使用FalseTreal?这更容易创建,阅读端可以依赖元素名称。在读取端事先不知道列的情况下,处理记录集或XML是非常笨拙的。。。这就是没有技巧就不可能实现的原因……我曾经用这种方式编写xml,我更喜欢这种方式,但是,当前的xml结构是为了替换为json而设计的。xml映射到{all:true,analytics:false,none:false}。我在REST c asp服务器中使用了它。我将json发送到mssql存储过程中,并将其转换为xml。我返回转换为json的xml,并通过rest服务器返回。我使用Newtonsoft来进行转换。这里的关键决定因素是发送到REST服务器和从REST服务器返回的json。这就是xml采用这种结构的原因。
DECLARE @tbl TABLE(name VARCHAR(100),permission INT,found BIT);
INSERT INTO @tbl VALUES
('none',0,1)
,('all',1,0)
,('analytics',2,0);
SELECT CAST('<root>'
+ (
SELECT '<' + name + '>' + CASE WHEN found=1 THEN 'true' ELSE 'false' END + '</' + name + '>'
FROM @tbl
FOR XML PATH(''),TYPE
).value('.','varchar(max)')
+'</root>' AS XML)