Oracle SQL MAX and GROUP BY Costs too Much Lines of Code - sql

I have this long query, where I want to fetch some data about employees:
SELECT e.id,
e.emp_number,
TO_CHAR(SYSDATE,'DD/MONTH/YYYY') "GREGORIAN",
to_char(sysdate,'DD-MM-YYYYY','nls_calendar=''arabic hijrah''') HIJRI,
ba.acc_number "Account Number"
to_char(c.id) "National ID",
en.name
FROM
relationships r,
rel_actions ra,
actions a,
payrolls p,
emp_names en,
citizenships c,
pay_methods pm,
bank_accounts ba,
assignments as,
emp e
WHERE r.id = ra.id
AND r.id=pm.id
AND as.id = e.id
AND r.id = e.id
AND en.id = e.id
AND en.NAME_TYPE ='GLOBAL'
AND a.action_type = 'T'
AND a.id = ra.id
AND a.id = p.id
and c.id = e.id
and ba.id=pm.id
AND a.effective_date BETWEEN ba.start_date AND ba.end_date
AND a.effective_date BETWEEN p.effective_start_date AND p.effective_end_date
AND a.effective_date BETWEEN r.start_date AND r.end_date
AND a.effective_date BETWEEN en.effective_start_date AND en.effective_end_date
AND a.effective_date BETWEEN e.effective_start_date AND e.effective_end_date
AND a.effective_date BETWEEN pm.effective_start_date AND pm.effective_end_date
AND a.effective_date BETWEEN as.effective_start_date AND as.effective_end_date
AND as.assignment_type = 'E'
AND SYSDATE BETWEEN as.effective_start_date AND as.effective_end_date
ORDER BY e.emp_number
the result of this query will be something like this :
emp_number account_number name national_id gregorian hijri
1 6456 john ^*&$^**$^** 6/12/2022 12/5/1444
1 6456 john ^*&$^**$^** 6/12/2022 12/5/1444
2 4121 Mathew %&#%^%&%&%^ 6/12/2022 12/5/1444
2 4121 Mathew %&#%^%&%&%^ 6/12/2022 12/5/1444
taking the first 2 rows for example, they have different effective_date, so I want to fetch the row that have the newest effective_date:
and a.effective_date in (
select effective_Date from pay_payroll_actions
where a.effective_date BETWEEN ba.start_date AND ba.end_date
AND a.effective_date BETWEEN p.effective_start_date AND p.effective_end_date
AND a.effective_date BETWEEN r.start_date AND r.end_date
AND a.effective_date BETWEEN en.effective_start_date AND en.effective_end_date
AND a.effective_date BETWEEN e.effective_start_date AND e.effective_end_date
AND a.effective_date BETWEEN pm.effective_start_date AND pm.effective_end_date
AND a.action_type = 'T'
AND a.id = ra.id
AND a.id = p.id
)
GROUP BY e.id, e.emp_number,
TO_CHAR(SYSDATE,'DD/MONTH/YYYY'),
to_char(sysdate,'DD-MM-YYYYY','nls_calendar=''arabic hijrah'''),
ba.acc_number ,
to_char(c.id),
en.name
my question is, do I really need to apply all related conditions in the sub-query in order to get the same effective dates resulted from the main query?
and if yes, its too long, is there a way to shorten this? thanks in advance

You can filter the duplicate rows using row_number ()
WITH cte
AS
(SELECT e.id,
e.emp_number,
TO_CHAR(SYSDATE,'DD/MONTH/YYYY') "GREGORIAN",
to_char(sysdate,'DD-MM-YYYYY','nls_calendar=''arabic hijrah''') HIJRI,
ba.acc_number "Account Number"
to_char(c.id) "National ID",
en.name,
row_number() over (partition BY e.id,
e.emp_number,ba.acc_number,c.id,en.name ORDER BY a.effective_date desc) AS dup_count
FROM your_query)
SELECT * FROM cte WHERE dup_count = 1;
OR Since you are already checking the dates between condition in your main query ,you can refine your sub query to
and a.effective_date in (
select effective_Date from pay_payroll_actions py
where a.id=py.id
)

Related

How to write select statement with if statement in where coundition

