Select records based on Id and most updated record of the same Id - sql

I have a table Applications
The user can submit more than one application. The user can also update an existing application, but instead of updating the record itself, we will insert a new record with the same ApplicationNumber
Id ApplicationNum ApplicantId ApplicantName CreateDate
1 101 789 John May-20-2021
2 101 789 John May-21-2021
3 102 789 John May-22-2021
4 103 123 Maria May-31-2021
I want to return the list of applications based on the ApplicantId, but I don’t want to display both records of the same ApplicationNumber
If I use this select statement
Select * from Applications where ApplicantId = 789
This is the result I currently get
1 101 789 John May-20-2021
2 101 789 John May-21-2021
3 102 789 John May-22-2021
This is the result I want to get
2 101 789 John May-21-2021
3 102 789 John May-22-2021
Notice that record Id = 1 is not displayed because it is an old version of record Id = 2
How can I achieve this?

I like using ROW_NUMBER along with a TIES trick here:
SELECT TOP 1 WITH TIES *
FROM Applications
WHERE ApplicantId = 789
ORDER BY ROW_NUMBER() OVER (PARTITION BY ApplicantId, ApplicationNum ORDER BY Id DESC);

Might be easier to just use:
select max(Id) as Id, ApplicationNum, ApplicantId, ApplicantName, max(CreateDate) as CreateDate
from Applications
where ApplicantId = 789
group by ApplicationNum, ApplicantId, ApplicantName

The traditional way which is usually the most performant is to use row_number and select the desired row from each group of Applicants
select Id, ApplicationNum, ApplicantId, ApplicantName, CreateDate
from (
select *, Row_Number() over(partition by ApplicantId, ApplicationNum order by Id desc) rn
from Applications
where ApplicantId=789
)a
where rn=1

Related

How to query: "for which do these values apply"?

I'm trying to match and align data, or resaid, count occurrences and then list for which values those occurrences occur.
Or, in a question: "How many times does each ID value occur, and for what names?"
For example, with this input
Name ID
-------------
jim 123
jim 234
jim 345
john 123
john 345
jane 234
jane 345
jan 45678
I want the output to be:
count ID name name name
------------------------------------
3 345 jim john jane
2 123 jim john
2 234 jim jane
1 45678 jan
Or similarly, the input could be (noticing that the ID values are not aligned),
jim john jane jan
----------------------------
123 345 234 45678
234 123 345
345
but that seems to complicate things.
As close as I am to the desired results is in SQL, as
for ID, count(ID)
from table
group by (ID)
order by count desc
which outputs
ID count
------------
345 3
123 2
234 2
45678 1
I'll appreciate help.
You seem to want a pivot. In SQL, you have to specify the number of columns in advance (unless you construct the query as a string).
But the idea is:
select ID, count(*) as cnt,
max(case when seqnum = 1 then name end) as name_1,
max(case when seqnum = 2 then name end) as name_2,
max(case when seqnum = 3 then name end) as name_3
from (select t.*,
row_number() over (partition by id order by id) as seqnum -- arbitrary ordering
from table t
) t
group by ID
order by count desc;
If you have an unknown number of columns, you can aggregate the values into an array:
select ID, count(*) as cnt,
array_agg(name order by name) as names
from table t
group by ID
order by count desc
the query would look similar to this if that's what you're looking for.
SELECT
name,
id,
COUNT(id) as count
FROM
dataSet
WHERE
dataSet.name = 'input'
AND dataSet.id = 'input'
GROUP BY
name,
id

sql that identifies which account numbers have multiple agents

