Simple query in sql through aggregate function and group by clause - sql

I have a table like the picture bellow and I need to extract the id,name and date of the max datetime that has been grouped by the name.
I can get the max datetime through this query:
SELECT MAX(Table.Date),Table.name FROM Table GROUP BY Table.name
and the result is:
To extract the information of max datetime that has been grouped by the name, I've had this query:
SELECT t1.name, t1.Date, t1.id
FROM Table t1
WHERE t1.Date in (SELECT MAX(t2.Date)
FROM Table t2
GROUP BY t2.name)
the result is:
but do not need the highlighted data. because between 'D's the 2014-01-12 has the max date.
NOTE: I can solve the problem through JOIN expression.
but because of saving time I need a simple query.

You could use row-number, partition by
Select * from
(Select *,rn=row_number()over(partition by name order by date desc) from table) x
Where x.rn = 1;

Related

Foreach/per-item iteration in SQL

I'm new to SQL and I think I must just be missing something, but I can't find any resources on how to do the following:
I have a table with three relevant columns: id, creation_date, latest_id. latest_id refers to the id of another entry (a newer revision).
For each entry, I would like to find the min creation date of all entries with latest_id = this.id. How do I perform this type of iteration in SQL / reference the value of the current row in an iteration?
select
t.id, min(t2.creation_date) as min_creation_date
from
mytable t
left join
mytable t2 on t2.latest_id = t.id
group by
t.id
You could solve this with a loop, but it's not anywhere close the best strategy. Instead, try this:
SELECT tf.id, tf.Creation_Date
FROM
(
SELECT t0.id, t1.Creation_Date,
row_number() over (partition by t0.id order by t1.creation_date) rn
FROM [MyTable] t0 -- table prime
INNER JOIN [MyTable] t1 ON t1.latest_id = t0.id -- table 1
) tf -- table final
WHERE tf.rn = 1
This connects the id to the latest_id by joining the table to itself. Then it uses a windowing function to help identify the smallest Creation_Date for each match.

SQL - Summarize column with maximum date value and other fields

I have a table with the following fields:
Id|Date|Name
---------------
A|2019-04-24|"VALUE1"
A|2019-04-23|"VALUE2"
A|2019-06-11|"VALUE3"
A|2019-06-12|"VALUE4"
B|2019-05-21|"VALUE5"
B|2019-05-22|"VALUE6"
B|2019-03-13|"VALUE7"
C|2019-01-03|"VALUE8"
I would like to get one line per Id having the info of the maximum date line. This would be the output:
Id|Date|Name
---------------
A|2019-06-12|"VALUE4"
B|2019-05-22|"VALUE6"
C|2019-01-03|"VALUE8"
I have achieved through a group by getting the Id and the MAX Date, but not the value associated to that date.
What I am working on now is to inner join that table with the input one joining it on date and id, but I am not able to join on two fields.
Is there any way to bring to the result the value field related to the max date in the group by clause?
Otherwise, How could I join on two different fields those two tables?
Any Suggestion?
Thank you so much!!
You can use a correlated subquery :
select t.*
from table t
where t.date = (select max(t1.date) from table t1 where t1.id = t.id);
However, Most of DBMS supports analytical functions, so you can use :
select t.*
from (select t.*, row_number() over (partition by t.id order by t.date desc) as seq
from table t
) t
where seq = 1;

Get the latest date based on another column

