Find last record in DB for each repeated field(Oracle query) - sql

Hy guys.
I have a query:
select *
from stat.cause_code_descriptions
INNER JOIN stat.stat_dial
on stat.cause_code_descriptions.CODE = stat.stat_dial.cause
where called like '%3623.1348'
and begdt > sysdate-500
and rownum <=100
order by begdt desc
This query returns something like that
login code called begdtu(unix timestamp)
oeanwel 4 VLAN:3623.1348 1336383493
oe192034 0 VLAN:3623.1348 1336382883
oe192034 2 VLAN:3623.1348 1336382640
oe192034 45 VLAN:3623.1348 1336380257
oeanwel 4 VLAN:3623.1348 1336379883
oe220850 20 VLAN:3623.1348 1336378666
oe194752 4 VLAN:3623.1348 1336378507
oeanna2510 45 VLAN:3623.1348 1336377516
oeanwel 4 VLAN:3623.1348 1336376273
oe237185 45 VLAN:3623.1348 1336374506
oe237185 4 VLAN:3623.1348 1336372662
oe237185 3 VLAN:3623.1348 1336370819
oe239364 3 VLAN:3623.1348 1336367329
oeanna2510 45 VLAN:3623.1348 1336366115
What I'm looking for is to return last(freshest) record of any login.
For not repeated records my query works well, but for oe192034 and oe237185 logins it shows all records.
I tried group by and distinct but it doesn't work. Please help

You need a window function, ROW_NUMBER:
select *
from
(
select ccd.*, sd.*, row_number() over (partition by login order by begdtu desc) rn
from stat.cause_code_descriptions ccd
INNER JOIN stat.stat_dial sd
on ccd.CODE = sd.cause
where called like '%3623.1348'
) dt
where rn = 1
order by begdt desc

SELECT *
FROM (
select *,ROW_NUMBER() OVER (PARTITION BY login ORDER BY begdt DESC) RN
from stat.cause_code_descriptions
INNER JOIN stat.stat_dial on stat.cause_code_descriptions.CODE = stat.stat_dial.cause
where called like '%3623.1348' and begdt > sysdate-500 and rownum <=100 )
WHERE RN=1;

Try this:
SELECT
LOGIN,
CODE,
CALLED,
BEGDTU
FROM
(SELECT
LOGIN,
CODE,
CALLED,
BEGDTU,
FIRST_VALUE ( LOGIN )
OVER (PARTITION BY CODE, CALLED ORDER BY BEGDTU DESC)
AS FIRST_ROW_ID
FROM
STAT.CAUSE_CODE_DESCRIPTIONS
INNER JOIN
STAT.STAT_DIAL
ON STAT.CAUSE_CODE_DESCRIPTIONS.CODE = STAT.STAT_DIAL.CAUSE
WHERE
CALLED LIKE '%3623.1348'
AND FIRST_ROW_ID = 1)
WHERE
BEGDT > SYSDATE
- 500
AND ROWNUM <= 100
ORDER BY
BEGDT DESC

Related

Row_number not showing 1 rank

I am using the below code to get the rank but not able to see the 1st rank. I am getting the results 2 and 3.
Select BPMDate,Tenor,TenorStartDays,TenorEndDays,NominalTransacted,
SumofNominalRate,AverageRate,VWAR,rw,SortOrder
FROM
(
SELECT case_id,created_date BPMDate,tenor Tenor,tenor_start_days TenorStartDays,
tenor_end_days TenorEndDays
,nominal_transacted NominalTransacted,sum_of_nominal_rates SumofNominalRate
,average_rate AverageRate,vmar VWAR
,Case when tenor='O/N' Then 1 when tenor='1W' Then 2 when tenor='1M' Then 3
when tenor='3M' Then 4
when tenor='6M' Then 5 when tenor='1Y' Then 6 Else 7 End SortOrder,
row_number() over ( partition by tenor order by created_date desc ) rw
From table1
Where df_type = 'DF1' and to_date(created_date) >= '2020-10-13' and
to_date(created_date) <= '2020-10-13'
) ard
inner join
(
select case_id,case_status from table2
where case_status='Completed') ad
on ard.case_id=ad.case_id
order by sortorder
The column rw is beginning from 2 instead 1
thanks for the support
I think you are filtering it out when you join to ad , If you just select the sub query I think you will be able to see it.

How to find the Limit the row to top 1 in oracle [duplicate]

