Pulling all ID with the latest date - sql

Say I have multiple columns and three different rows. I want to pull the all the ID with the latest date 20220205 (for Ann) and 20220208 (for Lima) to get the correct package code. How do I code it out in the where statement?
ID
Name
pkg_date
package
11
Ann
20220205
R
11
Ann
20220101
A
11
Ann
20211101
U
22
Lima
20210708
B
22
Lima
20220208
A

You can use one of the rank-related window functions (rank, dense_rank, or row_number). Here is an example which uses dense_rank function.
SELECT *
FROM (
select id,
name,
pkg_date,
package,
dense_rank() OVER(PARTITION BY id ORDER BY pkg_date DESC) rk
from table_name) t
WHERE rk = 1

You can use an inner join with the max date:
SELECT ID, NAME, PKG_DATE, PACKAGE
FROM table t INNER JOIN
(SELECT max(PKG_DATE), ID, NAME FROM table GROUP BY ID, NANE) i
on i.ID = t.ID;

Try the new MAX_BY function:
select
id
, name
, max_by(package, pkg_date) as latest_pkg_code
from test_table
group by 1,2;
Result:
ID
NAME
LATEST_PKG_CODE
11
Ann
R
22
Lima
A
Here is a sample script:
-- create table
create or replace transient table test_table (
id int
, name varchar(50)
, pkg_date date
, package varchar(1)
);
-- insert data
insert into test_table
values
(11,'Ann','2022-02-05','R')
,(11,'Ann','2022-01-01','A')
,(11,'Ann','2021-11-01','U')
,(22,'Lima','2021-07-08','B')
,(22,'Lima','2022-02-08','A');
-- test table
select * from test_table;
-- get package code for max date for each name/id
select
id
, name
, max_by(package, pkg_date) as latest_pkg_code
from test_table
group by 1,2;

Related

SQL find the 2 highest score for each country

