Finding the last duplicate row in (Oracle) SQL - sql

We have a history table which is defined as follows:
--ID (pk) -----------Object ID--------------Work ID--------date------
1 1111 AAAA 1/1/2010
2 1111 AAAA 1/2/2010
3 2222 BBBB 1/1/2010
4 3333 CCCC 1/1/2010
5 1111 DDDD 1/3/2010
We need the latest (date-based NOT id-based) row PER Work ID. Note that an object ID can have multiple work id's and we need the latest for EACH work ID.
What we need as our result set:
ID (pk) -----------Object ID--------------Work ID--------date------
2 1111 AAAA 1/2/2010
3 2222 BBBB 1/1/2010
4 3333 CCCC 1/1/2010
5 1111 DDDD 1/3/2010
Thoughts/Ideas?

SELECT *
FROM (
SELECT h.*,
ROW_NUMBER() OVER (PARTITION BY workID ORDER BY date DESC) AS rn
FROM history
)
WHERE rn = 1

select * from your_table a where (a.date, a.work_id) in (select max(b.date), b.work_id from your_table b where a.work_id=b.work_id group by work_id)

Related

find out the records - first two date records of each member of every year- db2udb

Need Help -
Scenario - I have a table testdata with columns
memberid (varchar) ,codetype(varchar),effectivedate(datetime)
this table having 20k records - from year 2015 to 2021
I need to find out the records - first two date records of each member of every year [ only memberid is unique)
eg.
member id
codetype
effectivedate
123
ABC
1/2/2015
123
ABC
1/2/2015
123
ABC
8/15/2015
123
EFG
9/15/2015
123
EFG
2/15/2018
345
EFG
3/14/2018
345
EFG
3/17/2018
345
ABC
9/19/2020
456
EFG
12/20/2021
result should be like below
member id
codetype
effectivedate
123
ABC
1/2/2015
123
ABC
1/2/2015
123
ABC
2/15/2018
345
EFG
3/14/2018
345
EFG
3/17/2018
345
ABC
9/19/2020
456
EFG
12/20/2021
tried lot of ways but no luck so far
Try this
with u as
(select memberid, codetype, effectivedate,
row_number() over(partition by memberid, year(effectivedate) order by
memberid) as rownum
from testdata)
(select memberid, codetype, effectivedate from u
where rownum <= 2)
Basically you get the row numbers of every record partitioned by memberid and the year of the record, then keep only the records where rownum is 1 or 2.

Select certain records and add them to a queue table