This question already has answers here:
How do I do top 1 in Oracle? [duplicate]
(9 answers)
Closed 4 years ago.
How to limit the output to only get the first row in ORACLE.
I tried FETCH first 1 rows only; But it is giving sql not ended properly error message
Current OUTPUT
70 19-APR-18 Base Line Date
71 20-JUN-19 Target Date
73 23-JUN-18
QUERY
SELECT EXEC_TRACKER_SESSION_SEQ,
(CASE WHEN tsm.SESSION_SEQ IS NULL THEN tsm.TAGETDATE ELSE s.SESSION_DATE END) as SESSION_DATE
,tsm.NOTES
FROM TRACKER_SESSION_MAP tsm
LEFT JOIN session s ON tsm.session_seq = s.session_seq
WHERE tsm.TRACKER_SEQ =244
order by TRACKER_SESSION_SEQ ASC
Required Output
70 19-APR-18 Base Line Date
Use rownum=1 as :
select * from
(
SELECT EXEC_TRACKER_SESSION_SEQ,
(CASE WHEN tsm.SESSION_SEQ IS NULL THEN tsm.TAGETDATE ELSE s.SESSION_DATE END) as SESSION_DATE
,tsm.NOTES
FROM TRACKER_SESSION_MAP tsm
LEFT JOIN session s ON tsm.session_seq = s.session_seq
WHERE tsm.TRACKER_SEQ =244
order by TRACKER_SESSION_SEQ ASC
)
where rownum=1;
Alternatively you may use row_number() function as :
select * from
(
SELECT EXEC_TRACKER_SESSION_SEQ,
(CASE WHEN tsm.SESSION_SEQ IS NULL THEN tsm.TAGETDATE ELSE s.SESSION_DATE END) as SESSION_DATE
,tsm.NOTES, row_number() over (order by day) as rn
FROM TRACKER_SESSION_MAP tsm
LEFT JOIN session s ON tsm.session_seq = s.session_seq
WHERE tsm.TRACKER_SEQ =244
order by TRACKER_SESSION_SEQ ASC
)
where rn=1;
fetch..rows statement works provided that you use Oracle 12c.
You need
WHERE ROWNUM=1
Oracle doesn't have a top X function, but it always knows what the rownumber, so take advantage.

Non duplicate records with max date query on oracle

Hello i have a problem with a simple query. I need to see the max date of some articles in two direfent sites.
This is my actual query:
SELECT a.aa_codart, MAX(t.tr_fechafac), t.tr_tipo
FROM ARTALM a, traspaso t
WHERE t.tr_codart = a.aa_codart
and t.tr_tipomov > 1
and a.aa_codalm = '1'
and (t.tr_tipo >= 1 and t.tr_tipo <=2)
group by a.aa_codart, t.tr_tipo;
And the result:
01..FRB10X80 30/11/07 2
01..FRB10X80 08/03/01 1
01.32122RS 05/02/16 1
01.32122RS 02/07/10 2
01.33052Z 21/09/15 1
01.60042Z 24/02/16 2
I want, for example in the two first rows, see only one row, like this:
01..FRB10X80 30/11/07 2
01.32122RS 05/02/16 1
01.33052Z 21/09/15 1
01.60042Z 24/02/16 2
Taking the max date
Thanks
This calls for an analytical query. This query shows how the ROW_NUMBER() function will assign the value 1 to the row with the article's most recent date. Give it a try first to help understand the final query, coming up next:
SELECT
a.aa_codart,
t.tr_fechafac,
t.tr_tipo,
ROW_NUMBER() OVER (PARTITION BY a.aa_codart ORDER BY t.tr_fechafac DESC) as rnk
FROM artalm a
INNER JOIN trapaso t ON a.aa_codart = t.tr_codart
WHERE t.tr_tipomov > 1
AND a.aa_codalm = '1'
AND t.tr_tipo BETWEEN 1 AND 2
You can't apply the WHERE clause to the rnk column because the column is calculated after the WHERE clause. You can get around this using a nested query:
SELECT * FROM (
SELECT
a.aa_codart,
t.tr_fechafac,
t.tr_tipo,
ROW_NUMBER() OVER (PARTITION BY a.aa_codart ORDER BY t.tr_fechafac DESC) as rnk
FROM artalm a
INNER JOIN trapaso t ON a.aa_codart = t.tr_codart
WHERE t.tr_tipomov > 1
AND a.aa_codalm = '1'
AND t.tr_tipo BETWEEN 1 AND 2
) WHERE rnk = 1;
I apologize in advance for any column names I may have retyped badly. The Oracle syntax should be fine; the column names maybe not so much :)
I think you may want to look at row_number() (then just pick the ones where it is one) something like this.
WITH t
AS (SELECT 'A' aa_codart,
TO_DATE ('17/05/00', 'dd/mm/yy') mydt,
1 tr_tipo
FROM DUAL
UNION ALL
SELECT 'A', TO_DATE ('12/04/00', 'dd/mm/yy'), 2 FROM DUAL
UNION ALL
SELECT 'B', TO_DATE ('30/06/98', 'dd/mm/yy'), 2 FROM DUAL
UNION ALL
SELECT 'C', TO_DATE ('30/06/98 ', 'dd/mm/yy'), 2 FROM DUAL),
t2
AS (SELECT aa_codart,
mydt,
tr_tipo,
ROW_NUMBER ()
OVER (PARTITION BY aa_codart ORDER BY mydt DESC)
rn
FROM t)
SELECT *
FROM t2
WHERE rn = 1

