using multiple conditions in one query in oracle - oracle

I have this record.
id performer end_time
300135 testuser 15-OCT-13
300135 testuser 14-OCT-13
300135 testuser 12-OCT-13
300137 newuser 14-OCT-13
300137 newuser 18-OCT-13
Now I want to show distinct id's but it will show me all of the Id's because end_time is different .
So what i need is to shwo disticnt Id's with the latest dates.
So the result should be
id performer end_time
300135 testuser 15-OCT-13 (as 15OCT is the heightest date for 300135)
300137 newuser 18-OCT-13 (as 18OCT is the heightest date for 300137)
Currently what i have is
select distinct id, performer, END_TIME from workstep where workstep_name = 'Review' and status ='W_COMPLETED' ....?
but this gives me all the 5 records.where as it should be only 2 , as there are only 2 unique id'.
please suggest
Thanks

You need GROUP BY
select id, performer, max(END_TIME) from workstep where workstep_name = 'Review' and status ='W_COMPLETED' group by id,performer

When you ask for unique row of 3 columns (id, performer, END_TIME )
you will get rows where combination of all 3 columns is unique (your first data listing)
There is simply not enough conditions to get from your first listing to the second one.
I assume that you want distint IDs, and for that IDs, you want to select record where END_TIME is the latest one. Withing the same ID, performer never changes.
So, put just that in sql (query will return only 1 reqord per ID):
select ID, max(performer), max(END_TIME)
from workstep
where ID in
(select distinct ID from workstep where <conditions>)
group by ID
Above query will work if performer is the same for ID.
If performer could be different, but you want to display it from row with end_time = max(END_TIME), you will need more (query could return more than 1 record per ID if there is a tie on END_TIME):
select ID, performer, END_TIME from
from workstep
where (id, end_time) in
(
select ID, max(END_TIME)
from workstep
where ID in
(select distinct ID from workstep where <conditions>)
group by ID
)
So, for query above, there is an assumtion that END_TIME is different for every record with the same ID.
Here is a more advanced version that is free from that assumtion (exatly 1 record per ID):
select id, performer, end_time
from (
select ID, performer, END_TIME,
row_number() over (partition by id order by end_time desc, performer) as No
from workstep
where <conditions>
)
where No = 1
questions?

Related

View All Columns Where Name Repeats

I've been asked to provide a list of all employees who are scheduled to take >6 trips. I need to have all the columns of their record showing for each trip.
I'm very new to SQL and don't have the logic down. So far I've been able to get a count:
SELECT SURNAME, GIVEN_NAME, COUNT(SURNAME)
from EP_EVENT
GROUP BY SURNAME, GIVEN_NAME HAVING COUNT(SURNAME) > 6;
But I need to see * not just SURNAME and GIVEN_NAME, none of the other columns contain the same information.
Help
You could use windowed COUNT:
WITH cte AS (
SELECT e.*, COUNT(*) OVER (PARTITION BY SURNAME, GIVEN_NAME) AS cnt
FROM EP_EVENT e
)
SELECT *
FROM cte
WHERE cnt > 6;

Oracle - select top transaction for each user_id

I have a select statement that gets user_id and a list of transactions for the day such as this:
select user_id, sale_amount, date, product from transactions
I want to be able to select each user_id (there are many) along with their top sale_amount, date and product. If there is a tie, I want it to just select one. How is this possible? Rownum or rank seem to be close but not quite there?
I m not ifo computer but this should work. Let me know
select * from (select user_id, sale_amount, date, product,row_number() over (partition by user_id order by sales_amount desc) as maxsale from transactions) l where maxsale=1

Joining the top result in Oracle

