Don't show query results if they appear in the other query - sql

In my application each manager has a work pattern (for example Monday-Friday). But I also have a table "pattern_changes" where they can insert data if they cannot be present at work.
With the first query I can show who is available today, according to the pattern assigned to them:
SELECT distinct gu.first_name || ' ' || gu.last_name
FROM patterns pa JOIN fmanager_pattern fp
ON pa.id = fp.pattern_id
JOIN fmanagers fm
ON fm.id = fp.fmanager_id
JOIN gen_users gu
ON gu.user_id = fm.user_id
WHERE (TO_CHAR(pa.start_dt, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') LIKE TO_CHAR(sysdate, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') AND pa.start_dt < sysdate and pa.end_dt > sysdate)
OR (TO_CHAR(pa.end_dt, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') LIKE TO_CHAR(sysdate, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') AND pa.start_dt < sysdate and pa.end_dt > sysdate)
OR TO_CHAR(sysdate, 'D') BETWEEN TO_CHAR(pa.start_dt, 'D') AND TO_CHAR(pa.end_dt, 'D') AND pa.start_dt < sysdate and pa.end_dt > sysdate
OR TO_CHAR(sysdate, 'D')+7 BETWEEN TO_CHAR(pa.start_dt, 'D') AND TO_CHAR(pa.start_dt, 'D')+7 AND pa.start_dt < sysdate and pa.end_dt > sysdate
In the second query I can show who is not available today, according to the pattern_changes table.
SELECT fm.id, gu.first_name || ' ' || gu.last_name
FROM fmanagers fm JOIN pattern_changes pc
ON pc.fmanagers_id = fm.id
JOIN gen_users gu
ON gu.user_id = fm.user_id
WHERE pc.change_dt < sysdate and pc.end_dt > sysdate
OR pc.change_dt = to_char(sysdate)
OR pc.end_dt = to_char(sysdate))
For example, the first query returns: ADAM and EVA
The second query returns ADAM
So I just want to see EVA as a result.
I tried to do it with NOT IN or NOT EXISTS but neither of them work.
Can anybody help?
Thank you in advance

Related

how to use double group by and sum statements together in oracle

I am trying to use query below but it is giving an error
SELECT s.LOCAL_CODE,substr(p.ACCOUNT_CREDIT,-3),(p.SUMMA/100) as profit
FROM OPERATIONS s INNER JOIN LEADS p ON s.PAY_ID = p.PAY_ID
WHERE s.date_paid >= TO_DATE('03.12.2019', 'DD.MM.YYYY')
AND s.date_paid < TO_DATE('03.12.2019', 'DD.MM.YYYY') + INTERVAL '1' DAY
AND state = 'T'
AND s.filial_code = '006789'
AND SUBSTR(p.ACCOUNT_CREDIT, 1, 5) = '765294'
GROUP BY s.LOCAL_CODE,substr(p.ACCOUNT_CREDIT,-3);
If LEADS.SUMMA has expected value then you don't need Group By clause, else if you use Group By then all not grouped fields can be used only as arguments of aggregate functions:
SELECT s.LOCAL_CODE
, Substr(p.ACCOUNT_CREDIT, -3)
, Sum(p.SUMMA)/100 as profit
FROM OPERATIONS s
INNER JOIN LEADS p ON s.PAY_ID = p.PAY_ID
WHERE s.date_paid >= TO_DATE('03.12.2019', 'DD.MM.YYYY')
AND s.date_paid < TO_DATE('03.12.2019', 'DD.MM.YYYY') + INTERVAL '1' DAY
AND state = 'T'
AND s.filial_code = '006789'
AND SUBSTR(p.ACCOUNT_CREDIT, 1, 5) = '765294'
GROUP BY s.LOCAL_CODE
, substr(p.ACCOUNT_CREDIT, -3);

How to make Select Statement Faster in Oracle

