Getting rid of the "where" clause if a value = 'ADMIN' - sql

So there is the main table (named Table1) and one of the columns in that table has a column called company name. and there's a another table called Account and in that table it has the usernames of people and the company name that user is associated with. so only the information in table1 associated with the user's company should be shown, unless if they're an admin.
I'm working on an APEX app on Oracle
I currently have a query that looks like this:
Select
SUPPLIER,
sum(NUMBER_OF_TICKETS) TICKETS,
round((sum(NUMBER_OF_TICKETS*AMOUNT_PAYABLE__FOREIGN_CUR)*.1),2) COMMISION,
round(sum(NUMBER_OF_TICKETS*AMOUNT_PAYABLE__FOREIGN_CUR),2) TOTAL_SALES,
round((sum(NUMBER_OF_TICKETS*AMOUNT_PAYABLE__FOREIGN_CUR)-(sum(NUMBER_OF_TICKETS*AMOUNT_PAYABLE__FOREIGN_CUR)*.1)),2) COMPANY_OWE,
CURRENCY
FROM TABLE1
WHERE
Supplier = (select COMPANYNAME from Account where lower(USERNAME)=lower(:APP_USER)) AND
PURCHASE_DATE_AND_TIME >= TO_DATE(:P2_START)
AND PURCHASE_DATE_AND_TIME < TO_DATE(:P2_END)+ 1
group by
SUPPLIER,
CURRENCY
I'm running into trouble with the "WHERE" function.
Because I basically want to have a if...then... (or a case statement in this case)
where
IF
((select COMPANYNAME from Account where lower(USERNAME)=lower(:APP_USER)) == 'COMPANY1' AND (select USERTYPE from Account where lower(USERNAME)=lower(:APP_USER)) == 'ADMIN')
THEN
show all the rows; aka, Supplier = (select COMPANYNAME from BBAccount where lower(USERNAME)=lower(:APP_USER)) in the query
Does anyone have any ideas on how to go about writing a query for this?
I tried doing
Case statement When statement Then NULL
It doesn't work
I tried drawing a diagram, let me know if this makes it more clear:
Diagram

As it is about Apex, I'd suggest you to create a function:
create or replace function f_is_admin_01 (par_app_user in varchar2)
return number
is
-- function returns 1 if PAR_APP_USER is admin; otherwise, it returns 0
l_usertype account.usertype%type;
begin
select a.usertype
into l_usertype
from account a
where lower(a.username) = lower(par_app_user);
return case when l_usertype = 'ADMIN' then 1
else 0
end;
exception
when no_data_found then
return 0;
end;
Now, you can use it in query as
select ...
from account a join table1 t on a.companyname = t.companyname
where (lower(a.username) = lower(:APP_USER) or f_is_admin_01 (:APP_USER) = 1)
and t.purchasedate ...
Such an approach (I mean, having a function) can be useful elsewhere; for example, if you want to show certain page region only to admins - you'd put
return f_is_admin_01(:APP_USER) = 1;
into region's "Server side condition" (its type would be "Function that returns Boolean").
See if it helps.

So there is the main table (named Table1) and one of the columns in that table has a column called company name. and there's a another table called Account and in that table it has the usernames of people and the company name that user is associated with. so only the information in table1 associated with the user's company should be shown, unless if they're an admin
I think that you could simply join - something like:
SELECT ...
FROM TABLE1 t
INNER JOIN ACCOUNTS a
ON lower(a.username) = lower(:APP_USER)
AND (a.companyname = t.companyname OR a.usertype = 'ADMIN')
WHERE
t.purchase_date_and_time >= TO_DATE(:P2_START)
AND t.purchase_date_and_time < TO_DATE(:P2_END) + 1
GROUP BY ...
The inner join on ACCOUNTS is there to implement the filtering logic: the user must either the user belongs to the same company, or have the admin type.

EXISTS(...) is your friend:
Select SUPPLIER
,sum(NUMBER_OF_TICKETS) TICKETS
,round((sum(NUMBER_OF_TICKETS*AMOUNT_PAYABLE__FOREIGN_CUR)*.1),2) COMMISION
,round(sum(NUMBER_OF_TICKETS*AMOUNT_PAYABLE__FOREIGN_CUR),2) TOTAL_SALES
,round((sum(NUMBER_OF_TICKETS*AMOUNT_PAYABLE__FOREIGN_CUR)
-(sum(NUMBER_OF_TICKETS*AMOUNT_PAYABLE__FOREIGN_CUR)*.1)),2) COMPANY_OWE
, CURRENCY
FROM TABLE1 t
WHERE EXISTS (
SELECT 1
from Account x
where x.Supplier = t.COMPANYNAME
AND lower(x.USERNAME) = lower(:APP_USER))
AND x.PURCHASE_DATE_AND_TIME >= TO_DATE(:P2_START)
AND x.PURCHASE_DATE_AND_TIME < TO_DATE(:P2_END)+ 1
)
group by SUPPLIER, CURRENCY
;

