简体   繁体   中英

XQuery exists check in select sql query

I have one sql table with xml column which holds the value like below xml

<Security xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Dacl>
    <ACEInformation>
      <UserName>Authenticated Users</UserName>
      <Access>Allow</Access>
      <IsInherited>false</IsInherited>
      <ApplyTo>This object only</ApplyTo>
      <Permission>List Contents</Permission>
      <Permission>Read All Properties</Permission>
      <Permission>Read Permissions</Permission>
    </ACEInformation>
    <ACEInformation>
      <UserName>Administrator</UserName>
      <Access>Allow</Access>
      <IsInherited>false</IsInherited>
      <ApplyTo>This object only</ApplyTo>
      <Permission>Read All Properties</Permission>
      <Permission>Delete</Permission>
    </ACEInformation>
    <ACEInformation>
      <UserName>Admin2</UserName>
      <Access>Allow</Access>
      <IsInherited>false</IsInherited>
      <ApplyTo>This object only</ApplyTo>
      <Permission>Read All Properties</Permission>
      <Permission>Delete</Permission>
    </ACEInformation>
    <ACEInformation>
      <UserName>Admin2</UserName>
      <Access>Deny</Access>
      <IsInherited>false</IsInherited>
      <ApplyTo>This object only</ApplyTo>
      <Permission>Read All Properties</Permission>
      <Permission>Delete</Permission>
    </ACEInformation>
  </Dacl>
</Security>

Here my need is, I have to query all UserName values who are having values Access: Allow and Permission: Delete . For that, I am using following XQuery.

select (
       select A.X.value('(UserName/text())[1]', 'nvarchar(max)')+';'
       from T.xmlColumn.nodes('/Security/Dacl/ACEInformation[Access = "Allow" and Permission = "Delete"]') as A(X)
       for xml path(''), type
       ).value('text()[1]', 'nvarchar(max)')
from myTable as T

It returns the value : Administrator;Admin2 for above xml. the query is working fine..

But here, I expect the result only one entry Administrator not Admin2 .. because Admin2 has both Access:Allow and Access: Deny values in two different ACEInformation node..

In that case, I have to exclude Admin2 from result, even though it has the Access:Allow .

Can you any one give me the xquery for this case?

with cte as (
    select
        A.X.value('(UserName/text())[1]', 'nvarchar(max)') as UserName,
        A.X.value('(Access/text())[1]', 'nvarchar(max)') as Access
    from myTable as T
        outer apply T.xmlColumn.nodes('/Security/Dacl/ACEInformation[Permission = "Delete"]') as A(X)
)
select *
from cte as c1
where
    c1.Access = 'Allow' and
    not exists (select * from cte as c2 where c2.UserName = c1.UserName and c2.Access = 'Deny')

sql fiddle demo

update

This one will give you desired result.

with cte as (
    select
        T.ID,
        A.X.value('(UserName/text())[1]', 'nvarchar(max)') as UserName,
        A.X.value('(Access/text())[1]', 'nvarchar(max)') as Access
    from myTable as T
        outer apply T.xmlColumn.nodes('/Security/Dacl/ACEInformation[Permission = "Delete"]') as A(X)
)
select
    T.ID,
    stuff(
        (
            select ',' + c1.UserName
            from cte as c1
            where
              c1.ID = T.ID and c1.Access = 'Allow' and
              not exists (select * from cte as c2 where c2.ID = T.ID and c2.UserName = c1.UserName and c2.Access = 'Deny')
            for xml path(''), type
        ).value('.', 'nvarchar(max)')
    ,1,1,'')
from myTable as T

sql fiddle demo

I think it's possible to do this with pure XQuery, try to add this later.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM