Oracle SQL (Oracle11g) - select statement where date equal to another select statement - sql

I have the following script that shows the last 11 months from the sysdate...
select * from (
select level-1 as num,
to_char(add_months(trunc(sysdate,'MM'),- (level-1)),'MM')||'-'||to_char(add_months(trunc(sysdate,'MM'),- (level-1)),'YYYY') as dte
from dual
connect by level <= 12
)
pivot (
max(dte) as "DATE"
for num in (0 as "CURRENT", 1 as "1", 2 as "2", 3 as "3", 4 as "4", 5 as "5",6 as "6",7 as "7",8 as "8",9 as "9",10 as "10", 11 as "11"))
I want to create a table that shows delivery qty where the delivery date ('MM-YYYY') equals the date generated from the above script.
I get the delivery qty and delivery date from the following
select dp.catnr,
nvl(sum(dp.del_qty),0) del_qty
from bds_dhead#sid_to_cdsuk dh,
bds_dline#sid_to_cdsuk dp
where dp.dhead_no = dh.dhead_no
and dh.d_status = '9'
and dp.article_no = 9||'2EDVD0007'
and to_char(trunc(dh.actshpdate),'MM')||'-'||to_char(trunc(dh.actshpdate),'YYYY') = = --this is where I would like to match the result of the above script
group by dp.catnr
The results would look something like...
Any ideas would be much appreciated.
Thanks, SMORF

with date_series as (
select add_months(trunc(sysdate,'MM'), 1 - lvl) start_date,
add_months(trunc(sysdate,'MM'), 2-lvl) - 1/24/60/60 end_date
from (select level lvl from dual connect by level <= 12)
),
your_table as (
select 'catnr1' catnr, 100500 del_qty, sysdate actshpdate from dual
union all select 'catnr1' catnr, 10 del_qty, sysdate-30 actshpdate from dual
union all select 'catnr2' catnr, 15 del_qty, sysdate-60 actshpdate from dual
),
subquery as (
select to_char(ds.start_date, 'MM-YYYY') dte, t.catnr, sum(nvl(t.del_qty, 0)) del_qty
from date_series ds left join your_table t
on (t.actshpdate between ds.start_date and ds.end_date)
group by to_char(ds.start_date, 'MM-YYYY'), t.catnr
)
select * from subquery pivot (sum(del_qty) s for dte in ('11-2013' d1, '12-2013' d2, '08-2014' d10, '09-2014' d11, '10-2014' d12))
where catnr is not null;

Related

Get range of dates from dates record in MS SQL

I have dates record
with DateTable (dateItem) as
(
select '2022-07-03' union all
select '2022-07-05' union all
select '2022-07-04' union all
select '2022-07-09' union all
select '2022-07-12' union all
select '2022-07-13' union all
select '2022-07-18'
)
select dateItem
from DateTable
order by 1 asc
I want to get ranges of dates between this record like this
with DateTableRange (dateItemStart, dateItemend) as
(
select '2022-07-03','2022-07-05' union all
select '2022-07-09','2022-07-09' union all
select '2022-07-12','2022-07-13' union all
select '2022-07-18','2022-07-18'
)
select dateItemStart, dateItemend
from DateTableRange
I am able to do it in SQL with looping using while or looping by getting first one and check the next dates and if they are 1 plus then I add it in enddate and do the same in loop
But I don't know what the best or optimized way is, as there were lots of looping and temp tables involve
Edited :
as in data we have 3,4,5 and 6,7,8 is missing so range is 3-5
9 exist and 10 is missing so range is 9-9
so ranges is purely depend on the consecutive data in datetable
Any suggestion will be appreciated
With some additional clarity this requires a gaps-and-islands approach to first identify adjacent rows as groups, from which you can then use a window to identify the first and last value of each group.
I'm sure this could be refined further but should give your desired results:
with DateTable (dateItem) as
(
select '2022-07-03' union all
select '2022-07-05' union all
select '2022-07-04' union all
select '2022-07-09' union all
select '2022-07-12' union all
select '2022-07-13' union all
select '2022-07-18'
), valid as (
select *,
case when exists (
select * from DateTable d2 where Abs(DateDiff(day, d.dateitem, d2.dateitem)) = 1
) then 1 else 0 end v
from DateTable d
), grp as (
select *,
Row_Number() over(order by dateitem) - Row_Number()
over (partition by v order by dateitem) g
from Valid v
)
select distinct
Iif(v = 0, dateitem, First_Value(dateitem) over(partition by g order by dateitem)) DateItemStart,
Iif(v = 0, dateitem, First_Value(dateitem) over(partition by g order by dateitem desc)) DateItemEnd
from grp
order by dateItemStart;
See Demo Fiddle
After clarification, this is definitely a 'gaps and islands' problem.
The solution can be like this
WITH DateTable(dateItem) AS
(
SELECT * FROM (
VALUES
('2022-07-03'),
('2022-07-05'),
('2022-07-04'),
('2022-07-09'),
('2022-07-12'),
('2022-07-13'),
('2022-07-18')
) t(v)
)
SELECT
MIN(dateItem) AS range_from,
MAX(dateItem) AS range_to
FROM (
SELECT
*,
SUM(CASE WHEN DATEADD(day, 1, prev_dateItem) >= dateItem THEN 0 ELSE 1 END) OVER (ORDER BY rn) AS range_id
FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY dateItem) AS rn,
CAST(dateItem AS date) AS dateItem,
CAST(LAG(dateItem) OVER (ORDER BY dateItem) AS date) AS prev_dateItem
FROM DateTable
) groups
) islands
GROUP BY range_id
You can check a working demo

