Oracle Select Highest date per record - sql

I'm a little bit stumped as to how to do this. I want to select records from a table "agency" joined to a table "notes" on an id column that the two tables share.
Table structure:
create table notes (
notes_id varchar2(5),
agency_gp_id varchar2(5),
call_date date,
call_note varchar2(4000)
);
create table agency(
agency_id varchar2(5),
agency_name varchar2(5),
street varchar2(75),
city varchar2(50)
);
alter table notes add constraint "fk_group_notes_agency_id" foreign key(agency_gp_id)
references agency(agency_id) enable;
-Each table has auto-numbering, "before-insert" triggers so the id numbers stay in synch (along with other stuff in the case of adding a note to a newly created agency) - everything I need it to do (the databse), it does.
-Each record from the agency table has a distinct name/address combo (with different branches in different cities) and each record from the notes table has a date entry corresponding to each agency.
-Each agency can have multiple notes (multiple note details from subsequent visits)
What I am attempting to do is select each (distinct agency,street,city) that has not had a note added to it within the past four months.
This is the query I came up with:
SELECT count(a.agency_name) as number_of_visits,
a.agency_name,
(a.street||', '||a.city) as "Location",
n.call_date,
ROUND(TRUNC(sysdate - call_date)) AS days_since_visit
FROM notes n, agency a
WHERE (sysdate - n.call_date) > 120
AND n.agency_gp_id = a.agency_id
--AND a.city = 'München' --not necessary, used for limiting number of results
GROUP BY n.call_date,a.agency_name,a.street, a.city
ORDER BY a.agency_name ASC, n.call_date desc;
It kind of works...I can see what I want but I also see what I DO NOT want (e.g. the multiple notes on each agency). The only thing I want to see is the last entry (most recent, according to the WHERE clause) of each agency. The picture I want to create is: For whichever agency that has not been annotated within 120 days of the last note, display the address and name and the last note date.
(Instead of showing the number of days since EACH visit, I want to show the number of days that have past since the LAST visit - per distinct agency,street,city).
This is for an app that will help a sales executive schedule her sales calls and is run twice a week. I have been unable to figure this out. Also, bear in mind that the actual tables used are much more descriptive - what I have used here are only the parts I need to describe the question.
I would appreciate any suggestions on how to solve this problem.
Thanks!

If I understand your problem correctly, changing call_date to MAX(call_date) (and removing it from the GROUP BY statement) should get you what you want int terms of data, but would also pull in false positives, namely any agency that had notes older than 120 days, regardless of the most recent note. If we filter those agencies out in a NOT EXISTS subquery, that should get you where you need to go.
SELECT count(a.agency_name) as number_of_visits,
a.agency_name,
(a.street||', '||a.city) as "Location",
MAX(n.call_date),
ROUND(TRUNC(sysdate - MAX(call_date))) AS days_since_visit
FROM notes n, agency a
WHERE (sysdate - n.call_date) > 120
AND n.agency_gp_id = a.agency_id
AND NOT EXISTS (SELECT 1 FROM notes n2
WHERE n2.agency_gp_id = a.agency_id
AND (sysdate - n2.call_date) <= 120)
--AND a.city = 'München' --not necessary, used for limiting number of results
GROUP BY a.agency_name,a.street, a.city
ORDER BY a.agency_name ASC, MAX(n.call_date) desc;

Related

SQL query to find and display duplicates where one of them have a birth year in 2000s and the other one in 1900s

I am working with table with user ID's but it is not a primary key so it can contain duplicate values and in some cases the birth year is wrong, it is for example 2052 and then user created another account with birth year 1952 which is correct. How to find duplicates so I can eliminate the wrong ones?
I wrote this but it's still not completely what I need
select *
from RF_CUSTOMER a
join ( select OID
from RF_CUSTOMER
group by OID
having count(OID) > 1 ) b
on a.OID= b.OID
order by a.oib;

I am trying to write a SQL Server query using joins and having some difficulty