I would like to write one select statement in postgres how could I place if condition in where condition
To creating a report in that suppose we have 20 country in our table and and we have three type of employee which having contact, payroll and permanent these are the employee_category I would like to get all employee details except India and USA who having contact employee in these two country if employee having payroll and permanent should come in result
something like this
SELECT
r.employee_id AS E_ID,
r.Joining_date AS J_DATE,
r.employee_type AS E_TYPE,
'NIL'::text AS REMARKS,
i.source as SOURCE,
i.user_orgname as USER_ORGNAME
from master_employee r
INNER JOIN users_master AS i ON r.user_id = i.loginid and i.userstatus = 'Active'
WHERE
if(country="india","USA"){
employee_category!='contract'
}
and
date(r.createddate) = date(now())
ORDER BY r.createddate ASC ;
Using the case statement should work.
SELECT
r.employee_id AS E_ID,
r.Joining_date AS J_DATE,
r.employee_type AS E_TYPE,
'NIL'::text AS REMARKS,
i.source as SOURCE,
i.user_orgname as USER_ORGNAME
from master_employee r
INNER JOIN users_master AS i ON r.user_id = i.loginid and i.userstatus = 'Active'
WHERE employee_category <> case when country in ("india","USA") then 'contract' end
and date(r.createddate) = date(now())
ORDER BY r.createddate ASC ;
Instead, use basic boolean logic:
where (country not in ('india', 'USA') or
employee_category <> 'contract'
) and
date(r.createddate) = date(now())

Unsupported subquery with table in join predicate

I am tried to run the next query but the next message appearance "Unsupported subquery with table in join predicate." Do you have some idea? I appreciate your comments.
WITH
D1 AS (
SELECT
SETID,
CUST_ID,
MAX(EFFDT) AS EFFDT
FROM
`g4s-data-reporting.g4s_data.PS_CUST_CREDIT`
WHERE
EFFDT <= CURRENT_TIMESTAMP()
GROUP BY
1,
2 ),
LEFT OUTER JOIN
`g4s-data-reporting.g4s_data.PS_CUST_CREDIT` D
ON
A.SETID = D.SETID
AND A.CUST_ID = D.CUST_ID
AND D.EFFDT = (
SELECT
MAX(EFFDT) --select 2
FROM
`g4s-data-reporting.g4s_data.PS_CUST_CREDIT` D1
WHERE
D1.SETID = D.SETID
AND D1.CUST_ID = D.CUST_ID
AND D1.EFFDT <= CURRENT_TIMESTAMP() )
WHERE
B.BUSINESS_UNIT IN ('00001',
'00048')
AND B.ITEM_STATUS = 'O'
AND B.ENTRY_TYPE NOT IN ('AO',
'CNVBC',
'MC',
'OA')

Oracle SQL Query to join multiple tables

I am trying to join multiple tables and the below query works well.
select
e.ENCNTR_ID e_id
, p.PERSON_ID p_id
, e.REG_DT_TM admitted
from
episode e
, patient p
where (e.reg_dt_tm > '01/JAN/2018'
and e.reg_dt_tm < '02/JAN/2018'
and e.active_ind = 1
and e.encntr_type_cd = 123.00
and e.ACTIVE_STATUS_CD = 1234
and e.person_id = p.person_id)
But when I change it and add more tables it gives me the error
"SQL Command not properly ended"
I need to add conditions on the first table(episode) as otherwise the query runs very slow.
select
e.ENCNTR_ID e_id
, p.PERSON_ID p_id
, e.REG_DT_TM admitted
, ce.EVENT_ID event_id
from
ENCOUNTER e
, person p
where (e.reg_dt_tm > '01/JAN/2018'
and e.reg_dt_tm < '02/JAN/2018'
and e.active_ind = 1
and e.encntr_type_cd = 7113.00
and e.ACTIVE_STATUS_CD = 22223
and e.person_id = p.person_id)
left join CLINICAL_EVENT ce on ce.ENCNTR_ID = e.ENCNTR_ID
and ce.EVENT_CD in (1235764
,22161234
)
and ce.valid_until_dt_tm > sysdate
left join CE_BLOB cb on ce.EVENT_ID = cb.EVENT_ID
and cb.valid_until_dt_tm > sysdate
order by e.REG_DT_TM, ce.PERFORMED_DT_TM, ce.CLINICAL_EVENT_ID
The query should look like this:
select e.ENCNTR_ID as e_id, p.PERSON_ID as p_id, e.REG_DT_TM as admitted, ce.EVENT_ID as event_id
from ENCOUNTER e join
person p
on e.person_id = p.person_id left join
CLINICAL_EVENT ce
on ce.ENCNTR_ID = e.ENCNTR_ID and
ce.EVENT_CD in (1235764, 22161234) and
ce.valid_until_dt_tm > sysdate left join
CE_BLOB cb
on ce.EVENT_ID = cb.EVENT_ID and
cb.valid_until_dt_tm > sysdate
where e.reg_dt_tm > date '2018-01-01' and
e.reg_dt_tm < date '2018-01-02' and
e.active_ind = 1 and
e.encntr_type_cd = 7113.00 and
e.ACTIVE_STATUS_CD = 22223
order by e.REG_DT_TM, ce.PERFORMED_DT_TM, ce.CLINICAL_EVENT_ID;
Notes:
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
The WHERE clause goes after the FROM clause.
JOIN is an operator in the FROM clause, so all JOINs need to be before the WHERE.
Use the keyword DATE for date constants.

