IF NOT EXISTS in Oracle - sql

I am new in Oracle, need some help to SQL Server's IF NOT EXISTS equivalent in Oracle.
I need to find the max RoleID from Role table based on entity number if a particular role does not exists. I have created below query but its failing (it should return null if an entity has that particular role and should return 1 if an entity has no role, its returning 1 in both cases) if an entity does not have any role.
Code:-
SELECT NVL(MAX(role_id), 0) + 1 AS RoleID from roles WHERE entity_no = '000001'
AND
NOT EXISTS (
SELECT 1
FROM roles
WHERE entity_no = '000001' AND name = 'Survey'
)
I need 1 as RoleID if an entity does not have any role(s) but it should return null for the entity having that particular role('Survey') else return max RoleID with increment, TIA.

Would this do? Read comments within code.
entity_no = 00001 has Survey, so query should return NULL
entity_no = 00002 doesn't have Survey, so query should return 1
SQL> with
2 roles (role_id, entity_no, name) as
3 -- sample data
4 (select 1, '00001', 'Survey' from dual union all
5 select 2, '00002', 'xxx' from dual
6 ),
7 temp as
8 -- does ENITITY_NO has role for NAME = Survey? If so, CNT = 1; else, CNT = 0
9 (select entity_no,
10 sum(case when name = 'Survey' then 1 else 0 end) cnt
11 from roles
12 group by entity_no
13 )
14 -- finally, check CNT value and return the result
15 select case when t.cnt = 0 then 1 else null end as role_id
16 from roles r join temp t on t.entity_no = r.entity_no
17 where r.entity_no = '&par_entity_no';
Enter value for par_entity_no: 00001
ROLE_ID
----------
SQL> /
Enter value for par_entity_no: 00002
ROLE_ID
----------
1
SQL>

Related

how to select SQL , ownerID 7 first then all from table USER ?(with OR condition )

The USER table structure is
id owneeId delete shop
1 12 null 1
2 13 1 0
3 12 null 1
4 7 1 1
5 7 null 1
6 13 null 1
7 16 null 1
8 17 null 1
Now I am getting the result of ( query given below )
select * from users WHERE ownerId in ('12', '13') and delete is null or
ownerId not IN ('12','13') and shop=1 and delete is null
I will get all users with owner id 12 or 13 (with delete null) + all users with owner id not 12 or 13 + shop =1 and dlete is null.
Desired result
I will give another ownerID 7.
I need to get all the users with owner id 7 first, that means; from above table ,
all users with owner id 7 and shop =1 first ...only then all users with owner id 12 or 13 (with delete null) + all users with owner id not 12 or 13 + shop =1 and dlete is null
query will be something like
I need to add "select * from users where ownerId 7 first and shop 1 and delete null" to the query(above one, this one below- both same query)
select * from users WHERE ownerId in ('12', '13') and delete is null or
ownerId not IN ('12','13') and shop=1 and delete is null
** (PS)EDIT FOR BETTER CLARITY**
My current result is
id owneeId delete shop
1 12 null 1
2 12 null 1
2 7 null 1
2 13 null 1
2 16 null 1
2 17 null 1
what I need is- desired result
id owneeId delete shop
2 7 null 1
1 12 null 1
2 12 null 1
2 13 null 1
2 16 null 1
2 17 null 1
all user with ownerid 7 first , then the rest...( I am getting this result as an array of objects in node , in sql as table)
PS : Owner id can be any number, in this case it is 7. It can be 912, 989,89009,...etc
If you wish to just combine the 2 results, you can simply use union like below:
(
select *
from users
where ownerId = 7 and shop = 1
)
union
(
select *
from users
WHERE (ownerId in ('12', '13') and `delete` is null) or
(ownerId not IN ('12','13') and shop = 1 and `delete` is null)
)
Note: Using delete as one of the column names is not recommended since delete is a keyword in itself. You can rather go for deleted_at if it's a timestamp etc.

SQL Select - "If that user-group combination has an attribute of X, don't return any records with that user-group combination"