I wrote query to find sum of money in a given period with one filial and it is working fast:
SELECT FILIAL_CODE,
sum(sum_eqv)/100 AS summa
FROM table
WHERE substr(acc,1,5) = '65434'
and cast(substr(acc,18,3) as integer) >= 600
and cast(substr(account_co,18,3) as integer)<=607
AND o_day >= to_date('01.12.2019', 'DD.MM.YYYY')
and oday < to_date('08.12.2019', 'DD.MM.YYYY')+ INTERVAL '1' DAY
AND FILIAL_CODE = '001234'
Above query is working fine. But when I want to use it multiple filials it is becoming more complex.
Below query is needs to be fixed.
SELECT FILIAL_CODE,
sum(sum_eqv)/100 AS summa
FROM table
WHERE substr(acc,1,5) = '65434'
and cast(substr(acc,18,3) as integer) >= 600
and cast(substr(account_co,18,3) as integer)<=607
AND o_day >= to_date('01.12.2019', 'DD.MM.YYYY')
and oday < to_date('08.12.2019', 'DD.MM.YYYY')+ INTERVAL '1' DAY
AND FILIAL_CODE in (select code from city where region = '26')
group by FILIAL_CODE;
This query runs long. How can I maximize this statement. Any Help is appreciated!
Try JOIN instead of IN, such as:
SELECT t.filial_code, SUM (sum_eqv) / 100 AS summa
FROM your_table t JOIN city c ON c.code = t.filial_code
WHERE SUBSTR (t.acc, 1, 5) = '65434'
AND CAST (SUBSTR (t.acc, 18, 3) AS INTEGER) >= 600
AND CAST (SUBSTR (t.account_co, 18, 3) AS INTEGER) <= 607
AND t.o_day >= TO_DATE ('01.12.2019', 'DD.MM.YYYY')
AND t.oday < TO_DATE ('08.12.2019', 'DD.MM.YYYY') + INTERVAL '1' DAY
AND c.region = '26'
GROUP BY t.filial_code;
It would probably help if city.code and table.filial_code were indexed.

How to limit return results

My query returns duplicate rows and I want to return only one row.
select papf.Full_Name,
papf.Employee_number,
papf.DatE_OF_BIRTH,
peef.last_update_date
/*,
petf1.ELEMENT_NAME as MedicalSchemeName*/
from per_all_people_f papf
,per_all_assignments_f paaf
,PAY_ELEMENT_ENTRIES_F peef
,pay_element_types_f petf
--,fnd_user fnu
where (papf.Employee_number) not in
(select
papf1.Employee_number
from per_all_people_f papfinner
,per_all_assignments_f paafinner
,PAY_ELEMENT_ENTRIES_F peefinner
,pay_element_types_f petfinner
where paafinner.person_id = papfinner.person_id
and peefinner.assignment_id = paafinner.assignment_id
and peefinner.element_type_id = petfinner.element_type_id
and upper(petf1.ELEMENT_NAME) like '%Condition%'
and SYSDATE BETWEEN papfinner.EFFECTIVE_START_DATE AND papfinner.EFFECTIVE_END_DATE
and SYSDATE BETWEEN paafinner.EFFECTIVE_START_DATE AND paafinner.EFFECTIVE_END_DATE
and SYSDATE BETWEEN peefinner.EFFECTIVE_START_DATE AND peefinner.EFFECTIVE_END_DATE
and SYSDATE BETWEEN petfinner.EFFECTIVE_START_DATE AND petfinner.EFFECTIVE_END_DATE
)
and SYSDATE BETWEEN papf.EFFECTIVE_START_DATE AND papf.EFFECTIVE_END_DATE
and SYSDATE BETWEEN paaf.EFFECTIVE_START_DATE AND paaf.EFFECTIVE_END_DATE
and SYSDATE BETWEEN peef.EFFECTIVE_START_DATE AND peef.EFFECTIVE_END_DATE
and SYSDATE BETWEEN petf.EFFECTIVE_START_DATE AND petf.EFFECTIVE_END_DATE
and upper(petf.ELEMENT_NAME) not like '%Condition%'
and rownum <= 10000
order by peef.last_update_date;
....
This query works properly and returns the correct results but the results are duplicated. I only need one unique row
One of the tables you are joining one is returning doubles or more. I bet it is "peef". Perhaps you can only show the MAX(last_update_date) and roll the rest up against that. So just GROUP BY.
select papf.Full_Name,
papf.Employee_number,
papf.DatE_OF_BIRTH,
last_update_date = MAX(peef.last_update_date)
...
GROUP BY
papf.Full_Name,
papf.Employee_number,
papf.DatE_OF_BIRTH

Age between two dates

