I have following table structure. I want to select distinct user_id according to office_id with lastest login_datetime.
tbl_id user_id office_id login_datetime
----------------------------------------
1 2 28 12/28/2012 5:35:50 AM
2 2 15 12/28/2012 5:35:50 AM
3 3 20 12/28/2012 5:35:50 AM
4 4 28 12/28/2012 5:35:50 AM
5 2 28 12/28/2012 5:35:50 AM
6 4 15 12/28/2012 5:35:50 AM
7 3 20 12/28/2012 5:35:50 AM
I tried like :
SELECT user_id as u_id,office_id,
(select login_datetime from tbl t2 where t2.user_id=u_id AND ROWNUM=1 ORDER BY t2.tbl_id DESC ) as LAST_LOGIN
FROM tbl
GROUP BY user_id,office_id
But, its not working for me, any help ?
use Window Function
SELECT tbl_id, user_id, office_id,login_datetime
FROM
(
SELECT tbl_id, user_id, office_id,login_datetime,
ROW_NUMBER() OVER (PARTITION BY user_id, "office_id"
ORDER BY login_datetime DESC) rn
FROM tableName
) a
WHERE a.rn = 1
SQLFiddle Demo
Another sollution is a direct group by with a keep dense rank:
select user_id, office_id,
max(login_datetime) keep (dense_rank first order by login_datetime desc) as latest_login_datetime
from tbl
group by user_id, office_id
or if you want unique user_id:
select user_id,
max(office_id) keep (dense_rank first order by login_datetime desc) as lastest_office_id,
max(login_datetime) keep (dense_rank first order by login_datetime desc) as latest_login_datetime
from tbl
group by user_id
OK, i have changed the example to ORACLE
I will explain the query
First i am selecting a distinct user_id and office id (so if a user belongs to two offices he will returns twice)
and then the MAX login_datetime to get the latest datetime,
Then in the WHERE i am filtering the query by the office_id where it equles to all distinct offices. (basically i am returning a distinct table of office_id)
In the end i am grouping by user_id and office_id because of the MAX function
SELECT
DISTINCT "user_id" ,
"office_id",
MAX("login_datetime")
FROM TableName
WHERE "office_id" IN (SELECT DISTINCT "office_id" FROM TableName)
GROUP BY
"user_id",
"office_id"
SQL Fiddle example
Related
user_id product_id category_id date_added date_update
1 2 1 2.3.2021 null
1 3 1 2.3.2020 2.4.2023
1 4 2 2.3.2020 null
1 5 2 2.3.2020 2.4.2023
2 5 2 2.3.2020 2.4.2023
2 4 1 2.3.2020 null
List the most up-to-date product of each category
You can use row_number()
select * from
(
select *,row_number() over(parition by userid,category_id order by date_update) as rn
from tablename
)A where rn=1
OR you can also use distinct on
select distinct on (user_id,category_id) *
FROM tablename
ORDER BY user_id,category_id, date_update
List the most up-to-date product of each category
You can use distinct on. Let me assume that if the update date is null, then you want the creation date:
select distinct on (category_id) t.*
from t
order by category_id, coalesce(date_update, date_added) desc;
If you wanted this per user/category combination, the logic would be:
select distinct on (user_id, category_id) t.*
from t
order by user_id, category_id, coalesce(date_update, date_added) desc;
Using Window function
select u_id,c_id, p_id, coalesce (date_update, date_added) as date ,
rank () over (partition by u_id, c_id order by coalesce (date_update, date_added) desc) as r
from inventory
) t where r = 1
I have a SQL Query of this:
SELECT
COUNT(PERMISSION_ID) AS USER_TOTAL_PERMISSION_PER_BRANCH,
USER_ID,
BRANCH_ID
FROM BRANCH_PERMISSION_USER
GROUP BY USER_ID, BRANCH_ID
ORDER BY USER_ID, USER_TOTAL_PERMISSION_PER_BRANCH DESC
But I have a problem because I only want the first row per user_id. The main goal is to get the list of user together it's branch and top 1 or the distinct on the USER_TOTAL_PERMISSION_PER_BRANCH
Here is the sample output:
Expected output should be:
[USER_TOTAL_PERMISSION_PER_BRANCH][USER_ID][BRANCH_ID]
135 1 1
135 2 1
134 3 1
1 4 1
1 5 1
1 6 1
You can use window functions:
SELECT USER_TOTAL_PERMISSION_PER_BRANCH, USER_ID, BRANCH_ID
FROM (SELECT COUNT(*) AS USER_TOTAL_PERMISSION_PER_BRANCH,
USER_ID, BRANCH_ID,
ROW_NUMBER() OVER (PARTITION BY USER_ID ORDER BY COUNT(*) DESC) as seqnum
FROM BRANCH_PERMISSION_USER
GROUP BY USER_ID, BRANCH_ID
) ub
WHERE seqnum = 1
You can turn your query to a CTE a do filtering using correlation:
with cte as (
select
count(permission_id) as user_total_permission_per_branch,
user_id,
branch_id
from branch_permission_user
group by user_id, branch_id
)
select c.*
from cte c
where c.user_total_permission_per_branch = (
select max(c1.user_total_permission_per_branch)
from cte c1
where c1.user_id = c.user_id and c1.branch_id = c.branch_id
)
Thanks to Sir #Gordon
I use his logic. Here is it:
SELECT USER_TOTAL_PERMISSION_PER_BRANCH, USER_ID, BRANCH_ID
FROM (SELECT COUNT(*) AS USER_TOTAL_PERMISSION_PER_BRANCH,
USER_ID, BRANCH_ID,
ROW_NUMBER() OVER (PARTITION BY USER_ID ORDER BY COUNT(*) DESC) as seqnum
FROM BRANCH_PERMISSION_USER
GROUP BY USER_ID, BRANCH_ID
) ub
WHERE seqnum = 1
I have a table which contains a lot of duplicated rows like this:
id_emp id date ch_in ch_out
1 34103 2019-09-01
1 34193 2019-09-01 17:00
1 34194 2019-09-02 07:03:21 16:59:26
1 34104 2019-09-02 07:03:21 16:59:26
1 33361 2019-09-02 NULL NULL
I want just one row for each date and others must delete with condition like I want the output must be:
id_emp id date ch_in ch_out
1 34193 2019-09-01 17:00
1 34104 2019-09-02 07:03:21 16:59:26
I tried to use distinct but nothing working:
select distinct id_emp, id, date_1, ch_in,ch_out
from ch_inout
where id_emp=1 order by date_1 asc
And I tried too using this query to delete:
select *
from (
select *, rn=row_number() over (partition by date_1 order by id)
from ch_inout
) x
where rn > 1;
But nothing is working the result is empty.
You can use aggregation:
select id_emp, max(id) as id, date, min(ch_in), max(ch_out)
from ch_inout
group by id_emp, date;
This returns the maximum id for each group of rows. That is not exactly what is returned in the question, but you don't specify the logic.
EDIT:
If you want to delete all but the largest id for each id_emp/date combination, you can use:
delete c from ch_inout c
where id < (select max(c2.id)
from ch_inout c2
where c2.id_emp = c.id_emp and c2.date = c.date
);
You can use ROW_NUMBER() to identify the records you want to delete. Assuming that you want to keep the record with the lowest id on each date:
SELECT *
FROM (
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY date ORDER BY id) rn
FROM ch_inout t
) x
WHERE rn > 1
You can easily turn this into a DELETE statement:
WITH cte AS (
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY date ORDER BY id) rn
FROM ch_inout t
)
DELETE FROM cte WHERE rn > 1
This seems something simple, but couldn't find an answer for this question last few hours.
I have a table request_state, where "id" is primary key, it can have multiple entries with same state_id. I want to get the id after grouping by state_id using max datetime.
So I tried this, but it gives error "state_id" must appear in the GROUP BY clause or be used in an aggregate function
select id, state_id, max(datetime)
from request_state
group by id
but when I use following query, I get multiple entries with same state_id.
select id, state_id, max(datetime)
from request_state
group by id, state_id
My table:
id state_id date_time
cef 1 Jan 1
ter 1 Jan 2
ijk 1 Jan 3
uuu 2 Feb 1
rrr 2 Feb 2
This is what I want as my result,
id state_id date_time
__ ________ _________
ijk 1 Jan 3
rrr 2 Feb 2
You seem to want:
select max(id) as id, state_id, max(datetime)
from request_state
group by state_id;
If you want the row where datetime is maximum for each state, then use distinct on:
select distinct on (state) rs.*
from request_state rs
order by state, datetime desc;
Try this query:
select id, state_id, date_time from (
select id, state_id, date_time,
row_number() over (partition by state_id order by date_time desc) rn
from tbl
) a where rn = 1
You can use correlated suqbuery :
select t.*
from table t
where date_time = (select max(date_time) from table t1 where t1.state_id = t.state_id);
The question is: For each day, list the User ID who has read the most number of messages.
user_id msgID read_date
1 1 10
1 2 10
2 2 10
2 2 23
3 2 23
I believe the date is an outer group and user_id is an inner group, but how to do group nesting in sql? Or somehow avoid this?
This is a task for a Window Function:
select *
from
(
select user_id, read_date, count(*) as cnt,
rank()
over (partition by read_date -- each day
order by count(*) desc) as rnk -- maximum number
from tab
group by user_id, read_date
) dt
where rnk = 1
This might return multiple users for one with the same maximum count, if you want just one (randomly) switch to ROW_NUMBER
select user_id
from
(
select user_id,count(msgID)
from table
group by read_date
)
where rownum <= 1;