I'm trying to write a SQL statement for auditing purposes. Basically, the purpose of it can be summarized as "Return all user-group combinations where the user is not currently Approved for ANY ROLES in that group".
For example, take the following records:
ID UserId GroupId Role Status
----------------------------------------
1 1 10 User Approved
2 1 10 Editor Denied
3 1 15 User Denied
4 2 20 User Pending
5 2 20 Editor Denied
6 2 20 Admin Denied
7 2 25 User Approved
As you can see, there are 4 basic User-Group combos here:
User 1 applied to be a User and Editor in Group10 and was denied as Editor, but Approved as User. We do not want any of this user's records to be returned, as he was approved for a role.
User 1 applied to be a User in Group15 and was Denied. This record should be returned as he has no membership in Group 15.
User 2 applied to be a User, Editor, and Admin in Group20. He was denied for Editor and Admin, but is still pending User privileges. His record should be returned as he currently has no membership.
User 2 applied to be a User in Group25 and he was Approved. His record shouldn't be returned - he is a member.
I've tried to do this via an INNER JOIN of the group on itself on UserId and GroupId, but that doesn't work as Records are created where ID 1 joins ID 1 and simple logic (return everything that doesn't have any Status=Approved) doesn't work because both statuses are the same.
I've got a feeling that a NOT could be useful, but I can't figure out a way to get all User-Group combos that have a value of Approved (so I can then Select NOT it).
The correct query should return records corresponding to ID 3, and ID 4-6 (any of 4/5/6, or all of them). Any guidance would be appreciated - thanks!
You can use this.
DECLARE #Table TABLE (ID INT, UserId INT, GroupId INT, Role VARCHAR(10), Status VARCHAR(10))
INSERT INTO #Table VALUES
(1 , 1, 10 ,'User','Approved'),
(2 , 1, 10 ,'Editor','Denied'),
(3 , 1, 15 ,'User','Denied'),
(4 , 2, 20 ,'User','Pending'),
(5 , 2, 20 ,'Editor','Denied'),
(6 , 2, 20 ,'Admin','Denied'),
(7 , 2, 25 ,'User','Approved')
SELECT * FROM #Table T1
WHERE NOT EXISTS
(SELECT * FROM #Table T2
WHERE T1.UserId = T2.UserID
and T1.GroupId = T2.GroupId
AND T2.Status ='Approved')
Result:
ID UserId GroupId Role Status
----------- ----------- ----------- ---------- ----------
3 1 15 User Denied
4 2 20 User Pending
5 2 20 Editor Denied
6 2 20 Admin Denied
Aggregate your table by the UserId and GroupId, and return only those users who never have a single record with an approved status in a particular group:
SELECT UserId, GroupId
FROM yourTable
GROUP BY UserId, GroupId
HAVING SUM(CASE WHEN Status = 'Approved' THEN 1 ELSE 0 END) = 0;
If you instead want to return all the users' matching records, then we can modify the above by adding a join:
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT UserId, GroupId
FROM yourTable
GROUP BY UserId, GroupId
HAVING SUM(CASE WHEN Status = 'Approved' THEN 1 ELSE 0 END) = 0
) t2
ON t1.UserId = t2.UserId AND
t1.GroupId = t2.GroupId;

Handle Duplicate Record in Oracle SQL

I have a table with records like below
NAME STATUS xml_configparamdb_id xml_configuration_id
STO INACTIVE 1 1
STO ACTIVE 1 2
BOS ACTIVE 1 3
KYC INACTIVE 1 4
KYC INACTIVE 1 5
ACC ACTIVE 1 6
ACC ACTIVE 1 7
Now result I am interested in is as follows:
NAME STATUS xml_configparamdb_id xml_configuration_id
STO ACTIVE 1 2
BOS ACTIVE 1 3
KYC INACTIVE 1 4
ACC ACTIVE 1 6
That is, I want to select data on basis of STATUS .
Condition -- If STATUS is ACTIVE for both case of same Parameter - select first coming ACTIVE
Condition -- If STATUS is INACTIVE for both case of same Parameter - select first coming INACTIVE
Condition -- If STATUS is ACTIVE & INACTIVE for same Parameter - select ACTIVE
Now I used below query to populate result like above without using PRIMARY KEY Column (xml_configuration_id)
CURSOR cCnfgTypData IS
select distinct name, description, STATUS
from stg_xml_cpdb_configuration
WHERE process_exec_num = 1
AND STATUS = 'ACTIVE'
UNION ALL
select name, description, STATUS
from stg_xml_cpdb_configuration t
where process_exec_num = 1
and STATUS = 'INACTIVE'
and not exists (select * from stg_xml_cpdb_configuration
where name = t.name
and STATUS = 'ACTIVE') order by name, description;
It's showing fine data. But when I execute using PRIMARY KEY Column (xml_configuration_id) like below it's displaying all data without satisfying condition
select distinct name, description, STATUS, xml_configparamdb_id, xml_configuration_id
from stg_xml_cpdb_configuration
WHERE process_exec_num = 1
AND STATUS = 'ACTIVE'
UNION ALL
select name, description, STATUS, xml_configparamdb_id, xml_configuration_id
from stg_xml_cpdb_configuration t
where process_exec_num = 1
and STATUS = 'INACTIVE'
and not exists (select * from stg_xml_cpdb_configuration
where name = t.name
and STATUS = 'ACTIVE') order by name, description;
Use analytic function ROW_NUMBER.
SQL> SELECT name,
2 status,
3 xml_configparamdb_id,
4 xml_configuration_id
5 FROM
6 ( SELECT t.*, row_number() over (partition BY name order by status) rn FROM t
7 )
8 WHERE rn = 1
9 ORDER BY xml_configuration_id
10 /
NAM STATUS XML_CONFIGPARAMDB_ID XML_CONFIGURATION_ID
--- -------- -------------------- --------------------
STO ACTIVE 1 2
BOS ACTIVE 1 3
KYC INACTIVE 1 4
ACC ACTIVE 1 6
SQL>

