Non duplicate records with max date query on oracle - sql

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

Related

Oracle Pivot rows to columns pattern matching

I want to rearrange the rows to columns (in tbl2 below) to count the number of occurrences of EXEN for the EXEN col, and any code starting with MPA for the MPACODE column.
SELECT *
FROM (select code from tbl2 where pidm='4062161')
PIVOT (count(*) FOR (code) IN ('EXEN' AS EXEN, 'MPA%' AS MPACODE));
tbl2:
Desired output:
Actual output:
You must perform an intermediate step to transform all MPA%to MPAsee subquery dt2
with dt as (
select 'EXEN' code from dual union all
select 'MPA'||rownum from dual connect by level <= 10),
dt2 as (
select
case when code like 'MPA%' then 'MPA' else code end as code
from dt)
select *
from dt2
pivot (
count(*) for
(code) IN ('EXEN' AS EXEN, 'MPA' AS MPACODE));
EXEN MPACODE
---------- ----------
1 10
PIVOT perform an equal comparison (not LIKE), so this is not valid: 'MPA%' AS MPACODE and the reason why the query fails.
for example:
select
count(case when code='EXEN' then 1 end) exen,
count(case when code like 'MPA%' then 1 end) mpacode
from tbl2 where pidm='4062161';

Single-column row-set exists in another table or a function returns positive value

I have following table structure: http://sqlfiddle.com/#!4/952e7/1
Now I am looking for a solution for the following problem:
Given an input data-time set (see below). And the SQL statement should return all of business IDs with a given business name, where every single date-times of the input set are either present in the ORDERS table or an additional function's statement is true (these both conditions are separately to be checked for each input date-time).
An example how the input date-time dataset looks like:
WITH DATES_TO_CHECK(DATETIME) AS(SELECT DATE '2021-01-03' FROM DUAL UNION ALL SELECT DATE '2020-04-08' FROM DUAL UNION ALL SELECT DATE '2020-05-07' FROM DUAL)
To be simple, the "additional function" should be a simple random number (if greather than 0.5 than true otherwise false, so the check is dbms_random.value > 0.5).
For one given date time it would look like:
SELECT BN.NAME, BD.ID
FROM BUSINESS_DATA BD, BUSINESS_NAME BN
WHERE BD.NAME_ID=BN.ID AND
BN.NAME='B1' AND
(TO_DATE('2021-01-03', 'YYYY-MM-DD') IN (SELECT OD.ORDERDATE FROM ORDERS OD WHERE OD.BUSINESS_ID=BD.ID)
OR dbms_random.value > 0.5)
ORDER BY BD.ID
Please help me, how this solution can be applied to the input date-time rowset above AND the specified name.
I don't any difference with the question you just deleted
This is the list of businesses named B1 and for which the number of order dates that match date input dates is equal to the number of input dates or dbms_random.value > 0.5
see SQL Fiddle
WITH DATES_TO_CHECK(DATETIME) AS(
SELECT DATE '2021-01-03' FROM DUAL
UNION ALL SELECT DATE '2020-04-08' fROM DUAL
UNION ALL SELECT DATE '2020-05-07' fROM DUAL
),
businesses_that_match as (
select
od.BUSINESS_ID, count(distinct OD.ORDERDATE)
from DATES_TO_CHECK dtc
left join ORDERS od on OD.ORDERDATE = dtc.datetime
group by od.BUSINESS_ID
having count(distinct OD.ORDERDATE) = (select count(distinct DATETIME) from DATES_TO_CHECK)
)
SELECT
BN.NAME, BD.ID
FROM BUSINESS_DATA BD
inner join BUSINESS_NAME BN on BD.NAME_ID=BN.ID
left join businesses_that_match btm on btm.BUSINESS_ID = bd.id
where bn.name = 'B1'
AND (btm.BUSINESS_ID is not null
OR dbms_random.value > 0.5
)

Consolidate information (time serie) from two tables