Efficiently writing this formula in SQL server 2008

Say I have table and these are its sample rows
ChangeID Change
1 102
2 105
3 107
4 110
The change formula is
(CurrentRowChange - PreviousRowChange) / PreviousRowChange
Hence:
for 1st row it should be 0
for 2nd row it should be (105 - 102) / 102
and so on. How can I efficiently write this formula in SQL?
I know I can write a scalar function and then do a RowNumber and order By ChangeID and fetch the row number's Change value and then find the current row number - 1 and then fetch that row's Change value and do a divide.
Is there any better way to achieve this?
give this a try, assuming that CHANGEID can be deleted and it is IDENTITY.
WITH changeList
AS
(
SELECT ChangeID, [Change],
(ROW_NUMBER() OVER (ORDER BY ChangeID ASC)) -1 AS rn
FROM TableName
),
normalList
AS
(
SELECT ChangeID, [Change],
(ROW_NUMBER() OVER (ORDER BY ChangeID ASC)) AS rn
FROM TableName
)
SELECT a.ChangeID, a.[Change],
COALESCE((a.Change - b.change) / (b.change * 1.0),0) result
FROM changeList a
LEFT JOIN normalList b
ON a.rn = b.rn
SQLFiddle Demo
select cur.*
, case
when prev.ChangeId is null then 0
else 1.0 * (cur.Change - prev.Change) / prev.Change
end
from Table1 cur
left join
Table1 prev
on cur.ChangeId = prev.ChangeId + 1
SQL Fiddle example.
While the ChangeID's are sequential in the sample, I wouldn't assume that they always are. So I would do something like this:
with RankedIDs as
select ChangeID
, Change
, rank() over
(partition by ChangeID order by ChangeId) rank
where something maybe ;
select case
when r1.rank = 1 then 0
else (r1.change - r2.change) / r2.change
end SomeName
from RankedIds r1 join RankedIds r2 on r1.rank = r2.rank + 1
That's the basic idea. You might want to add divide by zero protection
select T1.ChangeID,
(1.0 * T1.Change / T2.Change) - 1 as Result
from TableName as T1
outer apply (
select top(1) T.Change
from TableName as T
where T.ChangeID < T1.ChangeID
order by T.ChangeID desc
) as T2

SQL ROW_NUMBER with INNER JOIN

I need to use ROW_NUMBER() in the following Query to return rows 5 to 10 of the result. Can anyone please show me what I need to do? I've been trying to no avail. If anyone can help I'd really appreciate it.
SELECT *
FROM villa_data
INNER JOIN villa_prices
ON villa_prices.starRating = villa_data.starRating
WHERE villa_data.capacity >= 3
AND villa_data.bedrooms >= 1
AND villa_prices.period = 'lowSeason'
ORDER BY villa_prices.price,
villa_data.bedrooms,
villa_data.capacity
You need to stick it in a table expression to filter on ROW_NUMBER. You won't be able to use * as it will complain about the column name starRating appearing more than once so will need to list out the required columns explicitly. This is better practice anyway.
WITH CTE AS
(
SELECT /*TODO: List column names*/
ROW_NUMBER()
OVER (ORDER BY villa_prices.price,
villa_data.bedrooms,
villa_data.capacity) AS RN
FROM villa_data
INNER JOIN villa_prices
ON villa_prices.starRating = villa_data.starRating
WHERE villa_data.capacity >= 3
AND villa_data.bedrooms >= 1
AND villa_prices.period = 'lowSeason'
)
SELECT /*TODO: List column names*/
FROM CTE
WHERE RN BETWEEN 5 AND 10
ORDER BY RN
You can use a with clause. Please try the following
WITH t AS
(
SELECT villa_data.starRating,
villa_data.capacity,
villa_data.bedrooms,
villa_prices.period,
villa_prices.price,
ROW_NUMBER() OVER (ORDER BY villa_prices.price,
villa_data.bedrooms,
villa_data.capacity ) AS 'RowNumber'
FROM villa_data
INNER JOIN villa_prices
ON villa_prices.starRating = villa_data.starRating
WHERE villa_data.capacity >= 3
AND villa_data.bedrooms >= 1
AND villa_prices.period = 'lowSeason'
)
SELECT *
FROM t
WHERE RowNumber BETWEEN 5 AND 10;