how to join a table on a subquery that uses order by and limit

For each row from table tClass matching a given where clause,
join on the first row in tEv, sorted by time, where tEv.class_id = tClass.class_id
The following code throws the error
ORA-01799: a column may not be outer-joined to a subquery
select
c.class_id,
c.class_name,
e.start_time,
e.ev_id
from
tClass c
left join tEv e on (
e.ev_id = (
select
ss1.ev_id
from (
select
ed.ev_id
from
tEvDisp ed,
tEv e
where
ed.class_id = c.class_id
and ed.viewable = 'Y'
and ed.display_until > localtimestamp
and e.ev_id = ed.ev_id
order by
e.start_time
) ss1
where
rownum = 1
)
)
where
c.is_matching = 'Y';
How can this be rewritten to do what is described?
The above is for oracle, but needs to work in sqlite (substituting where necessary)
No idea about SQLite - that would need to be a separate question if this doesn't work - but for Oracle you could do something like this:
select c.class_id,
c.class_name,
e.start_time,
e.ev_id
from tClass c
left join (
select class_id, ev_id, start_time
from (
select ed.class_id,
ed.ev_id,
e.start_time,
row_number() over (partition by ed.class_id order by e.start_time) as rn
from tEvDisp ed
join tEv e on e.ev_id = ed.ev_id
where ed.viewable = 'Y'
and ed.display_until > localtimestamp
)
where rn = 1
) e on e.class_id = c.class_id
where c.is_matching = 'Y';
This uses a subquery which finds the most tEv data, using an analytic row_number() to identify the latest data for each class_id, which is restricted by the rn = 1 filter.
That subquery, consisting of at most one row per class_id, is then used the left outer join against tClass.
This sort of construct should get you what you need. You can fix the details.
select c.classid
, c.classname
, temp.maxstarttime
from tClass c left join (
select c.classid id
max(e.start_time) maxstarttime
from tClass join tEv on tEv.classId = tClass.ClassId
where whatever
group by c.classid) temp on c.classid = temp.id

Using MAX for date but adding column to group on 'breaks' the query - sub query?

I Have a table which holds date but I need to know the latest date where a condition is true per location, only issue is once I add a column called 'notes' it breaks the query and returns too many rows, current query is ...
SELECT
Location,
MAX(date) AS date,
type,
notes
FROM NotesTable a
INNER JOIN Location b on a.LocationID = b.LocationID
INNER JOIN Type c on a.typeid = c.typeid
WHERE typeid <> 8
GROUP BY Location, type, notes
If I comment out the notes column then it works fine but as soon as I add that to the grouping it then returns more rows than required.
Have tried using a subquery but still cant get it working, subquery below
SELECT
r.location,
r.date,
r.type,
t.notes
FROM (SELECT Location, MAX(date), type
FROM NotesTable a INNER JOIN Location b on a.LocationID = b.LocationID
INNER JOIN Type c on a.typeid = c.typeid
WHERE typeid <> 8
GROUP BY location,type
) r
INNER JOIN NotesTable t ON t.date = r.date
Anyone got any other suggestions?
select * from
(
SELECT Location,Date, Type, Notes, Row_Number() Over (Partition By Location, Type order by date desc) RN
FROM
NotesTable a
INNER JOIN Location b on a.LocationID = b.LocationID
INNER JOIN Type c on a.typeid = c.typeid
WHERE typeid <> 8
) v
WHERE rn = 1
Your query is almost correct, you need to add this additional condition in ON clause
AND
t.location = r.location AND
t.type = r.type
full query,
SELECT r.location
, r.DATE
, r.type
, t.notes
FROM (
SELECT Location
, MAX(DATE) maxDate
, type
FROM NotesTable a
INNER JOIN Location b
ON a.LocationID = b.LocationID
INNER JOIN Type c
ON a.typeid = c.typeid
WHERE typeid <> 8
GROUP BY location
, type
) r
INNER JOIN NotesTable t
ON t.DATE = r.maxDate AND
t.location = r.location AND
t.type = r.type