This query giving error, While executing this syntax error comes for AS LastYearVolumeBilled - oracle

Error comes on AS LastYearVolumeBilled this line how to add two case when in one select statement
select 'R-1' as Year,
(case when SDBM_MONTH_YR = to_number(extract(year from sysdate) || '04')then
round((sum(SDBM_BILLED_UNITS)/avg(sdbm_billing_days))/1000,2)
end )AS CurrentYearVolumeBilled
FROM t_servicedetail_billing
where SDBM_MONTH_YR= to_number(extract(year from sysdate) || '04')
group by SDBM_MONTH_YR ,
(CASE WHEN SDBM_MONTH_YR = to_number( extract(year from add_months(sysdate,-12)) || '04')
THEN round((sum(SDBM_BILLED_UNITS)/avg(sdbm_billing_days))/1000,2)
END)AS LastYearVolumeBilled
FROM t_servicedetail_billing
where SDBM_MONTH_YR= to_number( extract(year from add_months(sysdate,-12)) || '04')
group by SDBM_MONTH_YR;

These are two different queries, so one option might be to treat them as such by using a CTE (as my example shows) or as subqueries.
WITH
t_curr
AS
( SELECT 'R-1' AS year,
(CASE
WHEN sdbm_month_yr =
TO_NUMBER (EXTRACT (YEAR FROM SYSDATE) || '04')
THEN
ROUND (
(SUM (sdbm_billed_units) / AVG (sdbm_billing_days))
/ 1000,
2)
END) AS currentyearvolumebilled
FROM t_servicedetail_billing
WHERE sdbm_month_yr = TO_NUMBER (EXTRACT (YEAR FROM SYSDATE) || '04')
GROUP BY sdbm_month_yr),
t_last
AS
( SELECT 'R-1' AS year,
(CASE
WHEN sdbm_month_yr =
TO_NUMBER (
EXTRACT (YEAR FROM ADD_MONTHS (SYSDATE, -12))
|| '04')
THEN
ROUND (
(SUM (sdbm_billed_units) / AVG (sdbm_billing_days))
/ 1000,
2)
END) AS lastyearvolumebilled
FROM t_servicedetail_billing
WHERE sdbm_month_yr =
TO_NUMBER (
EXTRACT (YEAR FROM ADD_MONTHS (SYSDATE, -12)) || '04')
GROUP BY sdbm_month_yr)
SELECT a.year, a.currentyearvolumebilled, b.lastyearvolumebilled
FROM t_curr a CROSS JOIN t_last b;
How to add more subqueries (simplified):
with
t_curr_r1 as
(select 'R-1' as year, ... from ...),
t_curr_r2 as
(select 'R-2' as year, ... from ...),
t_curr_r3 as
(select 'R-3' as year, ... from ...),
--
t_last_r1
(select 'R-1' as year, ... from ...),
t_last_r2 as
(select 'R-2' as year, ... from ...),
t_last_r3 as
(select 'R-3' as year, ... from ...),
--
select c1.year, c1.currentyearvolumebilled,
c2.currentyearvolumebilled,
c3.currentyearvolumebilled,
...
l1.lastyearvolumebilled,
l2.lastyearvolumebilled,
l3.lastyearvolumebilled,
...
from t_curr_r1 c1 cross join t_curr_r2 c2
cross join t_curr_r3 c3
...
cross join t_last_r1 l1
cross join t_last_r2 l2
cross join t_last_r3 l3
...

You have repeated your query twice. You don't need a case statement cause you have the same condition in where clause. So the correct query might be -
select 'R-1' as Year,
round((sum(SDBM_BILLED_UNITS)/avg(sdbm_billing_days))/1000,2)
END AS CurrentYearVolumeBilled
FROM t_servicedetail_billing
WHERE SDBM_MONTH_YR = to_number(extract(year from sysdate) || '04')

Related

How to compare system month and sales months?