I'm using this query:
SELECT *
FROM HISTORY
LEFT JOIN CUSTOMER ON CUSTOMER.CUST_NUMBER = HISTORY.CUST_NUMBER
LEFT JOIN (
Select LOAN_DATE, CUST_NUMBER, ACCOUNT_NUMBER, STOCK_NUMBER, LOC_SALE
From LOAN
WHERE ACCOUNT_NUMBER != 'DD'
ORDER BY LOAN_DATE DESC
) LOAN ON LOAN.CUST_NUMBER = HISTORY.CUST_NUMBER
order by DATE desc
But I want only the top result from the loan table to be joined (Most recent by Loan_date). For some reason, it's getting three records (one for each loan on the customer I'm looking at). I'm sure I'm missing something simple?
If you're after joining the latest loan row per cust_number, then this ought to do the trick:
select *
from history
left join customer on customer.cust_number = history.cust_number
left join (select loan_date,
cust_number,
account_number,
stock_number,
loc_sale
from (select loan_date,
cust_number,
account_number,
stock_number,
loc_sale,
row_number() over (partition by cust_number
order by loan_date desc) rn
from loan
where account_number != 'DD')
where rn = 1) loan on loan.cust_number = history.cust_number
order by date desc;
If there are two rows with the same loan_date per cust_number and you want to retrieve both, then change the row_number() analytic function for rank().
If you only want to retreive one row, then you'd have to make sure you add additional columns into the order by, to make sure that the tied rows always display in the same order, otherwise you could find that sometimes you get different rows returned on subsequent runs of the query.

How to delete the recent (in date) records from a table in oracle?

i want to delete the last recent record from my table.
Code to select the last record:
SELECT * FROM
( select ID, NAME,
createdon
from Person where age= 30
order by createdon DESC)
WHERE ROWNUM <= 1;
i tried this to delete the last records:
DELETE * FROM
( select ID, NAME,
createdon
from Person where age= 30
order by createdon DESC)
WHERE ROWNUM <= 1;
It 's not working.
ERROR: "invalid table name"
Any help please, Thank you
As OracleUser said, you can't delete from an in-line view. You can use your original inner query to delete based on all three columns it selects, assuming they will uniquely identify a single row:
delete from person
where (id, name, createdon) = (
select * from (
select id, name, createdon
from person
where age = 30
order by createdon desc
)
where rownum <= 1
);
SQL Fiddle.
If ID is a primary or unique key you can do this instead:
delete from person
where id =
(
select id
from (
select id, row_number() over (order by createdon desc) as rn
from person where age = 30
)
where rn = 1
);
If it is not then you can use rowid instead, replacing both references to id in the statement.
The innermost query is basically the same as the inner query in your select, but I'm using the row_number analytic function to assign the equivalent of rownum. The next layer out filters out everything except the most recent, based on the row_number calculation.
You can use rank() instead but could get two record with exactly the same times, and would need to decide whether both should be deleted, or if you should have some additional way to break the tie - e.g. order by createdon desc, id desc. As I've shown it here, row_number() also breaks the tie arbitrarily but can have the explicitly extra ordering to control that, as would rownum. And there's also dense_rank().
SQL Fiddle.
This is a bit simpler but would also delete multiple rows, if you had more than one with the same createdon value:
delete from person
where createdon =
(
select max(createdon)
from person
where age = 30
);

ORACLE: How to select previous different value?

I have table that stores employee job name, it has the following columns:
id; date_from; date_to; emp_id; jobname_id; grade;
Each emp_id can have many consecutive records with the same jobname_id due to many grade changes.
How can I select previous different jobname_id omitting those that are the same like the most current one?
This solution uses the FIRST_VALUE() analytic function to identify each employee's current job. It then filters for all the jobs which dfon't match that one:
select distinct id
, jobname_id
from ( select id
, jobname_id
, first_value(jobname_id) over (partition by id
order by from_date desc) as current_job
from employee
where emp_id = 1234 )
where jobname_id != current_job
order by id, jobname_id
/
Will this work for your issue:
SELECT DISTINCT
e1.emp_id,
e1.jobname_id
FROM employee e1
WHERE NOT EXISTS
(SELECT 1
FROM employee e2
WHERE e1.emp_id = e2.emp_id
AND SYSDATE BETWEEN e2.date_from
AND NVL(e2.date_to, SYSDATE + 1));
(This asumes your table is named "employee" and emp_id is the PK value).
It selects unique emp_id, jobname_id values where the emp_id, jobname_id values are not current.
EDIT: I agree with Chin Boon that fundamentally this is a design issue and perhaps that should be addressed rather than working around the problem.

Resources