To list 12 months in a query Oracle SQL - 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;

Related

Count of consecutive days ORACLE SQL

I need help with a query where a need to count de consecutive days like this
select
a.numcad, a.datapu , f.datapu , nvl(to_char(f.datapu, 'DD'),0)dia,
row_number() over (partition by a.numcad, f.datapu order by f.datapu)particao
from
ronda.r066apu a
left join (select t.numcad, t.numemp, t.datacc, t.datapu
from ronda.r070acc t
where t.datacc >= '21/01/2022'
and t.datacc <= trunc(sysdate)
group by t.numcad, t.numemp, t.datacc, t.datapu)f
on a.numemp = f.numemp
and a.numcad = f.numcad
and a.datapu = f.datapu
where a.numcad = 2675
and A.DATAPU >= '21/01/2022'
and A.DATAPU <= trunc(sysdate)
group by a.numcad, a.datapu, f.datapu, f.datacc
order by a.datapu
result is
between 24/01/2022 and 04/02/2022
is 12 days i need know this count , but i will ways get the '21/mes/year'
You can try:
SELECT TO_DATE('2022-01-24', 'YYYY-MM-DD') -
TO_DATE('2022-02-04', 'YYYY-MM-DD')
FROM dual
This returns 21, for example...

Oracle SQL variable/parameter usage in query

I have this query below and I need to change WHERE conditions depending on QUARTER.
Meaning that I have to copy that query and change the DATE conditions to 06.2020 then use UNION.
I have no idea how can I optimize this query only with SQL because I am not able to DEFINE some variables/parameters in SQL (not using PL/SQL).
SELECT sum(a.limit_amount) as LIMIT,
sum(b.balance_amount) as OUTSTANDING,
'LOAN' as TYPE,
'Q1 2020' as QUARTER
FROM accounts a
left join account_balances b
ON a.account_key = b.account_key
AND b.balance_type_key = 16
AND b.balance_date = last_day(to_date('03.2020', 'MM.YYYY'))
WHERE a.account_close_date > last_day(to_date('03.2020', 'MM.YYYY')) and a.account_open_date <= last_day(to_date('03.2020', 'MM.YYYY'))
Thanks for help
If SQL*Developer, or SQLPlus, you can use the 'substitution variables'.
SELECT sum(a.limit_amount) as LIMIT,
sum(b.balance_amount) as OUTSTANDING,
'LOAN' as TYPE,
'Q1 2020' as QUARTER -- << probably want TO_CHAR('&&1', 'Q YYYY') or similar here
FROM accounts a
left join account_balances b
ON a.account_key = b.account_key
AND b.balance_type_key = 16
AND b.balance_date = last_day(to_date('&&1', 'MM.YYYY'))
WHERE a.account_close_date > last_day(to_date('&&1', 'MM.YYYY')) and a.account_open_date <= last_day(to_date('&&1', 'MM.YYYY'))
When you run this it will prompt you for the value.
If you used just '&1' it would prompt you for each occurence.
'&&1' reuses the value of the first occurence.
You could specify different variables using &1, &2, ...
Also you may used named variable as follows:
To prompt for the date :
ACCEPT dt CHAR PROMPT 'ENter the date (MM.YYYY): '
Or setting the value at declaration:
DEFINE dt='03.2020'
Then:
SELECT sum(a.limit_amount) as LIMIT,
sum(b.balance_amount) as OUTSTANDING,
'LOAN' as TYPE,
'Q1 2020' as QUARTER -- << probably want TO_CHAR('&&dt', 'Q YYYY') or similar here
FROM accounts a
left join account_balances b
ON a.account_key = b.account_key
AND b.balance_type_key = 16
AND b.balance_date = last_day(to_date('&&dt', 'MM.YYYY'))
WHERE a.account_close_date > last_day(to_date('&&dt', 'MM.YYYY')) and a.account_open_date <= last_day(to_date('&&dt', 'MM.YYYY'))
Ok first of all a disclaimer:
As I know nothing about your original query's logic - the query I propose only shows the main logic - and probably will not run as is.
Having said that - the approach would be:
Based on parameters :start_y (start year) and :end_y (end year)
generate a list with all the quarters for those years years_and_quarters.
Join the years_and_quarters with the required table based on quarter start and end dates - and then calculate the sums grouping by year and quarter.
with quarters as
(
select 'Q1' quarter, '03' q_end_date, '01' q_start_date from dual
union
select 'Q2' quarter, '06' q_end_date,'04' q_start_date from dual
union
select 'Q3' quarter, '09' q_end_date,'07' q_start_date from dual
union
select 'Q4' quarter, '12' q_end_date,'10' q_start_date from dual
),
years as
(select :start_y + (level-1) as mydate
from dual
connect by level <= (:end_y - :start_y) +1
),
years_and_quarters as (
select * from years,quarters
order by mydate
),
accounts as (
SELECT a.limit_amount ,
b.balance_amount,
'LOAN' as TYPE, b.balance_date,a.account_open_date,a.account_close_date
FROM accounts a
left join account_balances b
ON a.account_key = b.account_key
AND b.balance_type_key = 16
)
select sum(accounts.limit_amount) as LIMIT,
sum(accounts.balance_amount) as OUTSTANDING,
years_and_quarters.quarter,
accounts.TYPE
from
years_and_quarters,accounts
where
trunc(balance_date) = last_day(to_date(q_end_date||'.'||mydate, 'MM.YYYY'))
and trunc(account_close_date) > last_day(to_date(q_end_date||'.'||mydate, 'MM.YYYY')) and trunc(account_open_date) <= last_day(to_date(q_end_date||'.'||mydate, 'MM.YYYY'))
group by years_and_quarters.mydate,years_and_quarters.quarter
How about just aggregate by the quarter?
SELECT sum(a.limit_amount) as LIMIT,
sum(b.balance_amount) as OUTSTANDING,
'LOAN' as TYPE,
to_char(balance_date, '"Q"Q YYYY') as quarter
FROM accounts a LEFT JOIN
account_balances b
ON a.account_key = b.account_key AND
b.balance_type_key = 16 AND
b.balance_date = LAST_DAY(TRUNC(balance_date, 'Q') + INTERVAL '2' MONTH)
WHERE a.account_close_date > LAST_DAY(TRUNC(balance_date, 'Q') + INTERVAL '2' MONTH) AND
a.account_open_date <= LAST_DAY(TRUNC(balance_date, 'Q') + INTERVAL '2' MONTH)
GROUP BY TRUNC(balance_date, 'Q') ;
Your query seems focused on the last day of the quarter. This arrives at that by adding two months to the start and using LAST_DAY().

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!!

SQL query from Oracle SQL to T-SQL

I have a subquery which is used for an Oracle database, but I want to use an equivalent query for a SQL Server database.
I didn't figure out how to migrate the TO_TIMESTAMP(TO_CHAR(TO_DATE part and also didn't know how to handle the thing with rownums in T-SQL.
Is it even possible to migrate this query?
SELECT 0 run_id,
0 tran_id,
0 sort_id,
' ' tran_type,
10 prod_id,
72 type_id,
1 value,
TO_TIMESTAMP(TO_CHAR(TO_DATE('2016-03-18 00:00:00', 'YYYY.MM.DD HH24:MI:SS') + rownum -1, 'YYYY.MM.DD') || to_char(sw.end_time, 'HH24:MI:SS'), 'YYYY.MM.DD HH24:MI:SS') event_publication,
EXTRACT (YEAR
FROM (TO_DATE('2016-03-18 00:00:00', 'YYYY.MM.DD HH24:MI:SS') + rownum -1)) y,
EXTRACT (MONTH
FROM (TO_DATE('2016-03-18 00:00:00', 'YYYY.MM.DD HH24:MI:SS') + rownum -1)) mo,
EXTRACT (DAY
FROM (TO_DATE('2016-03-18 00:00:00', 'YYYY.MM.DD HH24:MI:SS') + rownum -1)) d,
to_number(to_char (sw.end_time, 'HH24')) h,
to_number(to_char (sw.end_time, 'MI')) mi,
to_number(to_char (sw.end_time, 'SS')) s,
0 ms
FROM all_objects ao,
settlement_win sw,
prod_def pd
WHERE pd.prod_id = 10
AND sw.country = pd.country
AND sw.commodity = pd.commodity
AND rownum <= TO_DATE('2016-03-18 23:59:00', 'YYYY.MM.DD HH24:MI:SS') -TO_DATE('2016-03-18 00:00:00', 'YYYY.MM.DD HH24:MI:SS')+1
The first thing to address is the use of rownum which has no direct equivalent in TSQL but we can mimic it, and for this particular query you need to recognize that the table ALL_OBJECTS is only being used to produce a number of rows. It has no other purpose to the query.
In TSQL we can generate rows using a CTE and there are many many variants of this, but for here I suggest:
;WITH
cteDigits AS (
SELECT 0 AS digit UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL
SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
)
, cteTally AS (
SELECT
d1s.digit
+ d10s.digit * 10
+ d100s.digit * 100 /* add more like this as needed */
-- + d1000s.digit * 1000 /* add more like this as needed */
+ 1 AS rownum
FROM cteDigits d1s
CROSS JOIN cteDigits d10s
CROSS JOIN cteDigits d100s /* add more like this as needed */
--CROSS JOIN cteDigits d1000s /* add more like this as needed */
)
This will quickly spin-up 1000 rows as is and can be extended to produce many more rows by adding more cross joins. Note this returns a column called rownum which starts at 1 thus mimicking the Oracle rownum.
So next you can just add some of the remaining query, like this:
SELECT
0 run_id
, 0 tran_id
, 0 sort_id
, ' ' tran_type
, 10 prod_id
, 72 type_id
, 1 value
, convert(varchar, dateadd(day, rownum - 1,'20160318'),121) event_publication
-- several missing rows here
, 0 ms
FOM cteTally
INNER JOIN settlement_win sw
INNER JOIN prod_def pd ON sw.country = pd.country AND sw.commodity = pd.commodity
WHERE pd.prod_id = 10
AND rownum <= datediff(day,'20160318','20160318') + 1
Note that you really do not need a to_timestamp() equivalent you just need the ability to output date and time to the maximum precision of your data which appears to be to the level of seconds.
To progress further (I think) requires an understanding of the data held in the column sw.end_time. If this can be converted to the mssql datetime data type then it is just a matter of adding a number of days to that value to arrive at the event_publication and similarly if sw.end_time is converted to a datetime data type then use date_part() to get the hours, minutes and seconds from that column. e.g.
, DATEADD(day,rownum-1,CONVERT(datetime, sw.end_time)) AS event_publication
also, if such a calculation works then it would be possible to use an apply operator to simplify the overall query, something like this
;WITH
cteDigits AS (
SELECT 0 AS digit UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL
SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
)
, cteTally AS (
SELECT
d1s.digit
+ d10s.digit * 10
+ d100s.digit * 100 /* add more like this as needed */
-- + d1000s.digit * 1000 /* add more like this as needed */
+ 1 AS rownum
FROM cteDigits d1s
CROSS JOIN cteDigits d10s
CROSS JOIN cteDigits d100s /* add more like this as needed */
--CROSS JOIN cteDigits d1000s /* add more like this as needed */
)
SELECT
0 run_id
, 0 tran_id
, 0 sort_id
, ' ' tran_type
, 10 prod_id
, 72 type_id
, 1 value
, convert(varchar(23), CA.Event_publication, 121) Event_publication
, datepart(day,CA.Event_publication) dd
, datepart(month,CA.Event_publication) mm
, datepart(year,CA.Event_publication) yyyy
, datepart(hour,CA.Event_publication) hh24
, datepart(minute,CA.Event_publication) mi
, datepart(second,CA.Event_publication) ss
, 0 ms
FOM cteTally
INNER JOIN settlement_win sw
INNER JOIN prod_def pd ON sw.country = pd.country AND sw.commodity = pd.commodity
CROSS APPLY (
SELECT DATEADD(day,rownum-1,CONVERT(datetime, sw.end_time)) AS event_publication ) CA
WHERE pd.prod_id = 10
AND rownum <= datediff(day,'20160318','20160318') + 1
NB: IT may be necessary to include this datediff(day,'19000101,'20160318') (which equals 42445) into the calculation of the event_date e.g.
SELECT DATEADD(day,42445 + (rownum-1),CONVERT(datetime, sw.end_time)) AS event_publication
One last point is that you could use datetime2 instead of datetime if you really do need a greater degree of time precision but there is no easily apparent requirement for that.

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

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;