I want to compare sales months with the system month. if equal get 1 output as new column(last_month) else 0. I tried below oracle query but I am getting a Null value.
SELECT a.agent_id,a.agent_name,a.ivr_registered_district,s.agent_type,s.district,s.province,a.parent_level1_id,a.parent_level1,a.sales_channel,TO_CHAR(TRUNC(a.connection_date, 'MONTH'), 'MON-YYYY') AS MONTHYEAR,
CASE
WHEN TO_CHAR(TRUNC(a.connection_date, 'MONTH'), 'MON-YYYY') = TO_CHAR(ADD_MONTHS(SYSDATE, - 1))
THEN 1
END as last_month
FROM EDW_TGT.FACT_LTE_SALES_CHANNELS a
JOIN SFA.sfa_agent_dtl s
ON a.agent_id = s.agent_id
where a.pre_post = 'LTE-PREPAID' and a.sales_channel in ('BUSINESS PARTNER', 'INSTITUSIONAL', 'REGIONAL TRADE PARTNERS', 'DISTRIBUTOR')
and a.connection_date >= TO_DATE('2020-01-01 00:00:0', 'YYYY-MM-DD HH24:MI:SS')
You don't need to truncate date as oracle provides you functionality to extract (day,month,year) from to_date function.
Your query should be like below.
SELECT a.agent_id,a.agent_name,a.ivr_registered_district,s.agent_type,s.district,s.province,a.parent_level1_id,a.parent_level1,a.sales_channel,TO_CHAR(TRUNC(a.connection_date, 'MONTH'), 'MON-YYYY') AS MONTHYEAR,
CASE
WHEN to_char(to_date(a.connection_date, 'DD-MM-YYYY'), 'Month') = to_char(to_date(sysdate-1, 'DD-MM-YYYY'), 'Month')
THEN 1
Else 0
END as last_month
FROM EDW_TGT.FACT_LTE_SALES_CHANNELS a
JOIN SFA.sfa_agent_dtl s
ON a.agent_id = s.agent_id
where a.pre_post = 'LTE-PREPAID' and a.sales_channel in ('BUSINESS PARTNER', 'INSTITUSIONAL', 'REGIONAL TRADE PARTNERS', 'DISTRIBUTOR')
and a.connection_date >= TO_DATE('2020-01-01 00:00:0', 'YYYY-MM-DD HH24:MI:SS')

Pl / SQL Oracle helps to run a Date in Subquery