SQL query to find ids in the same table but different timestamp events (cohorts)

I need to write a query that gives me the count with the following logic. The example below shows that ACCOUNT_ID 123 signup in 2020-02-21 so M0 is 1 and then the same ACCOUNT_ID had an event in the consecutive month so M1 is 1.
M0 is a the signup date
M1 is signup date + 1 month
M2 is signup date + 2 consecutive months
M3 is signup date + 3 consecutive months
WITH M_O AS (
SELECT
parsed_data."ACCOUNT_ID" AS "parsed_data.account_id",
MIN(TO_CHAR(TO_DATE(parsed_data."TIMESTAMP"::timestamp_ntz ), 'YYYY-MM-DD')) AS "SIGNUP",
COUNT(DISTINCT (parsed_data."ACCOUNT_ID") ) AS "COUNT_USERS_O"
FROM "PUBLIC"."PARSED_DATA"
AS parsed_data
WHERE (parsed_data."ACCOUNT_ID") IS NOT NULL
AND (((parsed_data."EVENT") = 'Started'))
AND (
((TO_CHAR(TO_DATE(parsed_data."TIMESTAMP"::timestamp_ntz ), 'YYYY-MM-DD')) >= '2020-02-21')
AND ((parsed_data."TIMESTAMP"::timestamp_ntz ) < CURRENT_DATE())
)
GROUP BY 1),
M_1 AS (
SELECT
parsed_data."ACCOUNT_ID" AS "parsed_data.account_id",
TO_CHAR(TO_DATE(parsed_data."TIMESTAMP"::timestamp_ntz ), 'YYYY-MM-DD') AS "parsed_data.timestamp_date",
COUNT(DISTINCT (parsed_data."ACCOUNT_ID") ) AS "COUNT_USERS_1"
FROM "PUBLIC"."PARSED_DATA"
AS parsed_data INNER JOIN M_O ON parsed_data.account_id = M_O."parsed_data.account_id"
WHERE
(parsed_data."ACCOUNT_ID") IS NOT NULL
AND (((parsed_data."EVENT") = 'Started'))
AND (
(TO_CHAR(TO_DATE(parsed_data."TIMESTAMP"::timestamp_ntz ), 'YYYY-MM-DD')) >= DATEADD('MONTH', 1, SIGNUP)
AND ((parsed_data."TIMESTAMP"::timestamp_ntz ) < CURRENT_DATE())
)
GROUP BY 1,2
)
It looks like you want to create cohorts? As in "establish the creation date for each id, and then look how they changed their behavior every month thereafter".
This code should work:
with events as (
select 1 id, '2020-01-01'::date e_date
union all select 1, '2020-02-03'
union all select 2, '2020-03-01'
union all select 2, '2020-05-08'
union all select 3, '2020-08-01'
union all select 3, '2020-09-02'
union all select 3, '2020-09-22'
union all select 3, '2020-09-30'
union all select 3, '2020-10-10'
),
first_per_id as (
select id, min(e_date) first_date
from events
group by id
)
select a.id
, count_if(e_date>=dateadd(month, 0, first_date) and e_date<dateadd(month, 1, first_date)) m0
, count_if(e_date>=dateadd(month, 1, first_date) and e_date<dateadd(month, 2, first_date)) m1
, count_if(e_date>=dateadd(month, 2, first_date) and e_date<dateadd(month, 3, first_date)) m2
from events a
join first_per_id b
where a.id=b.id
group by 1