Related

How to give access and partial access to specifc Users in ORACLE database

I am trying to create a view in an Oracle database whereby if a USER is in the PLAYER field of the base table, only the rows of this player are outputted, but if a USER matches the MANAGER role of another base table, all rows of this first base table are outputted.
So far I have this which I'm not sure even works?
CREATE VIEW Player_view AS
SELECT (CASE WHEN USER IN PT.PLAYER THEN (SELECT * FROM PT WHERE USER = PT.PLAYER)
ELSE WHEN USER IN PM.MANAGER THEN (SELECT * FROM PT)
END
FROM Player_Table PT, Player_Managers PM
Otherwise, I have tried with grant permissions - however, how do I give grant permission to SELECT over just one row vs. all rows?
Probably something like the following should suffice
create view player_view as
select * from player_table
where player = user
union all
select * from player_table
where exists ( select 1 from player_manager where manager = user )
If the two are not mutually exclusive, then you could add a 'not exists' to the second query
create view player_view as
select * from player_table
where player = user
union all
select * from player_table
where exists ( select 1 from player_manager where manager = user )
and player != user

Oracle - Need advice on multiple counts, on table with large amounts of data

Table with large data, does anyone know how to optimize the count statement?
Eg: table Booking(id, email, mobile,....) (about 30 fields).
Function GetBookingCount(p_email, p_mobile) return number
Select count(id)
from Booking
Where email = p_email
or mobile = p_mobile
Function GetBookingStatus3Count(p_email, p_mobile) return number
Select count(id)
from Booking
Where (email = p_email or mobile = p_mobile)
and status = 3;
Final select:
Select GetBookingCount(email, mobile) as BookingCount
, GetBookingStatus3Count(email, mobile) as BookingStatus3Count
, ...
From Booking
where ....
solution1: Set the field column index what in where clause to count as email column, mobile, status column.
solution2: create a new table with few columns to count.
new table: Booking_Stats(id, email, mobile, status).
Thanks for any suggestion.
select count(*) count_all, count( case when status=3 then 1 else null end ) count_status_3
from Booking
where email = p_email and mobile = p_mobile
//NOTE: Query is written from head, not tested
You would consider creating an index on (email,mobile) or on (email,mobile,status) depending how many lines for given (email,mobile) you get and would you pay the cost of update of the index for status change (if allowed). In case of many updates of status for the same line, you might prefer indexing only (email,mobile) [read/write cost trade off].
Email is likely very discriminant (one value filters out most of the columns). If that is not the case, consider changing order to (mobile,email) if mobile column is better candidate.
It seems likely all those GetBookingBlahBlah() functions are not helpful and in fact quiet injurious to performance.
You haven't posted a complete set of requirements (what is meant by ...?), so it's difficult to be certain, but it seems likely that a solution along these lines would be more performative:
with bk as (
select *
from booking
where email = p_email
or mobile = p_mobile
)
select count(*) as BookingCount
, count(case when bk.status = 3 then 1 end) as BookingStatus3Count
, ...
from bk
The idea is to query the base table once, getting all the data necessary to calculate all the counts, and crunching the aggregates on the smallest result set possible.
An index on booking(email,mobile) might be useful but probably not. A better solution would be to have different queries for each of p_email and p_mobile, with single column indexes supporting each query.
The booking table should have an index on email, mobile and status. You should use this select:
WITH B1 AS
(
SELECT ID,
COUNT(ID) CNT1,
STATUS
FROM BOOKING
WHERE EMAIL = P_EMAIL
AND MOBILE = P_MOBILE
)
SELECT CNT1,
COUNT(ID) CNT2
FROM B1
WHERE STATUS = 3;

Select entry with only one entry in many to many relationship

Say I have a database table user_provider, that contains many to many relationship of user and provider table.
I want to get only those userId which is having only one provider
SELECT spr1.SU_URS_ID,count(spr1.SU_URS_ID)
FROM overstappen.spr_usr spr1
WHERE spr1.SU_URS_ID in ( select spr.SU_URS_ID
from overstappen.spr_usr spr
where spr.SU_SPR_ID =40)
GROUP BY spr1.SU_URS_ID;
Above query returns all users which is having SU_SPR_ID 40. And the total no of users with same userId in spr_usr table.
I only want to get user with count 1. i.e user with only one provider.
Thanks in advance.
Try this
SELECT spr1.SU_URS_ID, COUNT(spr1.SU_URS_ID)
FROM overstappen.spr_usr spr1
WHERE spr1.SU_URS_ID IN
(SELECT spr.SU_URS_ID
FROM overstappen.spr_usr spr WHERE spr.SU_SPR_ID =40)
GROUP BY spr1.SU_URS_ID
HAVING COUNT(spr1.SU_URS_ID) = 1
Try adding at the end of your query HAVING COUNT(spr1.SU_URS_ID) = 1:
SELECT spr1.SU_URS_ID,count(spr1.SU_URS_ID)
FROM overstappen.spr_usr spr1
WHERE spr1.SU_URS_ID in (
SELECT spr.SU_URS_ID
FROM overstappen.spr_usr spr
WHERE spr.SU_SPR_ID =40)
GROUP BY spr1.SU_URS_ID
HAVING COUNT(spr1.SU_URS_ID) = 1;

Find records that exists in one table but not another based on multiple columns

I have two tables, billing and weekly.
I need to find values that are in the billing table but not in the weekly table, but I need to base it off of more than one column.
I have a query that works for just one column:
SELECT * from billing
outer apply
(select * from weekly where billing.[email]= weekly.[email])a
where a.[email] is null
Sometimes in my data the email can change.
So I need to add something if the email doesn't match, check first and last name but do not know how to do this.
You could use the exists operator:
SELECT *
FROM billing
WHERE NOT EXISTS
(SELECT *
FROM weekly
WHERE billing.[email] = weekly.[email] OR
(billing.[firstName] = weekly.[firstName] AND
billing.[lastName] = weekly.[lastName]
)
)
You can use NOT EXISTS operator to exclude any records that match in weekly based on email OR first and last name.
SELECT bl.*
FROM billing bl
WHERE NOT EXISTS (
SELECT 1
FROM weekly wk
WHERE (bl.[email] = wk.[email]
OR (
bl.firstName = wk.firstName
AND bl.lastName = wk.lastName))
AND bl.lenderName <> wk.lenderName --added this check
)

How to get one common value from Database using UNION

2 records in above image are from Db, in above table Constraint are (SID and LINE_ITEM_ID),
SID and LINE_ITEM_ID both column are used to find a unique record.
My issues :
I am looking for a query it should fetch the recored from DB depending on conditions
if i search for PART_NUMBER = 'PAU43-IMB-P6'
1. it should fetch one record from DB if search for PART_NUMBER = 'PAU43-IMB-P6', no mater to which SID that item belong to if there is only one recored either under SID =1 or SID = 2.
2. it should fetch one record which is under SID = 2 only, from DB on search for PART_NUMBER = 'PAU43-IMB-P6', if there are 2 items one in SID=1 and other in SID=2.
i am looking for a query which will search for a given part_number depending on Both SID 1 and 2, and it should return value under SID =2 and it can return value under SID=1 only if the there are no records under SID=2 (query has to withstand a load of Million record search).
Thank you
Select *
from Table
where SID||LINE_ITEM_ID = (
select Max(SID)||Max(LINE_ITEM_ID)
from table
where PART_NUMBER = 'PAU43-IMB-P6'
);
If I understand correctly, for each considered LINE_ITEM_ID you want to return only the one with the largest value for SID. This is a common requirement and, as with most things in SQL, can be written in many different ways; the best performing will depend on many factors, not least of which is the SQL product you are using.
Here's one possible approach:
SELECT DISTINCT * -- use a column list
FROM YourTable AS T1
INNER JOIN (
SELECT T2.LINE_ITEM_ID,
MAX(T2.SID) AS max_SID
FROM YourTable AS T2
GROUP
BY T2.LINE_ITEM_ID
) AS DT1 (LINE_ITEM_ID, max_SID)
ON T1.LINE_ITEM_ID = DT1.LINE_ITEM_ID
AND T1.SID = DT1.max_SID;
That said, I don't recall seeing one that relies on the UNION relational operator. You could easily rewrite the above using the INTERSECT relational operator but it would be more verbose.
Well in my case it worked something like this:
select LINE_ITEM_ID,SID,price_1,part_number from (
(select LINE_ITEM_ID,SID,price_1,part_number from Table where SID = 2)
UNION
(select LINE_ITEM_ID,SID,price_1,part_number from Table SID = 1 and line_item_id NOT IN (select LINE_ITEM_ID,SID,price_1,part_number from Table SID = 2)))
This query solved my issue..........