I have a dataset that includes a column DATETIME and a column BANKCASENUMBER. I want to select the rows with the latest dates for each BANKCASENUMBER.
This is what I've tried:
PROC SQL;
CREATE TABLE WORK.QUERY_FOR_WORK_QUERY_FOR_ACCOUNT AS
ORDER BY t1.DATETIME LIMIT 1
SELECT t1.LOGINNAME,
t1.FORENAME,
t1.SURNAME,
t1.BANKCASENUMBER,
MAX(t1.DATETIME),
t1.'Inbound/outbound'n,
t1.'succesvol?'n
FROM WORK.WORK_QUERY_FOR_ACCOUNTACTIVITIES t1
GROUP BY t1.BANKCASENUMBER;
QUIT;
The returned table should givall the rows with the latset DATETIME for each BANKCASENUMBER. So each BANKCASENUMBER should appear once.
I believe this is what you're looking for. The idea is to get the latest timestamp for each bank case number in a subquery, and join it to your main table.
PROC SQL;
CREATE TABLE WORK.QUERY_FOR_WORK_QUERY_FOR_ACCOUNT AS
SELECT t1.LOGINNAME,
t1.FORENAME,
t1.SURNAME,
t1.BANKCASENUMBER,
t1.DATETIME,
t1.'Inbound/outbound'n,
t1.'succesvol?'n
FROM WORK.WORK_QUERY_FOR_ACCOUNTACTIVITIES t1
JOIN (
SELECT t2.bankCaseNumber,
MAX(t2.dateTime) as maxDateTime
FROM WORK.WORK_QUERY_FOR_ACCOUNTACTIVITIES t2
GROUP BY t2.BANKCASENUMBER
) m
ON m.bankCaseNumber = t1.bankCaseNumber
AND t1.dateTime = m.maxDateTime
;
QUIT;
this seems a little simpler. Since we are grouping by LOGINNAME the having statement will refer to the max(DATETIME) within each group
proc sql noprint;
create table QUERY_FOR_WORK_QUERY_FOR_ACCOUNT as
select * from WORK_QUERY_FOR_ACCOUNTACTIVITIES
group by LOGINNAME
having DATETIME = max(DATETIME);
quit;

SQL - group by, keep earliest row

I have following table:
name team date
-----------------------------------
John A-team 02-5-2014
Jessica A-team 08-6-2015
David A-team 11-2-2013
Bill B-team 12-5-2017
Nicole B-team 18-1-2010
Brandom B-team 22-9-2012
I am trying to create a query which does:
one row per team, so we groupe on the team
select that row which happened first, so we are aggregating on min(date)
The following query give the team and the date:
select team, min(date)
from my_table
group by team
But how can I also retrieve the name? I tried following query, but now I get all rows (which I understand, because the grouping does nothing, as all rows are unique now):
select name, team, min(date)
from my_table
group by team, name
Do a self join, where you use your first query as sub-query to find each team's first date:
select t1.*
from my_table t1
join
(select team, min(date) min_date
from my_table
group by team) t2 on t1.team = t2.team and t1.date = t2.min_date
Will return both names if there are two names on a team's first date.
If you just want one row per team, even if that date has two name, you can do another GROUP BY, or simply NOT EXISTS:
select t1.*
from my_table t1
where not exists (select 1 from my_table t2
where t2.team = t1.team
and (t2.date < t1.date
or (t2.date = t1.date and t2.name < t1.name))
SELECT min(NAME)
,team
,min(DATE)
FROM my_table
GROUP BY team

Date of max id: sql/oracle optimization

What is a more elegant way of doing this:
select date from table where id in (
select max(id) from table);
Surely there is a better way...
You can use the ROWNUM pseudocolumn. The subquery is necessary to order the result before finding the first row:
SELECT date
FROM (SELECT * FROM table ORDER BY id DESC)
WHERE ROWNUM = 1;
You can use subquery factoring in Oracle 9i and later in the following way:
WITH ranked_table AS (
SELECT ROWNUM AS rn, date
FROM table
ORDER BY id DESC
)
SELECT date FROM ranked_table WHERE rn = 1;
You can use a self-join, and find where no row exists with a greater id:
SELECT date
FROM table t1
LEFT OUTER JOIN table t2
ON t1.id < t2.id
WHERE t2.id IS NULL;
Which solution is best depends on the indexes in your table, and the volume and distribution of your data. You should test each solution to determine what works best, is fastest, is most flexible for your needs, etc.
select date from (select date from table order by id desc)
where rownum < 2
assuming your ids are unique.
EDIT: using subquery + rownum