How to select next value

The task is to see the date of payment of the loan. If it falls on a date where there is no such number, it does not show data but should show the first date from the next month
Sql work good if i enter date 15.01.2019
But if i can enter date 31.01.2019 i have problem .
I can not see correct result sql request.
With days as (
Select rownum As Day from All_Objects where Rownum<=31
),
a as (Select 'WHWWHHWWWWWHHWWWWWHHWWWWWHHWWWW' as hl ,1 as Mnth,2019 as Yr from Dual
Union All
Select 'WHHWWWWWHHWWWWWHHWWWWWHHWWWW' as hl ,2 as Mnth,2019 as Yr from Dual
Union All
Select 'WHHWWWWHHHWWWWWHHWWHHHHHHHWWWHH' as hl ,3 as Mnth,2019 as Yr from Dual
Union All
Select 'WWWWWHHWWWWWHHWWWWWHHWWWWWHHWW' as hl ,4 as Mnth,2019 as Yr from Dual
Union All
Select 'WWWHHWWWHWHHWWWWWHHWWWWWHHWHWWW' as hl ,5 as Mnth,2019 as Yr from Dual
Union All
Select 'HHWWHHWHHWWWWWHHHWWWWHHWWHWWHH' as hl ,6 as Mnth,2019 as Yr from Dual
Union All
Select 'WWWWWHHWWWWWHHWWWWWHHWWWWWHHWWW' as hl ,7 as Mnth,2019 as Yr from Dual
)
,
Alll as
(Select TO_Date(Yr|| substr('0'||Mnth,-2,2)||substr('0'||Day,-2,2),'YYYYMMDD') as Dt,a.Yr,a.Mnth,Days.Day,substr(a.Hl,Days.Day,1) as Daytype from Days,a Where Days.Day<=Length(a.Hl)
),
Taksit as
(
Select To_Date('31.01.2019') as TDate, 1000 as Amount ,3 as Tcount from Dual
),
PD as (
Select
A.Dt,A.DayType , Case when A.DayType='H' then Min(W.Dt) else A.Dt end As PayableDate
From Alll A inner Join Alll W on W.DT>=A.DT and W.DayType='W'
Group by A.Dt, A.Daytype
Order by 1
),
PreResult as
(
Select PD.PayableDate,Amount,TCount,Max(PD.PayableDate) over (Partition by 'Contract') as MPD
From PD inner join Taksit T on PD.DT between add_months(T.TDate,1) and Add_Months(T.TDate,TCount)
and TO_Char(PD.DT,'DD')=TO_Char(T.TDate,'DD')
)
Select
PayableDate, Case when PayableDate=MPD then Amount-(Round(Amount/TCount,2)*(TCount-1)) else Round(Amount/TCount,2) end PayAmount
from PreResult
You have used TO_CHAR(PD.DT, 'DD') = TO_CHAR(T.TDATE, 'DD') but I don't think that Feb month has any date which will match with it.
Ideally, you should use add_month function as following in PRERESULT (I believe you need only 3 months data)
PRERESULT AS (
SELECT
PD.PAYABLEDATE,
AMOUNT,
TCOUNT,
MAX(PD.PAYABLEDATE) OVER(
PARTITION BY 'Contract'
) AS MPD
FROM
PD
INNER JOIN TAKSIT T ON PD.DT BETWEEN ADD_MONTHS(T.TDATE, 1) AND ADD_MONTHS(T.TDATE, TCOUNT)
AND PD.DT IN (ADD_MONTHS(T.TDATE, 1), ADD_MONTHS(T.TDATE, 2), ADD_MONTHS(T.TDATE, 3))
-- AND TO_CHAR(PD.DT, 'DD') = TO_CHAR(T.TDATE, 'DD')
)
It is giving 3 dates with 31.01.2019 and also it is working as expected in the case of 15.01.2019 also.
I think you should check if it is giving an expected result with 31.01.2019 as you have not mentioned the expected result. see this db<>fiddle demo
Cheers!!