How could I get the date of the Maximum Value, by means of a subquery
I can't put the Date in the Main query because I would have to add it to the group by it would bring me a lot of data
Here is the Code:
SELECT MAX (A1.VALOR) AS VALOR,
(SELECT sq1.FECHA
FROM VARIABLE_VALORES_SMEC sq1
WHERE sq1.ID_AGENTE = A1.ID_AGENTE)
MES, -- {<-- Here is the Problem}
(SELECT CODIGO_AGENTE
FROM AGENTES
WHERE ID_AGENTE = A1.ID_AGENTE)
Agentess,
(SELECT NOMBRE_AGENTE
FROM AGENTES
WHERE ID_AGENTE = A1.ID_AGENTE)
Nombre_Agente
FROM VARIABLE_VALORES_SMEC A1
WHERE A1.VALOR < '1'
AND A1.VALOR != '0'
AND A1.ID_AGENTE IN (SELECT C1.ID_AGENTE
FROM VARIABLE_VALORES_SMEC C1
WHERE A1.FECHA = C1.FECHA)
AND A1.ID_AGENTE IN (SELECT B1.ID_AGENTE
FROM AGENTES B1
WHERE ID_CATEGORIA_AGENTE = 'AC006')
AND (A1.FECHA BETWEEN (ADD_MONTHS (TO_DATE ( :FECHAIN, 'MM/DD/YYYY'),
-1))
AND (LAST_DAY (
ADD_MONTHS (
TO_DATE ( :FECHAIN, 'MM/DD/YYYY'),
-1))))
AND A1.ID_VARIABLE LIKE '%_calc_total_pot#%'
GROUP BY ID_AGENTE
Am I correct that you need (fecha) for maximum A1.VALOR?
If - yes, you can use the following query, or if - no, just replace A1.VALOR with the required column in keep() clause:
SELECT MAX (A1.VALOR) AS VALOR,
max(A1.FECHA)keep(dense_rank first order by A1.VALOR desc) MES, -- A1.VALOR is used here as sort key, replace it with what you want
(SELECT CODIGO_AGENTE
FROM AGENTES
WHERE ID_AGENTE = A1.ID_AGENTE)
Agentess,
(SELECT NOMBRE_AGENTE
FROM AGENTES
WHERE ID_AGENTE = A1.ID_AGENTE)
Nombre_Agente
FROM VARIABLE_VALORES_SMEC A1
WHERE A1.VALOR < '1'
AND A1.VALOR != '0'
AND A1.ID_AGENTE IN (SELECT C1.ID_AGENTE
FROM VARIABLE_VALORES_SMEC C1
WHERE A1.FECHA = C1.FECHA)
AND A1.ID_AGENTE IN (SELECT B1.ID_AGENTE
FROM AGENTES B1
WHERE ID_CATEGORIA_AGENTE = 'AC006')
AND (A1.FECHA BETWEEN (ADD_MONTHS (TO_DATE ( :FECHAIN, 'MM/DD/YYYY'),
-1))
AND (LAST_DAY (
ADD_MONTHS (
TO_DATE ( :FECHAIN, 'MM/DD/YYYY'),
-1))))
AND A1.ID_VARIABLE LIKE '%_calc_total_pot#%'
GROUP BY ID_AGENTE
You can use row_number analytical function to fetch one record for which value is highest and use the fecha of that record. Use following sub query:
(Select fecha from
(SELECT sq1.FECHA, row_number() over (order by sq1.value desc nulls last) as rn
FROM VARIABLE_VALORES_SMEC sq1
WHERE sq1.ID_AGENTE = A1.ID_AGENTE)
Where rn = 1) MES

Fill in gaps in cumulative query

I have the following query to calculate a cumulative sum:
SELECT to_char(INVC_DT, 'MON-YYYY') AS MONTH,
SUM(INVC_AMT),
SUM(SUM(INVC_AMT)) OVER (ORDER BY MIN(INVC_DT))
FROM T_INVC_INFO I INNER JOIN T_TASK_INFO T ON I.TASK_ID = T.TASK_ID
WHERE T.CNTRCT_ID = #session.user.cntrct_id#
GROUP BY to_char(INVC_DT, 'MON-YYYY')
ORDER BY MONTH DESC;
The problem I have is that I need to fill in the gaps in time. For example, if I have data for JAN, FEB, and APR, I need another row for MAR with value 0.
You may introduce a calendar table into your query, which will represent every month/year which you want to appear in your output. Assuming you wanted to cover all of 2017 to 2019, you might try:
WITH years AS (
SELECT '2017' AS year FROM dual UNION ALL
SELECT '2018' FROM dual UNION ALL
SELECT '2019' FROM dual
),
months AS (
SELECT 'JAN' AS month FROM dual UNION ALL
SELECT 'FEB' FROM dual UNION ALL
...
SELECT 'DEC' FROM dual
)
SELECT
m.month || '-' || y.year AS MONTH,
SUM(INVC_AMT),
SUM(SUM(INVC_AMT)) OVER (ORDER BY MIN(INVC_DT))
FROM years y
CROSS JOIN months m
LEFT JOIN T_INVC_INFO i
ON m.month || '-' || y.year = TO_CHAR(i.INVC_DT, 'MON-YYYY')
LEFT JOIN T_TASK_INFO t
ON i.TASK_ID = t.TASK_ID AND
t.CNTRCT_ID = #session.user.cntrct_id#
WHERE
TO_DATE(m.month || '-' || y.year, 'MON-YYYY') BETWEEN
(SELECT MIN(INVC_DT) FROM T_INVC_INFO) AND
(SELECT MAX(INVC_DT) FROM T_INVC_INFO)
GROUP BY
m.month || '-' || y.year
ORDER BY
MONTH DESC;

Oracle GRoup by 7 Days