MS SQL Server
I have two tables with different accounts from the same customer:
Table1:
ID
ACCOUNT
FROM
TO
1
A
01.10.2019
01.12.2019
1
A
01.02.2020
09.09.9999
and table2:
ID
ACCOUNT
FROM
TO
1
B
01.12.2019
01.01.2020
As result I want a table that summarize the story of this costumer and shows when he had an active account and when he doesn't.
Result:
ID
FROM
TO
ACTIV Y/N
1
01.10.2019
01.01.2020
Y
1
02.01.2020
31.01.2020
N
1
01.02.2020
09.09.9999
Y
Can someone help me with some ideas how to proceed?
This is the typical gaps and island problem, and it's not usually easy to solve.
You can achieve your goal using this query, I will explain it a little bit.
You can test on this db<>fiddle.
First of all... I have unified your two tables into one to simplify the query.
-- ##table1
select 1 as ID, 'A' as ACCOUNT, convert(date,'2019-10-01') as F, convert(date,'2019-12-01') as T into ##table1
union all
select 1 as ID, 'A' as ACCOUNT, convert(date,'2020-02-01') as F, convert(date,'9999-09-09') as T
-- ##table2
select 1 as ID, 'B' as ACCOUNT, convert(date,'2019-12-01') as F, convert(date,'2020-01-01') as T into ##table2
-- ##table3
select * into ##table3 from ##table1 union all select * from ##table2
You can then get your gaps and island using, for example, a query like this.
It combines recursive cte to generate a calendar (cte_cal) and lag and lead operations to get the previous/next record information to build the gaps.
with
cte_cal as (
select min(F) as D from ##table3
union all
select dateadd(day,1,D) from cte_cal where d < = '2021-01-01'
),
table4 as (
select t1.ID, t1.ACCOUNT, t1.F, isnull(t2.T, t1.T) as T, lag(t2.F, 1,null) over (order by t1.F) as SUP
from ##table3 t1
left join ##table3 t2
on t1.T=t2.F
)
select
ID,
case when T = D then F else D end as "FROM",
isnull(dateadd(day,-1,lead(D,1,null) over (order by D)),'9999-09-09') as "TO",
case when case when T = D then F else D end = F then 'Y' else 'N' end as "ACTIV Y/N"
from (
select *
from cte_cal c
cross apply (
select t.*
from table4 t
where t.SUP is null
and (
c.D = t or
c.D = dateadd(day,1,t.T)
)
) t
union all
select F, * from table4 where T = '9999-09-09'
) p
order by 1
option (maxrecursion 0)
Dates like '9999-09-09' must be treated like exceptions, otherwise I would have to create a calendar until that date, so the query would take long time to resolve.

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.

Query which gives list of dates between two date ranges

I am sorry for this but my previous question was not properly framed, so creating another post.
My question is similar to following question:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:14582643282111
I need to write inner query which will give me a list of dates between two date ranges to outer query.
My inner query returns following 2 rows:
SELECT request.REQ_DATE, request.DUE_DATE FROM myTable where id = 100
REQ_DATE DUE_DATE
3/19/2013 3/21/2013
3/8/2013 3/8/2013
So I need inner query which will return following dates to outer query:
3/19/2013
3/20/2013
3/21/2013
3/8/2013
The answer in above post has start date and end date hard coded and in my case, it is coming from other table. So I am trying to write query like this which does not work:
 
Select * from outerTable where my_date in
(
select to_date(r.REQ_DATE) + rownum -1 from all_objects,
(
SELECT REQ_DATE, DUE_DATE
FROM myTable where id = 100
) r
where rownum <= to_date(r.DUE_DATE,'dd-mon-yyyy')-to_date(r.REQ_DATE,'dd-mon-yyyy')+1;
)
with
T_from_to as (
select
trunc(REQ_DATE) as d_from,
trunc(DUE_DATE) as d_to
FROM myTable
where id = 100
),
T_seq as (
select level-1 as delta
from dual
connect by level-1 <= (select max(d_to-d_from) from T_from_to)
)
select distinct d_from + delta
from T_from_to, T_seq
where d_from + delta <= d_to
order by 1