Tables are explained in detail as below:
I have 3 tables:
Table A:
It serves as the master table for information about the employees.
EmployeeId(Primary key)
Employee Designation
EmployeeName (More columns of employee data which is not relevant to this particular query)
Table B:
It serves as table where all employees who are accounted for are stored. For ex an employee who has reported sick or is on leave or has pregnancy leave, etc. Bottom line an employee which is not available
EmployeeID (primary key) (also referencing master table A as foreign key)
AccountedFor
AccountedFordurationFrom (datetime)
AccountedForDurationTo (datetime)
Table C:
It serves as a table where excused data of employees are present. For ex we have our organization's time table spread as events, 1st event is morning time conference, then 2nd is silence working time, 3rd is brainstorming sessions etc. Now if an employee is excused for a particular event, it is entered here.
EmployeeID
EventCode
Excuse_DurationFrom
Excuse Duration To
Any specific details
Here EmployeeID and ExcusedForEventCode are both composite primary keys as it is possible to have same employeeId for multiple excuses,but the combination is always unique.
We have built some custom attendance management system and would require the following details:
We need to find all those employees who are neither accounted for nor excused for a specific event(this will be provided through front end) for a time duration selected through the front end.
The result of the above query will subsequently be used to compare with a biometric attendance machine logs which gives
EmployeeId|LogDate(datetime)|EventCodes as a separate table input to our database (Master table A employeeId references this EmployeeId as foreign key)
It will be compared to find out true absentees for a particular event. ie All those employees who are neither accounted for, nor excuses for any particular event and who does not figure out in the biometric scan machine logs are absented for those time duration selected. We need the output of absentee like this EmployeeId|Employee Designation|Employee Name|EventName (have a separate table linking with EventCode)|Date&time (this would be per day per event report of employee who are absent from the selected time duration).
We have tried queries like:
select
employeemastertable.employeeid,
employeemastertable.Designation,
employeemastertable.Name,
EventCodes.EventCodeName as Eventexcusedfrom
from
employeemastertable
inner join
employeeexcusedforevents on employeemastertable.employeeid = employeeexcusedforevents.employeeid
inner join
EventCodes on employeeexcusedforEvents.ExcusedForEventCode = EventCodes.Eventcode
left join
employeeaccountedFor on employeemastertable.employeeid = employeeaccountedFor.employeeid
where
employeeexcusedforevents.ExcusedForEventCode != 1 (Morning conference)
and employeeaccountedFor.employeeid is null;
Names have been changed
I do understand this will give those employees who does not figure out in event Morning conference but even if I do left join instead of inner join between employeemastertable and employeeexcusedForevents and put employeeexcusedforevents.excusedforeventcode is null and employeeexcusedforevents.employeeid is null, I do get all those employees not present in the other two table, but the criteria of event is not satisfied. That means what if the employee is excused for the 2nd event as well in the organization. How would I cater for that in the above code? (PS this is only the 1st part of the equation I understand that, after this I need help for the other part also, where time duration and comparing with logs is concerned)?
I assume there will be just one row for the EventCode=1 in table EventCodes. Below I cross join the wanted event to the employee master table and then exclude any employees that are excused or accounted for.
-- employees neither accounted for nor excused for a specific event
SELECT
em.employeeid
, em.Designation
, em.Name
, ec.EventCodeName AS Eventexcusedfrom
FROM employeemastertable em
CROSS JOIN (
SELECT Eventcode, EventCodeName
FROM EventCodes
WHERE Eventcode = 1
) ec
WHERE NOT EXISTS (
SELECT NULL
FROM employeeexcusedforevents ee
WHERE em.employeeid = ee.employeeid
AND ec.Eventcode = ee.ExcusedForEventCode
)
AND NOT EXISTS (
SELECT NULL
FROM employeeaccountedFor eaf
WHERE em.employeeid = eaf.employeeid
)
;

Postgresql/SQL - My date/timestamp logic seems solid but producing nulls

I have a massive table full of hospital visit information. Each row corresponds to one visit. The visit/row itself has a unique ID but also contains a person ID (patient) to match back to that persons specific information.
I'm building a "new patient" sequence model. In doing so, I need to remove any patient from the table who has one (or more) visits before a set date. I can't just remove records before that date, as those "loyal patients" will still have visit information.
I tried to build a look-up table with all the patient ID's that have one or more visits before a certain time. I then tried to use this table to remove all visit information for patients who have had one or more visit before that set time.
I've tried multiple variations of the below (with statements, delete statements, having statements ect.) Each time, the final table has no values. I have verified that there are "new patients" with visit dates only after the set date.
My logic feels solid but clearly something is off. Here is the last command I tried. Any help would be greatly appreciated!
create table client_myvisit_notnew_id as
select patient, admissiondate from client_myvisit_primary_temp1
where admissiondate < '2015-05-30 00:00:00';
create table client_myvisit_primary_temp2 as
select * from client_myvisit_primary_temp1
where patient not in
(select patient from client_myvisit_notnew_id);
not in is a very dangerous construct with subqueries. If any of the values returned by the subquery is NULL, then nothing ever passes the filter. Although you can fix this by adding a where clause, I suggest that you get used to not exists instead:
select mpt.*
from client_myvisit_primary_temp1 mpt
where not exists (select 1
from client_myvisit_notnew_id mni
where mpt.patient = mni.patient
);
This has the semantics that most people expect.
EDIT:
If you just want patients who's original visit is after a certain date, then use window functions:
select mpt.*
from (select mpt.*,
min(mpt.admission_date) over (partition by mpt.patient) as min_ad
from client_myvisit_primary_temp1
) mpt
where min_ad >= '2015-05-30';
Defining multiple views is not necessary.

