SQL MAX Query Multiple Columns - sql

Trying to populate multiple columns based on one MAX value but the grouping returns multiple results. Is there a way I can tell SQL to only pull the values based on the MAX that I want?
Query:
Select a.ID, (MAX)a.PayDate, a.AgencyName
From a
Group By a.ID, a.AgencyName
What I need is the latest paydate per ID, then I want additional information in reference to that entry such as AgencyName (& more columns I want to add) but because of the grouping - SQL returns the latest paydate for each of the AgencyNames that the person has had - but I only want the AgencyName associated with the record that is Max Paydate for that ID. I know it's the grouping that does this but I am unsure how to proceed - any help greatly appreciated.
Thanks

Select a.ID,a.PayDate, a.AgencyName
From a
where exists (select 1 from a a1 where a1.id = a.id
having a.payDate = max(a1.paydate)
Group By a.ID,

I would just use a correlated subquery like this:
select a.*
from a
where a.paydate = (select max(a2.paydate) from a a2 where a2.id = a.id);
Note that this could return multiple rows if an id has duplicates on the most recent paydate. An alternative that guarantees one row is row_number():
select a.*
from (select a.*,
row_number() over (partition by id order by paydate desc) as seqnum
from a
) a
where seqnum = 1;

Related

Listing multiple columns in a single row in SQL

(select ID,EXTERNAL_TRANSACTION_ID,EXTERNAL_TRANSACTION_TYPE,ROW_NUMBER() OVER(PARTITION BY EXTERNAL_TRANSACTION_ID ORDER BY ID ) AS SEQNUM
from AC_POS_TRANSACTION_TRK aptt WHERE [RESULT] ='Success'
GROUP BY ID, EXTERNAL_TRANSACTION_ID,EXTERNAL_TRANSACTION_TYPE )
Hello,
On above query, I want to get rows of transaction id's which has seqnum=1 and seqnum=2
But if that transaction id has no second row (seqnum=2), I dont want to get any row for that transaction id.
Thanks!!
Something like this
Not 100% sure if this is correct without you table definition, but my understanding is that you want to EXCLUDE records if that record has an entry with seqnum=2 -- you can't use a where clause alone because that would still return seqnum = 1.
You can use an exists /not exists or in/not in clause like this
(select ID,EXTERNAL_TRANSACTION_ID,EXTERNAL_TRANSACTION_TYPE,ROW_NUMBER() OVER(PARTITION BY EXTERNAL_TRANSACTION_ID ORDER BY ID ) AS SEQNUM
from AC_POS_TRANSACTION_TRK aptt WHERE [RESULT] ='Success'
and not exists ( select 1 from AC_POS_TRANSACTION_TRK a where a.id = aptt.id
and a.seqnum = 2)
GROUP BY ID, EXTERNAL_TRANSACTION_ID,EXTERNAL_TRANSACTION_TYPE )
basically what this does is it excludes records if a record exists as specified in the NOT EXISTS query.
One option you can try is to add a count of rows per group using the same partioning critera and then filter accordingly. Not entirely sure about your query without seeing it in context and with sample data - there's no aggregation so why use group by?
However can you try something along these lines
select * from (
select ID,EXTERNAL_TRANSACTION_ID,EXTERNAL_TRANSACTION_TYPE,
Row_Number() over(partition by EXTERNAL_TRANSACTION_ID order by ID) as SEQNUM,
Count(*) over(partition by EXTERNAL_TRANSACTION_ID) Qty
from AC_POS_TRANSACTION_TRK
where [RESULT] ='Success'
)x
where SEQNUM in (1,2) and Qty>1
This should do the job.
With Qry As (
-- Your original query goes here
),
Select Qry.*
From Qry
Where Exists (
Select *
From Qry Qry1
Where Qry1.EXTERNAL_TRANSACTION_ID = Qry.EXTERNAL_TRANSACTION_ID
And Qry1.SEQNUM = 1
)
And Exists (
Select *
From Qry Qry2
Where Qry2.EXTERNAL_TRANSACTION_ID = Qry.EXTERNAL_TRANSACTION_ID
And Qry2.SEQNUM = 2
)
BTW, your original query looks problematic to me, specifically I think that instead of a GROUP BY columns those columns should be in the PARTITION BY clause of the OVER statement, but without knowing more about the table structures and what you're trying to achieve, I could not say for sure.

How to filter records based on a criteria per group

In SQL how can I express this question: For all groups, return all records in a group that match the result of a condition specific to the group.
For example:
Book: (Id, Title, AuthorName, PublishDate)
Return all records in Book table that if the books are grouped by the AuthorName, they are the fifth or later books of that specific author.
I'm using MS SQL Server 2016.
The solution to this is basically the same as Get top 1 row of each group, however, instead of = 1 you want >=5:
WITH CTE AS(
SELECT {Columns}
ROW_NUMBER() OVER (PARTITION BY Author ORDER By PublishDate) AS RN
FROM dbo.YourTable)
SELECT {Columns
FROM CTE
WHERE RN >= 5;
You can also use a correlated subquery for this:
select t.*
from t
where t.publishdate >= (select t2.publishdate
from t t2
where t2.author = t.author
order by t2.publishdate asc
offset 4 fetch first 1 row only
);

Get the difference of unique elements of a flag-based ID in SQL

I have an SQL table from which I want to extract unique elements by ID, comparing different groups, for example :
ID,Group,Product
a,2,33
a,1,83
b,3,51
c,2,33
b,1,20
a,3,20
b,2,51
a,2,83
If I have two products equals in different groups for the same ID, then I don't save them. Resulting this:
ID,Group,Unique
a,2,33
c,2,33
b,1,20
a,3,20
I'm trying this in SQL, but I don't know how to do it, please help me!
Remove all rows that have the same product and different groups:
select *
from yourtable a
where not exists(
select 1 from yourtable b where a.Product = b.Product and a.Group <> b.Group
)
select * from table_1
qualify count("product") over(partition by "group")=1
One method is aggregation:
select id, max(group) as group, product
from t
group by id, product
having min(group) = max(group);

how to get latest date column records when result should be filtered with unique column name in sql?

I have table as below:
I want write a sql query to get output as below:
the query should select all the records from the table but, when multiple records have same Id column value then it should take only one record having latest Date.
E.g., Here Rudolf id 1211 is present three times in input---in output only one Rudolf record having date 06-12-2010 is selected. same thing with James.
I tried to write a query but it was not succssful. So, please help me to form a query string in sql.
Thanks in advance
You can partition your data over Date Desc and get the first row of each partition
SELECT A.Id, A.Name, A.Place, A.Date FROM (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Date DESC) AS rn
FROM [Table]
) A WHERE A.rn = 1
you can use WITH TIES
select top 1 PERCENT WITH TIES * from t
order by (row_number() over(partition by id order by date desc))
https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=280b7412b5c0c04c208f2914b44c7ce3
As i can see from your example, duplicate rows differ only in Date. If it's a case, then simple GROUP BY with MAX aggregate function will do the job for you.
SELECT Id, Name, Place, MAX(Date)
FROM [TABLE_NAME]
GROUP BY Id, Name, Place
Here is working example: http://sqlfiddle.com/#!18/7025e/2

Nested SQL Server Query Max Date

Ladies and Gents,
I need to write a query that grabs data from a view, but I'm not sure how to go about this. The issue is there is really no key and there are two fields I'm concerned with that will control what rows I need to retrieve.
The view looks something like this:
Category columna columnb uploaddate
-----------------------------------------------------
a value value 1/30/2013 04:04:04:000
a value value 1/29/2013 04:04:04:000
b value value 1/28/2013 01:23:04:000
b value value 1/30/2013 04:04:04:000
b value value 1/30/2013 04:04:04:000
c value value 1/30/2013 01:01:01:000
c value value 1/30/2013 01:01:01:000
What I need to retrieve is all rows for each unique category and the newest uploaddate. So in the example above I would get 1 row for category a which would have the newest uploaddate. Category b would have 2 rows which have the 1/30/2013 date. Category c would have two rows also.
I also need to just compare the date of upload, not the time. As the loading can take a couple seconds. I was trying to use max date but it would only grab the time to the second.
Any guidance/thoughts would be great.
Thanks!
EDIT:
Here is what I threw together so far and I think it's close but it's not working yet and I doubt this is the most efficient way to do this.
select
*
from
VIEW c
INNER JOIN
(
SELECT
Category,
MAX(CONVERT(DateTime, Convert(VarChar, UploadDate, 101))) as maxuploaddate
FROM
View
GROUP BY
Category,
UploadDate
) temp ON temp.Category = c.Category AND CONVERT(VarChar, UploadDate, 101) = temp.maxuploaddate
The problem lies in the nested selected statement as it's still grabbing all combinations of Category and Upload date. Is there a way to do a distinct on the Category and UploadDate, just getting the newest combination?
Thanks Again
Your query is close, you have a mistake in the group by. I'd also get rid of the date conversions; date comparisons work fine.
select
*
from
VIEW c
INNER JOIN
(
SELECT
Category,
MAX(UploadDate) as maxuploaddate
FROM
View
GROUP BY
Category
) temp ON temp.Category = c.Category AND UploadDate = temp.maxuploaddate
If you want to do this to the nearest date, you need to convert to a date first. In SQL Server syntax:
select *
from (select category, columna, columnb, uploaddate,
rank() over ( partition by category order by cast(uploaddate as date) desc) as seqnum
from view
) v
where seqnum = 1
In Oracle syntax:
select *
from (select category, columna, columnb, uploaddate,
rank() over ( partition by category order by to_char(uploaddate, 'YYYY-MM-DD') desc) as seqnum
from view
) v
where seqnum = 1
Because you want ties, these use rank() instead of row_number().
In Oracle you can use Rank() to achieve this. Rank() creates a duplicate number if the same criteria are met.
Edit: And you can use Trunc() to "trim" the time from the uploaddate.
select *
from (select category, columna, columnb, uploaddate,
rank() over ( partition by category order by trunc(uploaddate) desc) rank
from view)
where rank = 1
Also Dense_Rank() exists, which won't create duplicate numbers. So this is not applicable here. See this question for more info on the differences.