I'm trying to group seven days period for each date, but this seems not to work.
select
START_DATE-7 FROM_DATES,
SUM(EVENT_B),
SUM(EVENT_B)
FROM (
select
nvl(ENT1.DATE_FIELD,ENT2.DATE_FIELD)as START_DATE,
nvl(ENT1.EVENT_A,0) as EVENT_A,
nvl(ENT2.EVENT_B,0) as EVENT_B
from
(select
DATE_FIELD, SUM(NR_EVENTS) as EVENT_A
from TABLE_A
where EVENT_NAME in ('CALL', 'EDIT','INSERT')
group by START_DATE,START_HOUR,SUBSCRIBER_TYPE,CO_ID
) ENT1
FULL OUTER JOIN
(select
DATE_FIELD,
SUM(NR_EVENTS) as EVENT_B
from TABLE_B
where EVENT_NAME in ('CALL', 'EDIT','INSERT')
group by DATE_FIELD
) ENT2
on (
ENT1.DATE_FIELD=ENT2.DATE_FIELD)
)
WHERE
START_DATE >= START_DATE-7
AND START_DATE <= START_DATE-1
gROUP BY
START_DATE-7
The output im getting:
9/8/2014 262187 280365
9/7/2014 509405 478245
9/6/2014 564663 537996
9/5/2014 661871 632689
9/4/2014 669788 638839
Its only sum for one day not 7
The output should be
2014-09-15, (sum of event from A side in a 7 days period - 2014-09-15-7 to 2014-09-15) , (sum of event from B side in a 7 days period - 2014-09-15-7 to 2014-09-15)
2014-09-14, (sum of event from A side in a 7 days period - 2014-09-14-7 to 2014-09-14) , (sum of event from B side in a 7 days period - 2014-09-14-7 to 2014-09-14)
2014-09-13, (sum of event from A side in a 7 days period - 2014-09-13-7 to 2014-09-13) , (sum of event from B side in a 7 days period - 2014-09-13-7 to 2014-09-13)
etc...
Can anyone help me out?
with event_dates as (
select d_field from table_a
union
select d_field from table_b
)
select
d_field from_date,
d_field to_date,
(
select nvl(sum(nr_events),0) from table_a
where event_name in ('CALL', 'EDIT', 'INSERT')
and d_field between e.d_field and e.d_field+6
) nr_events_a,
(
select nvl(sum(nr_events),0) from table_b
where event_name in ('CALL', 'EDIT', 'INSERT')
and d_field between e.d_field and e.d_field+6
) nr_events_b
from event_dates e;
I made SQL Fiddle based on your original post and notes from Lalit Kumar B. Answer above includes event_name field filter which was later added.
Your query is incorrect.
Firstly, your output doesn't match with the selected columns. If 1st column is D_FIELD1+7, then how is that in the output the first column values are D_FIELD1?
Secondly, the predicate AND D_FIELD1 BETWEEN D_FIELD1+7 AND D_FIELD1 is ambiguous.
Thirdly, BETWEEN will include the upper and lower bound, so you will get the window of 8 days and not 7 days.
You could use an Analytic function with an Interval e.g.
SELECT nvl(ent1.date_field, ent2.date_field) - 6 start_date
, nvl(ent1.date_field, ent2.date_field) end_date
, sum(event_a) OVER
(ORDER BY nvl(ent1.date_field, ent2.date_field)
RANGE numtodsinterval(6, 'day') PRECEDING
) sum_event_a
, sum(event_b) OVER
(ORDER BY nvl(ent1.date_field, ent2.date_field)
RANGE numtodsinterval(6, 'day') PRECEDING
) sum_event_b
FROM (SELECT date_field,
sum(nr_events) AS event_a
FROM table_a
WHERE event_name IN ('CALL', 'EDIT', 'INSERT')
GROUP BY date_field
) ent1
FULL OUTER JOIN
(SELECT date_field,
sum(nr_events) AS event_b
FROM table_b
WHERE event_name IN ('CALL', 'EDIT', 'INSERT')
GROUP BY date_field
) ent2
ON (ent1.date_field = ent2.date_field)
I suggest you change the way of get the sums, I prefer in this case analytic functions. Try something like this:
SELECT START_DATE - 7 FROM_DATES,
SUM (EVENT_A) OVER (ORDER BY START_DATE RANGE 7 PRECEDING),
SUM (EVENT_B) OVER (ORDER BY START_DATE RANGE 7 PRECEDING)
FROM (SELECT NVL (ENT1.DATE_FIELD, ENT2.DATE_FIELD) AS START_DATE,
NVL (ENT1.EVENT_A, 0) AS EVENT_A,
NVL (ENT2.EVENT_B, 0) AS EVENT_B
FROM ( SELECT DATE_FIELD, SUM (NR_EVENTS) AS EVENT_A
FROM TABLE_A
WHERE EVENT_NAME IN ('CALL', 'EDIT', 'INSERT')
GROUP BY START_DATE,
START_HOUR,
SUBSCRIBER_TYPE,
CO_ID) ENT1
FULL OUTER JOIN
( SELECT DATE_FIELD, SUM (NR_EVENTS) AS EVENT_B
FROM TABLE_B
WHERE EVENT_NAME IN ('CALL', 'EDIT', 'INSERT')
GROUP BY DATE_FIELD) ENT2
ON (ENT1.DATE_FIELD = ENT2.DATE_FIELD))

