Report "Query By Date" APEX - sql

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

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;

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.

OracleSQL: Assigning employees to groups with date values, querying current assignments by date

I have a database which consists of employees (one table) which can be assigned to groups (another table). Bother are joined together with another table, employee-to-group, which lists the group id, the employee id and the start date of the assignment.
An employee always has to be assigned to a group, but the assignments can change daily. One employee could be working in group A for day, then change into group B and work in group C only a week later.
My task is to find out which employees are assigned to a certain group given by its name at any given date. So the input should be: group name, date and I want the output to be the data of all the employees which are part of that group at the given moment in time.
Here's an SQL fiddle with some test data:
http://sqlfiddle.com/#!9/6d0bb
I recreated the database with mysql-statements because I couldn't figure out the oracle statements, I'm sorry.
As you can see from the test data, some employees may never change groups, while others change frequently. THere are also employees which are planned to change assignments in the future. The query has to account for that.
Because the application is a legacy one, the values (especially in the date field) are questionable. They are given as "days since the 1st of january, 1990", so the entry "9131" means "1st of january, 2015". 9468 would be today (2015-12-04) and 9496 would be 2016-01-01).
What I already have is code to find out the "date value" for any given date in what I call the "legacy format" of the application I'm working with (here I've just used CURRENT_DATE):
SELECT FLOOR(CURRENT_DATE - TO_DATE('1990-01-01', 'YYYY-MM-DD')) AS diffdate
For finding out which group a certain employee is assigned to, I tried:
SELECT * FROM history h
WHERE emp_nr = 1 AND valid_from <= 9131
ORDER BY valid_from DESC
FETCH FIRST ROW ONLY;
which should return me the group which an employee is assigned to on the 1st of january 2015.
What I do need help with is creating a statement that joins all tables does the same for a whole group instead of only one employee (as there are thousands of employees in the database and I only want the data of at most 10 groups).
I'm thankful for any kind of pointers in the right direction.
Use row_number to rank your history and get the latest group, just as you did with your FETCH FIRST query:
select *
from
(
select
h.*,
row_number() over (partition by emp_nr order by valid_from desc) as rn
from history h
where valid_from <= 9131
)
where rn = 1
You can then join this result with other tables.

Oracle Select Highest date per record

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;

Where are Cartesian Joins used in real life?

Where are Cartesian Joins used in real life?
Can some one please give examples of such a Join in any SQL database.
just random example. you have a table of cities: Id, Lat, Lon, Name. You want to show user table of distances from one city to another. You will write something like
SELECT c1.Name, c2.Name, SQRT( (c1.Lat - c2.Lat) * (c1.Lat - c2.Lat) + (c1.Lon - c2.Lon)*(c1.Lon - c2.Lon))
FROM City c1, c2
Here are two examples:
To create multiple copies of an invoice or other document you can populate a temporary table with names of the copies, then cartesian join that table to the actual invoice records. The result set will contain one record for each copy of the invoice, including the "name" of the copy to print in a bar at the top or bottom of the page or as a watermark. Using this technique the program can provide the user with checkboxes letting them choose what copies to print, or even allow them to print "special copies" in which the user inputs the copy name.
CREATE TEMP TABLE tDocCopies (CopyName TEXT(20))
INSERT INTO tDocCopies (CopyName) VALUES ('Customer Copy')
INSERT INTO tDocCopies (CopyName) VALUES ('Office Copy')
...
INSERT INTO tDocCopies (CopyName) VALUES ('File Copy')
SELECT * FROM InvoiceInfo, tDocCopies WHERE InvoiceDate = TODAY()
To create a calendar matrix, with one record per person per day, cartesian join the people table to another table containing all days in a week, month, or year.
SELECT People.PeopleID, People.Name, CalDates.CalDate
FROM People, CalDates
I've noticed this being done to try to deliberately slow down the system either to perform a stress test or an excuse for missing development deliverables.
Usually, to generate a superset for the reports.
In PosgreSQL:
SELECT COALESCE(SUM(sales), 0)
FROM generate_series(1, 12) month
CROSS JOIN
department d
LEFT JOIN
sales s
ON s.department = d.id
AND s.month = month
GROUP BY
d.id, month
This is the only time in my life that I've found a legitimate use for a Cartesian product.
At the last company I worked at, there was a report that was requested on a quarterly basis to determine what FAQs were used at each geographic region for a national website we worked on.
Our database described geographic regions (markets) by a tuple (4, x), where 4 represented a level number in a hierarchy, and x represented a unique marketId.
Each FAQ is identified by an FaqId, and each association to an FAQ is defined by the composite key marketId tuple and FaqId. The associations are set through an admin application, but given that there are 1000 FAQs in the system and 120 markets, it was a hassle to set initial associations whenever a new FAQ was created. So, we created a default market selection, and overrode a marketId tuple of (-1,-1) to represent this.
Back to the report - the report needed to show every FAQ question/answer and the markets that displayed this FAQ in a 2D matrix (we used an Excel spreadsheet). I found that the easiest way to associate each FAQ to each market in the default market selection case was with this query, unioning the exploded result with all other direct FAQ-market associations.
The Faq2LevelDefault table holds all of the markets that are defined as being in the default selection (I believe it was just a list of marketIds).
SELECT FaqId, fld.LevelId, 1 [Exists]
FROM Faq2Levels fl
CROSS JOIN Faq2LevelDefault fld
WHERE fl.LevelId=-1 and fl.LevelNumber=-1 and fld.LevelNumber=4
UNION
SELECT Faqid, LevelId, 1 [Exists] from Faq2Levels WHERE LevelNumber=4
You might want to create a report using all of the possible combinations from two lookup tables, in order to create a report with a value for every possible result.
Consider bug tracking: you've got one table for severity and another for priority and you want to show the counts for each combination. You might end up with something like this:
select severity_name, priority_name, count(*)
from (select severity_id, severity_name,
priority_id, priority_name
from severity, priority) sp
left outer join
errors e
on e.severity_id = sp.severity_id
and e.priority_id = sp.priority_id
group by severity_name, priority_name
In this case, the cartesian join between severity and priority provides a master list that you can create the later outer join against.
When running a query for each date in a given range. For example, for a website, you might want to know for each day, how many users were active in the last N days. You could run a query for each day in a loop, but it's simplest to keep all the logic in the same query, and in some cases the DB can optimize the Cartesian join away.
To create a list of related words in text mining, using similarity functions, e.g. Edit Distance