An update with multiple conditions. SQL 2008

I have a table...
ProjectID UserID RoleID
101 1 10
101 2 10
102 2 10
102 3 10
103 1 10
Currently there is only one type of Role, role '10', but I'm wanting to add a new role, role '11', which will act as a lead. So any project that has a user with the role of '10', should have a lead. The user chosen to be lead will be based on a priorty list, in this example we'll say the order is 1, 2, 3.
Expected result...
ProjectID UserID RoleID
101 1 11
101 2 10
102 2 11
102 3 10
103 1 11
You can figure out which user has the highest priority by using row_number(). SQL Server let's you do this in an updatable CTE, so the query looks like this:
with toupdate as (
select t.*,
row_number() over (partition by projectid
order by (case when userid = 1 then 1
when userid = 2 then 2
when userid = 3 then 3
else 4
end
)
) as PriorityForLead
from table t
)
update toupdate
set RoleId = 11
where PriorityForLead = 1;

SQL to remove specific rows from select

Ive got a table:
UserA UserB UserBB UserAA
for example:
1 2 2 1
1 3 3 1
2 1 1 2
2 4 4 2
2 5 5 2
5 2 2 5
What I want to achieve is to remove rows (duplicates) like to only leave rows as in example:
1 2 2 1
1 3 3 1
2 4 4 2
2 5 5 2
2 1 1 2 -> deleted because there is already 1 2 2 1
5 2 2 5 -> deleted because there is already 2 5 5 2
How to write such a query ?
Thanks for help
-- Find Duplicate Rows
SELECT MAX(ID) as ID, CustName, Pincode FROM #Customers
GROUP BY CustName, Pincode
HAVING COUNT(*) > 1
-- Delete Duplicate Rows
DELETE FROM #Customers
WHERE ID IN
( SELECT MAX(ID) FROM #Customers
GROUP BY CustName, Pincode
HAVING COUNT(*) > 1)
Taken from MSDN. :
http://archive.msdn.microsoft.com/SQLExamples/Wiki/View.aspx?title=DuplicateRows
Let me know if you are unable to figure it out from that code.
This may be a little bit closer to your needs. :
DELETE FROM TABLE
WHERE USERA IN ( SELECT MAX(USERA) FROM TABLE
GROUP BY USERA, USERB, USERBB, USERAA HAVING COUNT(*) > 1)
The below also covers situations where UserA and UserB are equal between the two rows but UserAA and UserBB are switched and the reverse. Your question is a bit unclear about what exactly constitutes a duplicate. Hopefully this points you in the right direction at the very least though.
I would turn this into a SELECT statement first though and make sure that it is returning the rows that you think should be deleted and only those rows.
DELETE T1
FROM
My_Table T1
INNER JOIN My_Table T2 ON
(
T2.UserA = T1.UserA AND
T2.UserB = T1.UserB AND
T2.UserAA = T1.UserBB AND
T2.UserBB = T1.UserAA AND
T2.UserAA < T2.UserBB
) OR
(
T2.UserA = T1.UserB AND
T2.UserB = T1.UserA AND
T2.UserAA = T1.UserAA AND
T2.UserBB = T1.UserBB AND
T2.UserA < T2.UserB
) OR
(
T2.UserA = T1.UserB AND
T2.UserB = T1.UserA AND
T2.UserAA = T1.UserBB AND
T2.UserBB = T1.UserAA AND
T2.UserA < T2.UserB
)
It was Enough just to add:
Where UserA < UserB