I need to get all the employees whose age will be 64 between two dates that I specify. Any help would be appreciated.
What I have tried is:
SELECT
papf.person_id,
date_of_birth,
first_name, last_name,
FROM per_all_people_f papf
WHERE
paaf.person_id = NVL(:P_PERSON_ID, paaf.person_id)
AND :START_DATE = TO_DATE(:START_DATE, 'YYYY-MM-DD')
AND :END_DATE = TO_DATE(:END_DATE, 'YYYY-MM-DD')
Try this :-
SELECT person_id, date_of_birth, first_name, last_name FROM per_all_people_f
WHERE floor(months_between(date START_DATE, date END_DATE) /12)=64;
I tried this and it worked:
SELECT papf.person_id,
date_of_birth,
INITCAP (papf.title) || ' ' || papf.first_name || ' ' || papf.last_name,
employee_number,
assignment_id
FROM per_all_people_f papf, per_all_assignments_f paaf
WHERE papf.person_id = paaf.person_id
AND paaf.person_id = NVL(:P_PERSON_ID, paaf.person_id)
AND PAPF.BUSINESS_GROUP_ID = NVL(:P_BUS_ID, PAPF.BUSINESS_GROUP_ID)
AND months_between((:P_START_D), (date_of_birth)) / 12 < 64
AND months_between((:P_END_D), (date_of_birth)) / 12 >= 64
AND SYSDATE BETWEEN papf.effective_start_date AND papf.effective_end_date
AND SYSDATE BETWEEN paaf.effective_start_date AND paaf.effective_end_date
Since your query from Oracle, please try this one:
SELECT PER.FULL_NAME,
PER.DATE_OF_BIRTH,
ROUND(TRUNC(MONTHS_BETWEEN('your custom date', PER.DATE_OF_BIRTH)) / 12,
1)
FROM PER_ALL_PEOPLE_F PER
WHERE TRUNC(SYSDATE) BETWEEN PER.EFFECTIVE_START_DATE AND
PER.EFFECTIVE_END_DATE
AND ROUND(TRUNC(MONTHS_BETWEEN('your custom date', PER.DATE_OF_BIRTH)) /
12, 1) > 64

Sql query for following scenario

I have following scenario, for which i need to write sql query.
I have ICCID table and ICCID property table which holds following information.
I want to find out all active iccids and iccid's which are in removed state in month of december 2012.for ICCIDs which are in removed state, date.to.change key in the ICCID property table itself which record the removed date of ICCID.
this is my attempt, but that did not worked
select e.ID_ICCID from ICCID_PROPERTY e where
e.c_key ='STATE' and e.c_value='Active' or(
e.c_key ='STATE' and
e.c_value='Removed' and
e.c_key='date.to.change' and
to_date(e.c_value,'yyyymmdd') >=to_date('2012-DEC-01 00:00:00', 'YYYY-MON-DD HH24:MI:SS') and
to_date(e.c_value,'yyyymmdd') <= to_date('2012-DEC-31 23:59:59', 'YYYY-MON-DD HH24:MI:SS')
))
Thanks in advance for any help
This is one of the issues with a key-value pair design such as this...
You can't just check a single property row to see if it matches the search criteria, since the criteria in this case will span multiple properties... you have to check if a single parent row has all the children properties that match:
SELECT
i.ICCID
FROM
ICCID i
WHERE
EXISTS (
SELECT 1
FROM ICCID_PROPERTY ip
WHERE
ip.ID_ICCID = i.ID_ICCID
AND ip.c_key = 'STATE'
AND ip.c_value = 'Active'
) OR (
EXISTS (
SELECT 1
FROM ICCID_PROPERTY ip
WHERE
ip.ID_ICCID = i.ID_ICCID
AND ip.c_key = 'STATE'
AND ip.c_value = 'Removed'
) AND
EXISTS (
SELECT 1
FROM ICCID_PROPERTY ip
WHERE
ip.ID_ICCID = i.ID_ICCID
AND ip.c_key = 'date.to.change'
AND to_date(ip.c_value,'yyyymmdd') >=
to_date('2012-DEC-01 00:00:00', 'YYYY-MON-DD HH24:MI:SS')
AND to_date(ip.c_value,'yyyymmdd') <=
to_date('2012-DEC-31 23:59:59', 'YYYY-MON-DD HH24:MI:SS')
)
)
I think you could join the Property table three times -- maybe something like this (untested):
SELECT I.ID_ICCID
FROM ICCID I
JOIN ICCID_Property IP ON I.ID_ICCID = IP.ID_ICCID AND IP.C_Key = 'STATE' AND IP.C_Value = 'Active'
JOIN ICCID_Property IP2 ON I.ID_ICCID = IP.ID_ICCID AND IP2.C_Key = 'STATE' AND IP2.C_Value= 'Removed'
JOIN ICCID_Property IP3 ON I.ID_ICCID = IP.ID_ICCID AND IP3.C_Key = 'date.to.change' AND to_date(IP3.C_Value,'yyyymmdd') >= to_date('2012-DEC-01 00:00:00', 'YYYY-MON-DD HH24:MI:SS')
AND to_date(IP3.C_Value,'yyyymmdd') <=
to_date('2012-DEC-31 23:59:59', 'YYYY-MON-DD HH24:MI:SS')
Good luck.