I dont think a count will work here, can someone help me get an sql that identifies which account numbers have multiple agents, more than two agents in the where condition.
AGENT_NAME ACCOUNT_NUMBER
Clemons, Tony 123
Cipollo, Michael 123
Jepsen, Sarah 567
Joanos, James 567
McMahon, Brian 890
Novak, Jason 437
Ralph, Melissa 197
Reitwiesner, John 221
Roman, Marlo 123
Rosenzweig, Marcie 890
Results should be something like this.
ACCOUNT_NUMBER AGENT_NAME
123 Cipollo, Michael
123 Roman, Marlo
123 Clemons, Tony
890 Rosenzweig, Marcie
890 McMahon, Brian
567 Joanos, James
567 Jepsen, Sarah
You can do this using window functions:
select t.account_number, t.agent_name
from (select t.*, min(agent_name) over (partition by account_number) as minan,
max(agent_name) over (partition by account_number) as maxan
from table t
) t
where minan <> maxan;
If you know the agent names are never duplicated, you could just do:
select t.account_number, t.agent_name
from (select t.*, count(*) over (partition by account_number) as cnt
from table t
) t
where cnt > 1;
Assuming your table name is test, this should pull all the records with duplicate ACCOUNT_NUMBER:
select * from test where ACCOUNT_NUMBER in
(select ACCOUNT_NUMBER from test
group by ACCOUNT_NUMBER having
count(ACCOUNT_NUMBER)>1)
order by ACCOUNT_NUMBER
Using count function u can get the result
CREATE TABLE #TEMP
(
AGENT_NAME VARCHAR(100),
ACCOUNT_NUMBER INT
)
INSERT INTO #TEMP
VALUES ('CLEMONS, TONY',123),
('CIPOLLO, MICHAEL',123),
('JEPSEN, SARAH',567),
('JOANOS, JAMES',567),
('MCMAHON, BRIAN',890),
('NOVAK, JASON',437),
('RALPH, MELISSA',197),
('REITWIESNER, JOHN',221),
('ROMAN, MARLO',123),
('ROSENZWEIG, MARCIE',890)
SELECT a.ACCOUNT_NUMBER,a.AGENT_NAME
FROM #TEMP A
JOIN(SELECT COUNT(1) CNT,
ACCOUNT_NUMBER
FROM #TEMP
GROUP BY ACCOUNT_NUMBER) B
ON A.ACCOUNT_NUMBER = B.ACCOUNT_NUMBER
WHERE B.CNT != 1

SQL Query to return the difference between records of two most recent dates

I have the following table:
**TABLE1**
RecordID UserID UserName Balance TranDate
---------------------------------------------------------------
100 10001 John Doe 10213.00 2013-02-12 00:00:00.000
101 10001 John Doe 1932.00 2013-04-30 00:00:00.000
102 10001 John Doe 10213.00 2013-03-25 00:00:00.000
103 10001 John Doe 14514.00 2013-04-12 00:00:00.000
104 10001 John Doe 5430.00 2013-02-19 00:00:00.000
105 10001 John Doe 21242.00 2010-02-11 00:00:00.000
106 10001 John Doe 13342.00 2013-05-22 00:00:00.000
Now what i'm trying to do is to query the two most recent transactions and arrive at this data:
RecordID UserID UserName Balance TranDate
---------------------------------------------------------------
106 10001 John Doe 13342.00 2013-05-22 00:00:00.000
101 10001 John Doe 1932.00 2013-04-30 00:00:00.000
Then using the data above I would like to compare the balances to show the difference:
UserID UserName Difference
---------------------------------------------------------------
10001 John Doe -11410.00
This just shows the difference between the two previous balances (the latest and the balance before the latest)
Now I have the following query below. This works okay to show the two most recent transactions.
SELECT
TOP 2 *
FROM Table1
WHERE UserID = '1001'
ORDER
BY TranDate DESC
Now my issues are:
Is the sql above safe to use? I am just relying on the sorting of the TranDate by the ORDER BY DESC keyword and I am not so sure if this is very much reliable or not.
How do I select the difference between the two Balances (Row 2 - Row 1 )? I was looking for some answers online and I find stuff about self-joining. I tried it but it doesn't show me my desired output.
EDIT:
This is the closest I can get to my desired result. Can someone help me out on this please? Thanks!
DECLARE #SampleTable TABLE
(
UserID INT,
UserName VARCHAR(20),
Balance DECIMAL(9,2) DEFAULT 0
)
INSERT
INTO #SampleTable
(UserID, UserName, Balance)
SELECT
TOP 2 UserID,
UserName,
Balance
FROM Table1
WHERE UserID = '1001'
ORDER
BY TranDate DESC
SELECT A.UserID,
A.UserName,
B.Balance - A.Balance AS Difference
FROM #SampleTable A
JOIN #SampleTable B
ON A.UserID = B.UserID
Thanks a lot!
You should be able to use something like the following assuming SQL Server as the RDBMS:
;with cte as
(
select recordid, userid, username, balance, trandate,
row_number() over(partition by userid order by trandate desc) rn
from table1
)
select c1.userid, c1.username,
c1.balance - c2.balance diff
from cte c1
cross apply cte c2
where c1.rn = 1
and c2.rn = 2;
See SQL Fiddle with demo.
Or this could be done using an INNER JOIN on the row_number value:
;with cte as
(
select recordid, userid, username, balance, trandate,
row_number() over(partition by userid order by trandate desc) rn
from table1
)
select c1.userid, c1.username,
c1.balance - c2.balance diff
from cte c1
inner join cte c2
on c1.rn + 1 = c2.rn
where c1.rn = 1
See SQL Fiddle with Demo