I have a table (Table1) that stores several snapshots for each account. Every day we may receive/Insert new snapshots to the accounts if values change for any of the columns val1, val2, val3, val4, val5
Table1
T1ID Account# snapshotDate val1 val2 val3 val4 val5
1 1001 1/1/2017 1111 2222 3333 4224 5551
2 1001 1/1/2018 1111 2222 3333 4444 5551
3 1001 1/1/2019 1111 2222 3333 4444 5550
4 2002 1/1/2017 123 1234 12345 123456 3434
5 2002 1/1/2018 123 1212 12345 123456 3434
6 2002 1/2/2019 333 1212 62626 252525 3434
I want to pull from Table1 the updated snapshots for these accounts every week and add them to a table/Queue (Table2) only if it is the first snapshot or if certain columns change (val2 or val5)
Table2
T2ID T1ID
01 1
02 3
03 4
04 5
T1ID 1 for account# 1001 was added because it’s the first snapshot
T1ID 2 for account# 1001 was NOT added because no change to columns (val2 or val5)
T1ID 3 for account# 1001 was added because of the change to column (val5)
T1ID 4 for account# 2002 was added because it’s the first snapshot
T1ID 5 for account# 2002 was added because of the change to column (val2)
T1ID 6 for account# 2002 was NOT added because no change to columns (val2 or val5)
Table2 will be used as a queue of changes for each account that will be sent to another process.
What is the best optimized query that I can use for this?
Use LAG() and ROW_NUMBER().
In a subquery, you can recover the last value for each of the 2 columns to compare withing account partitions, ordered by date. Then, the outer query can bring in the first record in each group, along with the records where any of the 2 related values changed.
SELECT
ROW_NUMBER() OVER(ORDER BY t1id) t2id,
t1id
FROM (
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY [Account#] ORDER BY snapshotDate) rn,
LAG(val2) OVER(PARTITION BY [Account#] ORDER BY snapshotDate) lval2,
LAG(val5) OVER(PARTITION BY [Account#] ORDER BY snapshotDate) lval5
FROM mytable t
) x
WHERE
rn = 1
OR NOT (val2 = lval2)
OR NOT (val5 = lval5)
Demo on DB Fiddle:
t2id | t1id
:--- | ---:
1 | 1
2 | 3
3 | 4
4 | 5

How to keep duplicates chains in database, using 2 columns to search, but with chained records with same ids

How to keep only the most recent chain?
ID Name Chain_id Chain_n
ABC Juan 123 1
ABC Juan 123 2
ABC Juan 123 3
ABC Juan 456 1
ABC Juan 456 2
ABC Juan 456 3
ABC Juan 789 1 Keep this
ABC Juan 789 2 Keep this
DEF Ana 234 1
DEF Ana 234 2
DEF Ana 567 1 Keep this
GHI Jill 345 1
GHI Jill 345 2
GHI Jill 678 1 Keep this
GHI Jill 678 2 Keep this
GHI Jill 678 3 Keep this
Tried to use common querys for duplicates, but based on just two columns it removes all records except 1, and I need to keep all the chain
select *
from t
where (columns-to-be-compared) in (select columns-to-be-compared
from t
group by columns-to-be-compared
having count(*) > 1 )
I need only to keep the last 2 records for ABC,789,1 and 2 for example, the rows marked on the table, chains with greater chain_id
We used an additional column "Name"
Delete from temptable
where rowid in
( select rwid
from ( select rowid rwid,
row_number() over (partition by ID, Name order by chain_id desc) rn
from temptable
) t
where rn > 1
);

Oracle SQL- Fetch a particular column based on other two columns

Table 1
I_ID S_id E_id
1000 1234 123
1002 1235 12
1002 1235 13
1003 3456 234
1004 1256 236
1004 1257 236
1005 1239 236
Table2
Desc SS_id EE_id
aaaa 1234 125
bbbb 1235 13
cccc 2222 234
hhhh 4444 236
jjjj 1239 236
1.First I need to match S_id of table 1 with SS_id of Table 2 and pick the corresponding Desc
2.If the count of S_id in point 1 is greater than 1 then match S_id,E_ID of table 1 with SS_id,EE_ID of Table 2 and pick the corresponding Desc
3.When S_ID of Table 1 is not present in SS_ID of Table2 then match E_id of Table 1with EE_id of Table2 and pick the corresponding Desc
4.if count of E_id in the point 3 is greater than 1 then match S_id,E_ID of table 1 with SS_id ,EE_ID of Table 2 and pick the corresponding Desc
5.Else populate null
Output
I_ID Desc
1000 aaaa
1002 bbbb
1003 cccc
1004 null
1005 jjjj
can you help me write SQl query
looking to your result seem that you need only
select table1.I_ID
INNER JOIN table2 on table1.S_id = table2.SS_id
(otherwise try to post an example more appropriate)

SQL transpose data

I need to transpose data that looks like the following. I don't need to use any aggregate functions, just want to transpose columns to rows.
Current view:
Name | Code1 | Code2 | Code3 | Pct1 | Pct2 | Pct3 | Amt1 | Amt2 | Amt3
Name1 123 124 125 50 25 25 1000 1500 1555
Name2 123 124 125 50 25 25 1222 1520 1600
What I Need:
AccountName | Code# | Pct | Amt
Name1 123 50 1000
Name1 124 25 1500
Name1 125 25 1555
Name2 123 50 1222
Name2 124 25 1520
Name2 125 25 1600
if this is possible, could you also include where I would place my joins if I need to use data in a different table?
I'm using SQL Server Management Studio 2014 and I don't have the permission to create tables
This is a neat trick using table valued expression
SELECT [Name], ca.*
From myTable
CROSS APPLY (Values
(Code1, Pct1, Amt1),
(Code2, Pct2, Amt2),
(Code3, Pct3, Amt3)
) ca([Code#], [Pct], [Amt])
select
Name,
case n when 1 then Code1 when 2 then Code2 when 3 then Code3 end as Code,
case n when 1 then Pct1 when 2 then Pct2 when 3 then Pct3 end as Pct,
case n when 1 then Amt1 when 2 then Amt2 when 3 then Amt3 end as Amt
from T cross join (values (1), (2), (3)) multiplier(n)
The basic idea is to triplicate the rows and then use case to pick out the correct values.