在mssql中使用sql输出列作为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

我有一个返回xml的存储过程

样本电话是

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)