Suppress Nonadjacent Duplicates in Report

Medical records in my Crystal Report are sorted in this order:
...
Group 1: Score [Level of Risk]
Group 2: Patient Name
...
Because patients are sorted by Score before Name, the report pulls in multiple entries per patient with varying scores - and since duplicate entries are not always adjacent, I can't use Previous or Next to suppress them. To fix this, I'd like to only display the latest entry for each patient based on the Assessment Date field - while maintaining the above order.
I'm convinced this behavior can be implemented with a custom SQL command to only pull in the latest entry per patient, but have had no success creating that behavior myself. How can I accomplish this compound sort?
Current SQL Statement in use:
SELECT "EpisodeSummary"."PatientID",
"EpisodeSummary"."Patient_Name",
"EpisodeSummary"."Program_Value"
"RiskRating"."Rating_Period",
"RiskRating"."Assessment_Date",
"RiskRating"."Episode_Number",
"RiskRating"."PatientID",
"Facility"."Provider_Name",
FROM (
"SYSTEM"."EpisodeSummary"
"EpisodeSummary"
LEFT OUTER JOIN "FOOBARSYSTEM"."RiskAssessment" "RiskRating"
ON (
("EpisodeSummary"."Episode_Number"="RiskRating"."Episode_Number")
AND
("EpisodeSummary"."FacilityID"="RiskRating"."FacilityID")
)
AND
("EpisodeSummary"."PatientID"="RiskRating"."PatientID")
), "SYSTEM"."Facility" "Facility"
WHERE (
"EpisodeSummary"."FacilityID"="Facility"."FacilityID"
)
AND "RiskRating"."PatientID" IS NOT NULL
ORDER BY "EpisodeSummary"."Program_Value"
The SQL code below may not be exactly correct, depending on the structure of your tables. The code below assumes the 'duplicate risk scores' were coming from the RiskAssessment table. If this is not correct, the code may need to be altered.
Essentially, we create a derived table and create a row_number for each record, based on the patientID and ordered by the assessment date - The most recent date will have the lowest number (1). Then, on the join, we restrict the resultset to only select record #1 (each patient has its own rank #1).
If this doesn't work, let me know and provide some table details -- Should the Facility table be the starting point? are there multiple entries in EpisodeSummary per patient? thanks!
SELECT es.PatientID
,es.Patient_Name
,es.Program_Value
,rrd.Rating_Period
,rrd.Assessment_Date
,rrd.Episode_Number
,rrd.PatientID
,f.Provider_Name
FROM SYSTEM.EpisodeSummary es
LEFT JOIN (
--Derived Table retreiving highest risk score for each patient)
SELECT PatientID
,Assessment_Date
,Episode_Number
,FacilityID
,Rating_Period
,ROW_NUMBER() OVER (
PARTITION BY PatientID ORDER BY Assessment_Date DESC
) AS RN -- This code generates a row number for each record. The count is restarted for every patientID and the count starts at the most recent date.
FROM RiskAssessment
) rrd
ON es.patientID = rrd.patientid
AND es.episode_number = rrd.episode_number
AND es.facilityid = rrd.facilityid
AND rrd.RN = 1 --This only retrieves one record per patient (the most recent date) from the riskassessment table
INNER JOIN SYSTEM.Facility f
ON es.facilityid = f.facilityid
WHERE rrd.PatientID IS NOT NULL
ORDER BY es.Program_Value

Report "Query By Date" APEX

I am working in Oracle APEX.I want to make report of previous month patients treated by doctor from two tables i-e Patient and History.
Pat_id is Primary key in Patient table and foreign key in History Table.
I want report that should show me Pat_Name ,Pat_Age ,Treated_By and Date where as i can also select month from LOV(List of Value) and on the basis of that month it should show me the report.
Kindly Help me out
Thanks,
SELECT p.pat_name, p.pat_age, h.treated_by, h.date
FROM patient p
JOIN history h
ON p.pat_id = h.pat_id
WHERE EXTRACT(MONTH FROM h.date) = TO_NUMBER(:P1_MONTH)
(a really basic join condition really)
If you want ordering, you could include this in the sql, or define this in the report definition of a classic report, or as defaults in an interactive report.
P1_MONTH : a select list. As for its list of values, you can either define the months statically (12 entries with month number as return value and month name as display), or use a query:
SELECT to_char(add_months(to_date('01/01/2012','DD/MM/YYYY'),LEVEL-1),'Month') display_value, LEVEL return_value
FROM dual
CONNECT BY LEVEL <= 12
Set the select list to submit on change.
As an extra note: set your column names to be UPPERCASE in your schemas. Columns are always uppercase unless they are defined otherwise upon creation. Also be careful with using reserved keywords for things such as a column name: DATE may not be the best name for a column... Give it a useful name such as TREATED_ON