How to subtract dates of two column in sql

Please go through this edited table.
You can assume order_header_key as order no.
I want to get the list of order nos whose current status is 3 and previous status was 2, and the status date(status3)-status date(2) <=3 days for that order
in the following table
for order no-1 'date(status 3)' - 'date(status 2) = 20 OCT - 19 OCT
which is less than 3 days--> So valid order
but for order no 3 'date(status 3)' - 'date(status 2)' = 30 OCT - 24 OCT
which is more than 3 days so invalid order
order no 2 in invalid since the statuses are 3 and 1 , 2 is missing
Assuming an order can't have more than one entry per order_no/status combination, you could join two subqueries:
SELECT s3.order_no
FROM (SELECT *
FROM orders
WHERE status = 3) s3
JOIN (SELECT *
FROM orders
WHERE status = 2) s2 ON s3.order_no = s2.order_no AND
s3.status_date - s3.status_date <= 3
Use lag():
select o.*
from (select o.*,
lag(o.status_date) over (partition by o.order_no order by o.status_date ) as prev_sd,
lag(o.status) over (partition by o.order_no order by o.status_date) as prev_status
from orders o
) o
where prev_status = 2 and status = 3 and
(status_date - prev_sd) <= 3;
Analytic functions (lag() in this case) allow you to avoid joins and/or subqueries, and may (and often will) be much faster.
with
-- begin test data; not part of the solution
orders ( order_no, status, status_date ) as (
select 1, 1, to_date('18-OCT-16', 'DD-MON-YY')from dual union all
select 1, 2, to_date('19-OCT-16', 'DD-MON-YY')from dual union all
select 1, 3, to_date('20-OCT-16', 'DD-MON-YY')from dual union all
select 1, 1, to_date('20-OCT-16', 'DD-MON-YY')from dual union all
select 1, 3, to_date('23-OCT-16', 'DD-MON-YY')from dual union all
select 1, 2, to_date('24-OCT-16', 'DD-MON-YY')from dual union all
select 1, 1, to_date('30-OCT-16', 'DD-MON-YY')from dual
),
-- end test data; solution is the word "with" from above, plus the query below
prep ( order_no, status, status_date, prev_status, prev_status_date) as (
select order_no, status, status_date,
lag(status) over (partition by order_no order by status_date),
lag(status_date) over (partition by order_no order by status_date)
from orders
)
select order_no
from prep
where status = 3 and prev_status = 2 and prev_status_date - status_date <= 3
;
ORDER_NO
--------
1

To list 12 months in a query Oracle SQL

I need your help, please.
I have a query to list a PDAs numbers and I need to sort this in twelve months. My query:
SELECT TO_CHAR(primeirodia_mes,'mm/yyyy') competencia,
'Suporte' tipo,
(SELECT COUNT(tipo)
FROM v_pdas_suporte_se
WHERE TO_CHAR(primeirodia_mes,'mm/yyyy') = TO_CHAR(v_pdas_suporte_se.dt,'mm/yyyy')
AND tipo IN ( 'S','E')
) quantidade
FROM
(SELECT To_Date( '01/'
||LPad(ID,2,0)
||'/'
||TO_CHAR(SYSDATE,'yyyy') ,'dd/mm/yyyy') primeirodia_mes
FROM
(SELECT LEVEL AS ID FROM DUAL CONNECT BY LEVEL <= 12 )
) contador
I need to list , for example, Oct/2014 to Oct/2015.
I assume you are looking for this:
WITH t AS
(SELECT ADD_MONTHS(TRUNC(SYSDATE, 'MM'), - LEVEL+1) AS primeirodia_mes
FROM dual CONNECT BY LEVEL <= 13)
SELECT
primeirodia_mes AS competencia,
'Suporte' tipo,
COUNT(tipo)
FROM v_pdas_suporte_se
RIGHT OUTER JOIN t ON primeirodia_mes = TRUNC(dt, 'MM')
GROUP BY primeirodia_mes;