Reputation: 420
Suppose I have following table RIGHTS with data:
ID NAME OWNER_ID ACL_ID ACL_NAME
--------------------------------------------------
100 Entity_1 1 1 g1
100 Entity_1 2 2 g2
100 Entity_1 3 3 g3
200 Entity_2 1 1 g1
200 Entity_2 2 2 g2
300 Entity_3 1 1 g1
300 Entity_3 2 2 g2
300 Entity_3 4 NULL NULL
400 Entity_4 1 1 g1
400 Entity_4 2 2 g2
400 Entity_4 3 3 g3
400 Entity_4 4 NULL NULL
500 Entity_5 4 NULL NULL
500 Entity_5 5 NULL NULL
500 Entity_5 6 NULL NULL
600 Entity_6 NULL NULL NULL
How to select all (ID, NAME) records for which there is no even single ACL_ID=NULL row except those rows with OWNER_ID=NULL. In this particular example I want to select 3 rows:
(100, Entity_1) - because all 3 rows with ACL_ID != NULL (1, 2, 3)
(200, Entity_2) - because all 2 rows with ACL_ID != NULL (1, 2)
(600, Entity_6) - because OWNER_ID=NULL
For now I use SQL Server, but I want it works on Oracle as well if it possible.
UPDATE I apologize I had to mention that this table data is just a result of a query with joins, so it has to be taken into account:
SELECT DISTINCT
EMPLOYEE.ID
,EMPLOYEE.NAME
, OWNERS.OWNER_ID as OWNER_ID
, GROUPS.GROUP_ID as ACL_ID
, GROUPS.NAME as ACL_NAME
from EMPLOYEE
inner join ENTITIES on ENTITIES.ENTITY_ID = ID
left outer join OWNERS on (OWNERS.ENTITY_ID = ID and OWNERS.OWNER_ID != 123)
left outer join GROUPS on OWNERS.OWNER_ID = GROUPS.GROUP_ID
where
ENTITIES.STATUS != 'D'
Upvotes: 0
Views: 1951
Reputation: 4538
Using simple filters in where clause:
with tab(ID,NAME,OWNER_ID,ACL_ID,ACL_NAME) as (
select 100, 'Entity_1', 1,1, 'g1' from dual union all
select 100, 'Entity_1', 2,2, 'g2' from dual union all
select 100, 'Entity_1', 3,3, 'g3' from dual union all
select 200, 'Entity_2', 1,1, 'g1' from dual union all
select 200, 'Entity_2', 2,2, 'g2' from dual union all
select 300, 'Entity_3', 1,1, 'g1' from dual union all
select 300, 'Entity_3', 2,2, 'g2' from dual union all
select 300, 'Entity_3', 4,NULL, NULL from dual union all
select 400, 'Entity_4', 1,1, 'g1' from dual union all
select 400, 'Entity_4', 2,2, 'g2' from dual union all
select 400, 'Entity_4', 3,3, 'g3' from dual union all
select 400, 'Entity_4', 4,NULL,NULL from dual union all
select 500, 'Entity_5', 4,NULL,NULL from dual union all
select 500, 'Entity_5', 5,NULL,NULL from dual union all
select 500, 'Entity_5', 6,NULL,NULL from dual union all
select 600, 'Entity_6', NULL,NULL,NULL from dual)
--------------------------------
---End of data preparation here
--------------------------------
select a.id, a.name
from tab a
where ((a.ACL_ID is not null and a.ACL_NAME is not NULL) or a.OWNER_ID is null)
and not exists (select 'x'
from tab b
where b.id = a.id
and (b.ACL_ID is null or b.ACL_NAME is null)
and b.owner_id is not null)
group by a.id, a.name;
Output:
ID NAME
------------
200 Entity_2
100 Entity_1
600 Entity_6
But I still wonder, what would be you logic where there is data like :
ID NAME OWNER_ID ACL_ID ACL_NAME
--------------------------------------------------
600 Entity_1 null null null
600 Entity_1 2 null null
??????????
Upvotes: 0
Reputation: 2091
Here's my solution on Oracle.
SELECT DISTINCT
EMPLOYEE.ID
,EMPLOYEE.NAME
, OWNERS.OWNER_ID as OWNER_ID
, GROUPS.GROUP_ID as ACL_ID
, GROUPS.NAME as ACL_NAME
from EMPLOYEE
inner join ENTITIES on ENTITIES.ENTITY_ID = ID
left outer join OWNERS on (OWNERS.ENTITY_ID = ID and OWNERS.OWNER_ID != 123)
left outer join GROUPS on OWNERS.OWNER_ID = GROUPS.GROUP_ID
where ENTITIES.STATUS != 'D'
and EMPLOYEE.ID not in (select id from EMPLOYEE
where GROUPS.GROUP_ID is null
and OWNERS.OWNER_ID is not null);
You simply need to append the inner subquery from my earlier answer and you will get your solution.
Upvotes: 0
Reputation: 21757
Try this:
select s.id, s.name
from
(select id,name,max(coalesce(owner_id,-1)) owner_id, min(coalesce(acl_id,-1)) acl_id
from yourtable
group by id,name) as s
where s.owner_id = -1
or (s.owner_id > -1 and s.acl_id > -1)
We use COALESCE
to default null values to -1 (assuming the columns are integers), and then get the minimum values of owner_id
and acl_id
per unique id-name
combination. If the maximum value of owner_id
is -1, then the owner column is null. Likewise, if minimum value of acl_id
is -1, then at least one null valued row exists. Based on these 2 conditions, we filter the list to get the required id-name
pairs. Note that in this case, I simply chose -1 as the default value because I assume you don't use negative numbers as IDs. If you do, you can choose a suitable, "impossible" value as the default for the COALESCE
function.
This should work on SQL Server and Oracle.
Upvotes: 1