Create table with distinct values based on date

I have a table which fills up with lots of transactions monthly, like below.
Name ID Date OtherColumn
_________________________________________________
John Smith 11111 2012-11-29 Somevalue
John Smith 11111 2012-11-30 Somevalue
Adam Gray 22222 2012-12-11 Somevalue
Tim Blue 33333 2012-12-15 Somevalue
John NewName 11111 2013-01-01 Somevalue
Adam Gray 22222 2013-01-02 Somevalue
From this table i want to create a dimension table with the unique names and id's. The problem is that a person can change his/her name, like "John" in the example above. The Id's are otherwise always unique. In those cases I want to only use the newest name (the one with the latest date).
So that I end up with a table like this:
Name ID
______________________
John NewName 11111
Adam Gray 22222
Tim Blue 33333
How do I go about achieving this?
Can I do it in a single query?
Use a CTE for this. It simplifies ranking and window functions.
;WITH CTE as
(SELECT
RN = ROW_NUMBER() OVER (PARTITION BY ID ORDER BY [Date] DESC),
ID,
Name
FROM
YourTable)
SELECT
Name,
ID
FROM
CTE
WHERE
RN = 1
I think creating a table is a bad idea, but this is how you get the most recent name.
select name
from yourtable yt join
(select id, max(date) maxdate
from yourtable
group by id ) temp on temp.id = yt.id and yt.date = maxdate
JNK's CTE solution is an equivalent of the following.
SELECT
Name,
ID
FROM (
SELECT
RN = ROW_NUMBER() OVER (PARTITION BY ID ORDER BY [Date] DESC),
Name,
ID
FROM theTable
)
WHERE RN = 1
Trying to think a way to get rid of the partition function without introducing the possible duplicates.

Issue with returning distinct records based on single column (Oracle)

If I have the table "members" (shown below), how would I go about getting the record of the first occurrence of a membership_id (Oracle).
Expected results
123 John Doe A P
313 Michael Casey A A
113 Luke Skywalker A P
Table - members
membership_id first_name last_name status type
123 John Doe A P
313 Michael Casey A A
113 Luke Skywalker A P
123 Bob Dole A A
313 Lucas Smith A A
SELECT membership_id,
first_name,
last_name,
status,
type
FROM( SELECT membership_id,
first_name,
last_name,
status,
type,
rank() over (partition by membership_id
order by type desc) rnk
FROM members )
WHERE rnk = 1
will work for your sample data set. If you can have ties-- that is, multiple rows with the same membership_id and the same maximum type-- this query will return all those rows. If you only want to return one of the rows where there is a tie, you would either need to add additional criteria to the order by to ensure that all ties are broken or you would need to use the row_number function rather than rank which will arbitrarily break ties.
Select A.*
FROM Members AS A inner join
(Select membership_id, first(first_name) AS FN, first(last_name) AS LN
From Members
Group by membership_id) AS B
ON A.membership_id=B.membership_id and A.first_name=B.FN and A.last_name=B.LN
Hope that helps!
select *
from members
where rowid in (
select min(rowid)
from members
group by membership_id
)