I have two tables: maps_query and map_time like below:
CREATE TABLE maps_query (
id int
day varchar
search_query varchar
country varchar
query_score int
)
CREATE TABLE map_time (
id int
am_pm varchar
)
The question is to find the 2 highest score for each country. Desired output is like below:
country search_query query_score
CA Target 1000
CA Store 900
FR Eiffiel 1500
FR London 800
I was trying to use row_number() over but don't know how to complete the query.
Select t1.country, t1.search_query, t1.score_rank,
from (select *, (row_number() over(partition by country order by query_score) as score_rank from maps_search) t1
where score_rank = 1 and score_rank=2
This can be achieved by rank() instead of row_number().
select
*
from
(
select
*,
rank() over (
PARTITION by country
order by
query_score desc
)
from
maps_query
) q
where
rank <= 2;
A good reference article: https://spin.atomicobject.com/2016/03/12/select-top-n-per-group-postgresql/

function that allows grouping of rows

I'm using SQL Server Management Studio 2012. I have a similar looking output from a query shown below. I want to eliminate someone from the query who has 2 contracts.
Select
Row_Number() over (partition by ID ORDER BY ContractypeDescription DESC) as [Row_Number],
Name,
ContractDescription,
Role
From table
Output
Row_Number ID Name Contract Description Role
1 1234 Mike FullTime Admin
2 1234 Mike Temp Manager
1 5678 Dave FullTime Admin
1 9785 Liz FullTime Admin
What I would like to see
Row_Number ID Name Contract Description Role
1 5678 Dave FullTime Admin
1 9785 Liz FullTime Admin
Is there a function rather than Row_Number that allows you to group rows together so I can then use something like 'where Row_Number not like 1 and 2'?
You can use HAVING as
SELECT ID,
MAX(Name) Name,
MAX(ContractDescription) ContractDescription,
MAX(Role) Role
FROM t
GROUP BY ID
HAVING COUNT(*) = 1;
Demo
Try this:
select * from (
Select
Count(*) over (partition by ID ) as [Row_Number],
Name,
ContractDescription,
Role
From table
)t where [Row_Number] = 1
You can check this option-
SELECT *
FROM table
WHERE ID IN
(
SELECT ID
FROM table
GROUP BY ID
HAVING COUNT(*) = 1
)
You can use a CTE to get all the ids of people who got only one contract and then just join the result of the CTE with your table.
;with cte as (
select
id
,COUNT(id) as no
from #tbl
group by id
having COUNT(id) = 1
)
select
t.id
,t.name
,t.ContractDescription
,t.role
from #tbl t
inner join cte
on t.id = cte.id
Basically you need those record who have exactly one contract.
Just extend your script, (My script is not tested)
;with CTE as
(
Select
Row_Number() over (partition by ID ORDER BY ContractypeDescription DESC) as [Row_Number],
Name,
ContractDescription,
Role
From table
)
select * from CTE c where [Row_Number]=1
and not exists(select 1 from CTE c1 where c.id=c1.id and c1.[Row_Number]>1 )
Is there a function rather than Row_Number that allows you to group
rows together so I can then use something like 'where Row_Number not
like 1 and 2'?
You can use a windowed COUNT(). The key is the OVER() clause.
;WITH WindowedCount AS
(
SELECT
T.*,
WindowCount = COUNT(1) OVER (PARTITION BY T.ID)
FROM
YourTable AS T
)
DELETE W FROM
WindowedCount AS W
WHERE
W.WindowCount > 1
The COUNT() will count the amount of rows for each different ID, so if the same ID appears in 2 or more rows, those rows will be deleted.

Group by with MIN value in same query while presnting all other columns

I have a view called a with this data:
ID tDate name task val
23 2015-06-14
23 2015-06-25
126 2015-06-18
126 2015-06-22
126 2015-06-24
ID is integer and tDate is timestamp.
Basically I want to get for each ID the min value of tDate and present this row.
meaning:
ID tDate name task val
23 2015-06-14
126 2015-06-18
I wrote this query:
select ID, min(tDate)
from a
group by ID
order by ID
This is working BUT it doesn't allow me to present all other columns of a
for example if I do:
select ID, min(tDate), name
from a
group by ID
order by ID
it says that name must be under group by. So I wrote this query:
select ID, MIN(tDate), name, task, val , ....
from a
group by ID, name, task, val , ....
order by ID
And this one doesn't work. it gives false results.
How do I solve it?
Postgres has the very convenient distinct on for this type of problem:
select distinct on (id) a.*
from a
order by id, tdate;
This will return one row for each id. The row is the first one determined by the ordering defined in the order by clause.
Do a join from the one table to a sub-query table on just the ID / Min Date
select
YT.ID,
YT.tDate as OriginalDate,
PQ.MinDate,
YT.name,
YT.task,
YT.val
from
YourTable YT
JOIN ( select ID, min( tdate ) as MinDate
from YourTable
group by ID ) as PQ
on YT.ID = PQ.ID
AND YT.tDate = PQ.MinDate
order by
ID
Try something like this:
select a.id, a.tdate , .... from a
join (select id, min(tdate) min_date
from a
group by ID
) b
on a.id=b.id and a.tdate = b.min_date
order by a.id

SQL select latest record of particular student with particular status

Please help me to select latest record of each student with status=1. I have a table called stdData and columns
Student ID FDate Status
12 2014-03-12 1
12 2014-03-15 1
13 2014-02-03 1
13 2014-02-04 0
13 2014-02-05 1
How can I select latest record of each student with status=1?
You need to use group by
select student_id, max(date)
from table_name
where status=1
group by student_id;
fiddle
if you are using sql server then try this
Select top(1) * from StudentTable where status =1 order by student_id desc
In this query it is clear that status = 1 there for i add it in my select, like this:
Select Student_ID ,max(Date) Date, 1 status From table1
where status = 1 Group by Student_ID;
SQL Fiddle
In Sqlserver
Create table Student(
ID int identity(1,1) primary key not null,
S_Date datetime,
Status bit
)
insert into Student values ('2014-03-11',1)
insert into Student values ('2014-03-12',0)
insert into Student values ('2014-03-13',1)
insert into Student values ('2014-03-14',0)
insert into Student values ('2014-03-15',1)
select top 1 * from Student where Status=1 Order By S_Date Desc
You can use ROW_NUMBER function to achieve this:
SELECT Student_ID, Date , Status
FROM
(
SELECT ROW_NUMBER() OVER (PARTITION BY Student_ID ORDER BY Date DESC) AS rn, Student_ID, Date , Status
FROM your_table
WHERE Status = 1
) tab
WHERE tab.rn = 1
try this !
;with cte as
(
select *,rn=row_number() over(partition by Student_Id order by Date desc) from #t
)
select * from cte where rn=1 and status=1
SEE DEMO
try this !
SELECT LAST(column_name) FROM table_name;

SQL query to return only 1 record per group ID

I'm looking for a way to handle the following scenario. I have a database table that I need to return only one record for each "group id" that is contained within the table, furthermore the record that is selected within each group should be the oldest person in the household.
ID Group ID Name Age
1 134 John Bowers 37
2 134 Kerri Bowers 33
3 135 John Bowers 44
4 135 Shannon Bowers 42
So in the sample data provided above I would need ID 1 and 3 returned, as they are the oldest people within each group id.
This is being queried against a SQL Server 2005 database.
SELECT t.*
FROM (
SELECT DISTINCT groupid
FROM mytable
) mo
CROSS APPLY
(
SELECT TOP 1 *
FROM mytable mi
WHERE mi.groupid = mo.groupid
ORDER BY
age DESC
) t
or this:
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY groupid ORDER BY age DESC) rn
FROM mytable
) x
WHERE x.rn = 1
This will return at most one record per group even in case of ties.
See this article in my blog for performance comparisons of both methods:
SQL Server: Selecting records holding group-wise maximum
Use:
SELECT DISTINCT
t.groupid,
t.name
FROM TABLE t
JOIN (SELECT t.groupid,
MAX(t.age) 'max_age'
FROM TABLE t
GROUP BY t.groupid) x ON x.groupid = t.groupid
AND x.max_age = t.age
So what if there's 2+ people with the same age for a group? It'd be better to store the birthdate rather than age - you can always calculate the age for presentation.
Try this (assuming Group is synonym for Household)
Select * From Table t
Where Age = (Select Max(Age)
From Table
Where GroupId = t.GroupId)
If there are two or more "oldest" people in some household (They all are the same age and there is noone else older), then this will return all of them, not just one at random.
If this is an issue, then you need to add another subquery to return an arbitrary key value for one person in that set.
Select * From Table t
Where Id =
(Select Max(Id) Fom Table
Where GroupId = t.GroupId
And Age =
(Select(Max(Age) From Table
Where GroupId = t.GroupId))
SELECT GroupID, Name, Age
FROM table
INNER JOIN
(
SELECT GroupID, MAX(Age) AS OLDEST
FROM table
) AS OLDESTPEOPLE
ON
table.GroupID = OLDESTPEOPLE.GroupID
AND
table.Age = OLDESTPEOPLE.OLDEST
SELECT GroupID, Name, Age
FROM table
INNER JOIN
(
SELECT GroupID, MAX(Age) AS OLDEST
FROM table
**GROUP BY GroupID**
) AS OLDESTPEOPLE
ON
table.GroupID = OLDESTPEOPLE.GroupID
AND
table.Age = OLDESTPEOPLE.OLDEST