self join with max value

I am have a table with 500k transactions. I want to fetch the last balance for a particular date. So I have have returned a query like below.
SELECT curr_balance
FROM transaction_details
WHERE acct_num = '10'
AND is_deleted = 'N'
AND ( value_date, srl_num ) IN(
SELECT MAX( value_date ), MAX( srl_num )
FROM transaction_details
WHERE TO_DATE( value_date, 'dd/mm/yyyy' )
<= TO_DATE( ADD_MONTHS( '05-APR-2012', 1 ), 'dd/mm/yyyy' )
AND acct_num = '10'
AND is_deleted = 'N'
AND ver_status = 'Y' )
AND ver_status = 'Y'
This has to be executed for incrementing of 12 months to find the last balance for each particular month. But this query is having more cpu cost, 12 times it is taking huge time. How to remodify the above query to get the results in faster way. Whether this can be broken into two part in PL/SQL to achieve the performance. ?
Try:
select * from(
SELECT value_date, srl_num, curr_balance
FROM transaction_details
WHERE acct_num = '10'
AND is_deleted = 'N'
AND ver_status = 'Y'
row_number() over (partition by trunc(value_date - interval '5' day,'MM')
order by srl_num desc
) as rnk
)
where rnk = 1;
You'll get a report with the ballance on last srl_num on each month in your table.
The benefit is that your approach scans the table 24 times for 12 months report and my approach scans the table once.
The analytic function gets the rank of record in current month(partition by clause) ordering the rows in the month after srl_num.
You don't have to query your table twice. Try using analytic functions
SELECT t.curr_balance
-- , any other column you want as long it is in the subselect.
FROM (
SELECT
trans.curr_balance
, trans.value_date
-- any other column you want
, trans.srl_num
, MAX(trans.srl_num) OVER(PARTITION BY trans.value_date, trans.srl_num) max_srl_num
, MAX(trans.value_date) OVER(PARTITION BY trans.value_date, trans.srl_num) max_date
FROM transaction_details trans
WHERE TO_DATE( value_date, 'dd/mm/yyyy' ) <= TO_DATE( ADD_MONTHS( '01-APR-2012', 1 ), 'dd/mm/yyyy' )
AND acct_num = '10'
AND is_deleted = 'N'
AND ver_status = 'Y'
) t
WHERE t.max_date = t.value_date
AND t.max_srl_num = t.srl_num
A couple of thoughts.
Why do you have TO_DATE( value_date...? Isn't your data type DATE? this might be breaking your index if you have one in that column.
Note that (this is a wild guess) if your srl_num is not the highest for the latest date, you will have incorrect results and might not return any rows.

Resources