Oracle - select top transaction for each user_id - oracle

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

Related

joining tables to sum the amount of a items ordered

Have the following data tables:
menu_items:
item_id,
item_name,
price,
sales:
item_id,
customer_id,
employee_id,
date
I am attempting to join the tables on item_id. I want to display the item_name, number of item_names sold and date, and group them by the date. How should I adjust the code below to make the query work.
select item_name, count(item_name), date
from menu_items join sales
on item_id = item_id
group by date
As you probably found out, it won't work; all non-aggregated items must be contained in the GROUP BY clause. Also, you should use table aliases, always.
select s.date_col,
i.item_name,
count(*) number_of_items_sold
from menu_items i join sales s on s.item_id = i.item_id
group by s.date_col, i.item_name
order by s.date_col, i.item_name;
If it is not what you wanted, please, post some sample data and desired output; it might be easier to answer, then.

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;

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.

using multiple conditions in one query in 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?

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