Can I create a date variable in R for dbGetQuery? - r

This is my code:
cohort_query <- dbGetQuery(con,'select u.unique_id customer_id,
o.user_id user_hash,
"min"(o.deliveryconfirmeddate) first_order,
(
CASE
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(\'2021-11-01\') - INTERVAL \'1\' YEAR)
) THEN 0
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(\'2021-11-01\') - INTERVAL \'2\' YEAR)
) THEN 1
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(\'2021-11-01\') - INTERVAL \'3\' YEAR)
) THEN 2
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(\'2021-11-01\') - INTERVAL \'4\' YEAR)
) THEN 3
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(\'2021-11-01\') - INTERVAL \'5\' YEAR)
) THEN 4
ELSE 5
END
) "cohort_year",
min(o.id) as first_order_id
FROM (
"bj-analytics"."mysql_bj_orders" o
INNER JOIN "bj-analytics"."mysql_bj_users" u ON (u.user_id = o.user_id)
)
WHERE (
(
(o.connectedorder = false)
AND (o.status <> \'cancelled\')
)
AND (o.status <> \'Cancelled\')
)
GROUP BY 1,
2
HAVING (
"min"(o.deliveryconfirmeddate) >= (date(\'2021-11-01\') - INTERVAL \'6\' YEAR)
)
and "min"(o.deliveryconfirmeddate) < date(\'2021-11-01\')')
This all runs fine. Basically, I want to make the 2021-11-01 date a variable, so that I only have to enter it once.
Someone recommended glue_sql but I couldn't make it work. I think it's an issue with the double quotation marks and the single marks. I tried to change these to all "" or to all '' but then the query just doesn't run!
I also found that I have to include \'s - again without them doesn't seem to run.
I'm new to R so not too sure how to get around this!
Basically can anyone please help with turning that date into a variable?
Any help is much appreciated - thanks!

Never use paste or sprintf to put "data" into a query, for many reasons (query optimization/caching and accidental sql-injection being the top two), instead use parameter-binding:
DBI::dbGetQuery(con, "
select (case
when (5 < ?) then 5
when (3 < ?) then 3
when (1 < ?) then 1
else 0 end) as quux",
params = replicate(n=3, expr=3, simplify = FALSE))
# quux
# 1 1
DBI::dbGetQuery(con, "
select (case
when (5 < ?) then 5
when (3 < ?) then 3
when (1 < ?) then 1
else 0 end) as quux",
params = replicate(n=3, expr=10, simplify = FALSE))
# quux
# 1 5
The replicate(3,10,F) is just a programmatic way to do list(10,10,10), they are equivalent here. My use of static comparisons (5 < ?) is solely for placeholders, your min(.) should work fine.
(FYI, one more benefit of parameter-binding: no need to deal with additional quotes in the query.)
See https://db.rstudio.com/best-practices/run-queries-safely/#parameterized-queries for more discussions on safely using data in the query.
I think that would make your query this:
cohort_query <- dbGetQuery(con, 'select u.unique_id customer_id,
o.user_id user_hash,
"min"(o.deliveryconfirmeddate) first_order,
(
CASE
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(?) - INTERVAL \'1\' YEAR)
) THEN 0
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(?) - INTERVAL \'2\' YEAR)
) THEN 1
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(?) - INTERVAL \'3\' YEAR)
) THEN 2
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(?) - INTERVAL \'4\' YEAR)
) THEN 3
WHEN (
"min"(o.deliveryconfirmeddate) >= (date(?) - INTERVAL \'5\' YEAR)
) THEN 4
ELSE 5
END
) "cohort_year",
min(o.id) as first_order_id
FROM (
"bj-analytics"."mysql_bj_orders" o
INNER JOIN "bj-analytics"."mysql_bj_users" u ON (u.user_id = o.user_id)
)
WHERE (
(
(o.connectedorder = false)
AND (o.status <> \'cancelled\')
)
AND (o.status <> \'Cancelled\')
)
GROUP BY 1,
2
HAVING (
"min"(o.deliveryconfirmeddate) >= (date(?) - INTERVAL \'6\' YEAR)
)
and "min"(o.deliveryconfirmeddate) < date(?)'),
params = replicate(n=7, expr='2021-11-01', simplify=FALSE)

Related

Is it possible to replace sub-queries, used as a scalar value, with CTE?

I want to replace a long sub-query that return a scalar value or does not exist with just a short alias, because I place it 3 times to the UPDATE statement. Sub-query takes the last value in UncoveredLoss, if there is one, and the new UncoveredLoss value is calculated in the updated row depending on the last UncoveredLoss value.
It is a non-correlated query, but it is used in SELECT clause, not in the FROM clause. Maybe I should somehow modify the UPDATE statement in the trigger.
The working code:
CREATE TRIGGER Result
UPDATE OF Win ON Log
BEGIN
UPDATE Log
SET Profit = CASE
WHEN NEW.Win = 0
THEN - Stake
WHEN NEW.Win = 1
THEN Rate * Stake / 100
WHEN NEW.Win = 2
THEN 0
END
WHERE ID = OLD.ID;
UPDATE Log
SET SumProfit = (
SELECT Sum(Profit)
FROM (
SELECT StrategyAccountID
,Profit
FROM Log
WHERE DATE <= NEW.DATE
)
GROUP BY StrategyAccountID
HAVING StrategyAccountID = NEW.StrategyAccountID
)
WHERE ID = NEW.ID;
UPDATE Log
SET UncoveredLoss = CASE
WHEN EXISTS (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
)
AND (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
) + NEW.Profit < 0
THEN (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
) + NEW.Profit
WHEN NOT EXISTS (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
)
AND NEW.Profit < 0
THEN NEW.Profit
ELSE 0
END
WHERE ID = NEW.ID;
END;
The simple replacement of the sub-query using CTE not working:
CREATE TRIGGER Result
UPDATE OF Win ON Log
BEGIN
UPDATE Log
SET Profit = CASE
WHEN NEW.Win = 0
THEN - Stake
WHEN NEW.Win = 1
THEN Rate * Stake / 100
WHEN NEW.Win = 2
THEN 0
END
WHERE ID = OLD.ID;
UPDATE Log
SET SumProfit = (
SELECT Sum(Profit)
FROM (
SELECT StrategyAccountID
,Profit
FROM Log
WHERE DATE <= NEW.DATE
)
GROUP BY StrategyAccountID
HAVING StrategyAccountID = NEW.StrategyAccountID
)
WHERE ID = NEW.ID;
WITH Loss
AS (
SELECT UncoveredLoss
FROM Log
WHERE DATE < NEW.DATE
AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY DATE DESC LIMIT 1
)
UPDATE Log
SET UncoveredLoss = CASE
WHEN EXISTS (Loss)
AND (Loss) + NEW.Profit < 0
THEN (Loss) + NEW.Profit
WHEN NOT EXISTS (Loss)
AND NEW.Profit < 0
THEN NEW.Profit
ELSE 0
END
WHERE ID = NEW.ID;
END;
Error: near "UPDATE": syntax error
It works nicely when I don't replace the sub-query, but when I try to use CTE it fails. I work in sql.el mode in Emacs.
Yeah, that can be cleaned up a lot. Consider something like:
CREATE TRIGGER Result UPDATE OF Win ON Log BEGIN
UPDATE Log
SET SumProfit = (SELECT sum(Profit)
FROM Log
WHERE Date <= NEW.Date AND StrategyAccountID = NEW.StrategyAccountID)
, UncoveredLoss = ifnull((SELECT min(UncoveredLoss + NEW.Profit, 0)
FROM Log
WHERE Date < NEW.Date AND StrategyAccountID = NEW.StrategyAccountID
ORDER BY Date DESC
LIMIT 1), 0)
WHERE ID = NEW.ID;
END;
which I'm pretty sure calculates the same results as yours. (Actual sample table definition and data to work with would be nice)
Also note that in recent Sqlite3 releases (3.25 and later), your SumProfit column can easily be computed on demand instead of taking up space in the table:
SELECT *
, sum(profit) OVER (PARTITION BY StrategyAccountID ORDER BY Date) AS SumProfit
FROM Log;

Update statement not providing correct result in a BTEQ after Teradata 15 upgradation

An update statement is not working when executed inside BTEQ after Teradata 15 upgrade. The statement gives required output if executed from SQL Assistant manually. The statement is having a simple code.
---Update statement
UPDATE MAIN2
FROM
PSE_BIX_ABT.TP_ABT_DT_MOB_SBSCR_MAIN2 AS MAIN2,
(
SELECT DISTINCT
SBSCR_ID,
( SELECT DT FROM PSE_BIX_ABT.TP_ABT_DT_MOB_SBSCR_DT WHERE ID = 1 ) AS SNAP_DT,
SRVC_PRVDR_ID AS PORTED_IN_DNR_SP_ID,
SRVC_PRVDR_NM AS PORTED_IN_DNR_SP_NM,
OREPLACE(OREPLACE(SRVC_PRVDR_DESC,'[Fixed]',''),'[Mobile]','') AS PORTED_IN_DNR_SP_DESC,
PORT_STRT_DT AS PORTED_IN_DT,
CASE
WHEN PORTED_IN_DT = SNAP_DT THEN 1
ELSE 0
END AS PORTED_IN_CNT
FROM
PSE_BIX_SL_VW.V_F_PORTED_SBSCRS AS PORTED_SBSCR
INNER JOIN
PSE_BIX_SL_VW.V_SRVC_PRVDR SRVC
ON PORTED_SBSCR.DNR_SRVC_PRVDR_ID = SRVC.SRVC_PRVDR_ID
WHERE
PORT_IN_FL = 1
AND SBSCR_ID <> -1
AND PORT_STRT_DT <= ( SELECT DT FROM PSE_BIX_ABT.TP_ABT_DT_MOB_SBSCR_DT WHERE ID = 1 )
AND (SBSCR_ID,PORT_STRT_DT) IN (SEL SBSCR_ID,MAX(PORT_STRT_DT) FROM PSE_BIX_SL_VW.V_F_PORTED_SBSCRS WHERE PORT_STRT_DT <= ( SELECT DT FROM PSE_BIX_ABT.TP_ABT_DT_MOB_SBSCR_DT WHERE ID = 1 ) GROUP BY 1 )
) D_PORT_IN
SET
PORTED_IN_DNR_SP_ID = D_PORT_IN.PORTED_IN_DNR_SP_ID,
PORTED_IN_DNR_SP_NM = D_PORT_IN.PORTED_IN_DNR_SP_NM,
PORTED_IN_DNR_SP_DESC = D_PORT_IN.PORTED_IN_DNR_SP_DESC,
PORTED_IN_DT = D_PORT_IN.PORTED_IN_DT,
PORTED_IN_CNT = D_PORT_IN.PORTED_IN_CNT
WHERE
MAIN2.SBSCR_ID = D_PORT_IN.SBSCR_ID
AND MAIN2.SNAP_DT = D_PORT_IN.SNAP_DT;
Kindly help on the same.
Current Teradata 15.10.04.05 (Upgraded from 14)

Populating a grid view is taking too much time

I am trying to bind a gridview in asp.net, but it takes me too much time. I am using stored procedure, but in microsoft sql server management studio, the stores procedure takes only 2-3 second. My problem is when i load asp page. It takes 20-30 sec to populate my gridview... any idea?
UPDATE: My problem is in my stored procedure
SELECT
ROW_NUMBER() OVER
(
ORDER BY A.[ActiuniNumar] DESC
) as RowNum,
A.[Id],
A.[Societate_Id],
A.[Denumire],
A.[NrORC],
A.[CUI],
A.[CNP],
A.[Adresa],
A.[Localitate],
A.[Judet],
A.[Tip],
A.[ActiuniNumar],
A.[ActiuniSerie],
A.[ActiuniNumar] * [ValoareNominala] AS [ActiuniValoare],
CASE
WHEN S.[Capital] = 0 THEN 0
ELSE CAST(A.[ActiuniNumar] * 100 / S.ActiuniNumar AS decimal(18, 8))
END AS [ActiuniProcent],
A.[ActiuniNevandabileNumar],
A.[ActiuniNevandabileSerie],
A.[Diverse],
A.[SerieCI],
A.[Deleted],
A.[ModifiedBy],
A.[ModifiedAt]
INTO #Results2
FROM [dbo].[Actionar] A
INNER JOIN [dbo].[Societate] S ON A.[Societate_Id] = S.[Id]
WHERE 1 = 1
AND ((#ActiuniNumar IS NULL AND 1 = 1) OR (#ActiuniNumar IS NOT NULL AND (#ActiuniNumar = 0 AND A.[ActiuniNumar] <= 0) OR (#ActiuniNumar != 0 AND A.[ActiuniNumar] > 0)))
AND [Societate_Id] = #Id
AND ((#Filter = '' AND 1 = 1) OR (#Filter != '' AND (A.[Denumire] LIKE #Filter OR A.[NrORC] LIKE #Filter OR A.[CUI] LIKE #Filter OR A.[CNP] LIKE #Filter OR A.[ActiuniNumar] LIKE #Filter OR A.[SerieCI] LIKE #Filter)))
and A.[Deleted] = 0
ORDER BY A.[ActiuniNumar] DESC
SELECT * FROM #Results2 where RowNum BETWEEN(#pageIndex -1) * #pageSize + 1 AND(((#pageIndex -1) * #pageSize + 1) + #pageSize) - 1
It takes me 20 sec to run..
sorry if it's too late. But this happened to me. And the only solution that worked was this:
...
and A.[Deleted] = 0
--ORDER BY A.[ActiuniNumar] DESC
Comment the ORDER BY. That makes it slower.

How to get maximum column values across a row in Teradata sql?

I have a table named cnst_chrctrstc_abc with 10 columns (equ_gender1 - bb_population_flag) each row which contain numeric values (count) .
I want to get maximum 5 values out of each row across those 10 numeric columns.
The query I have looks something like the following ..
SEL
FROM
(
SEL
SUM(CASE WHEN COALESCE(act.equ_gender1,'') = COALESCE(inact.equ_gender1,'') THEN 0 ELSE 1 END ) AS equ_gender1_chg_cnt,
SUM(CASE WHEN COALESCE(act.exp_ex_bmyr1,'') = COALESCE(inact.exp_ex_bmyr1,'') THEN 0 ELSE 1 END ) AS exp_ex_bmyr1_chg_cnt,
SUM(CASE WHEN COALESCE(act.equ_age1,'') = COALESCE(inact.equ_age1,'') THEN 0 ELSE 1 END ) AS equ_age1_chg_cnt,
SUM(CASE WHEN COALESCE(act.maritalstatus1,'') = COALESCE(inact.maritalstatus1,'') THEN 0 ELSE 1 END ) AS maritalstatus1_chg_cnt,
SUM(CASE WHEN COALESCE(act.person_type1,'') = COALESCE(inact.person_type1,'') THEN 0 ELSE 1 END ) AS person_type1_chg_cnt,
SUM(CASE WHEN COALESCE(act.homeowner,'') = COALESCE(inact.homeowner,'') THEN 0 ELSE 1 END ) AS homeowner_chg_cnt,
SUM(CASE WHEN COALESCE(act.dwelling_size,'') = COALESCE(inact.dwelling_size,'') THEN 0 ELSE 1 END ) AS dwelling_size_chg_cnt,
SUM(CASE WHEN COALESCE(act.lengthofresidence,'') = COALESCE(inact.lengthofresidence,'') THEN 0 ELSE 1 END ) AS lengthofresidence_chg_cnt,
SUM(CASE WHEN COALESCE(act.childrenage0_18,'') = COALESCE(inact.childrenage0_18,'') THEN 0 ELSE 1 END ) AS childrenage0_18_chg_cnt,
SUM(CASE WHEN COALESCE(act.bb_population_flag,'') = COALESCE(inact.bb_population_flag,'') THEN 0 ELSE 1 END ) AS bb_population_flag
FROM
(SEL * FROM arc_mdm_Tbls.cnst_chrctrstc_abc WHERE load_id=1024 AND cnst_chrctrstc_end_dt='9999-12-31' (DATE))act
LEFT JOIN
(SEL * FROM arc_mdm_Tbls.cnst_chrctrstc_abc WHERE load_id=1024 AND cnst_chrctrstc_end_dt<'9999-12-31' (DATE)
QUALIFY ROW_NUMBER() OVER (PARTITION BY cnst_mstr_id ORDER BY cnst_chrctrstc_strt_ts DESC)=1
)inact
ON act.cnst_mstr_id = inact.cnst_mstr_id
)X
I know SEL GREATEST would produce the maximum value out of each row . But I want 5 top values and assign a rank to them.
Something like for some row first five columns may hold the top 5 values and for some last five i.e. homeowner to bb_population_flag may hold the top 5 values.
so if the columns and values from cnst_chrctrstc_abc look something like the following
cdi_batch_id | a | b | c | d | e | f | g | h | i |j
1024 |116|105|102|100|117|119|108|104|101|121
so the select query should return me columns j,f,e,a,g having the top 5 values.
And then I would assign a rank to them accordingly .
Should it be done using unpivot or something ?
Thanks in advance.
Yes, you need to unpivot your result.
Before TD14.10 you will need a list of those column names, either as a table
create table ColumnList (col varchar(128));
Insert into ColumnList('equ_gender1' );
Insert into ColumnList('exp_ex_bmyr1' );
Insert into ColumnList('equ_age1' );
Insert into ColumnList('maritalstatus1' );
Insert into ColumnList('person_type1' );
Insert into ColumnList('homeowner' );
Insert into ColumnList('dwelling_size' );
Insert into ColumnList('lengthofresidence' );
Insert into ColumnList('childrenage0_18' );
Insert into ColumnList('bb_population_flag');
or on-thy-fly using a bulky
with ColumnList as
(
select * from (select 'equ_gender1' as Col) as dt union all
select * from (select 'exp_ex_bmyr1' as Col) as dt union all
select * from (select 'equ_age1' as Col) as dt union all
select * from (select 'maritalstatus1' as Col) as dt union all
select * from (select 'person_type1' as Col) as dt union all
select * from (select 'homeowner' as Col) as dt union all
select * from (select 'dwelling_size' as Col) as dt union all
select * from (select 'lengthofresidence' as Col) as dt union all
select * from (select 'childrenage0_18' as Col) as dt union all
select * from (select 'bb_population_flag' as Col) as dt
)
Then you CROSS JOIN to unpivot:
select
col,
case col
when 'equ_gender1' then equ_gender1
when 'exp_ex_bmyr1' then exp_ex_bmyr1
when 'equ_age1' then equ_age1
when 'maritalstatus1' then maritalstatus1
when 'person_type1' then person_type1
when 'homeowner' then homeowner
when 'dwelling_size' then dwelling_size
when 'lengthofresidence' then lengthofresidence
when 'childrenage0_18' then childrenage0_18
when 'bb_population_flag' then bb_population_flag
end as Counts,
rank() over (order by Counts desc) as rnk
FROM
(
your current select
) as dt
cross join ColumnList
qualify rnk <= 5
In TD14.10 you could utilize the TD_UNPIVOT function:
SELECT Col, rank() over (order by Counts desc) as rnk
from TD_UNPIVOT(
ON (
your current select
)
USING
VALUE_COLUMNS('Counts')
UNPIVOT_COLUMN('Col')
COLUMN_LIST('equ_gender1'
,'exp_ex_bmyr1'
,'equ_age1'
,'maritalstatus1'
,'person_type1'
,'homeowner'
,'dwelling_size'
,'lengthofresidence'
,'childrenage0_18'
,'bb_population_flag')
) dt
qualify rnk <= 5;
Edit:
Additionally you might replace your LEFT JOIN with a single OLAP-function. Depending on the number of rows per cnst_mstr_id this might be more efficient as you need a ROW_NUMBER anyway:
SEL
SUM(CASE WHEN COALESCE(equ_gender1,'') = COALESCE(last_equ_gender1,'') THEN 0 ELSE 1 END ) AS equ_gender1_chg_cnt,
...
FROM
( SELECT
min(equ_gender1) OVER (PARTITION BY cnst_mstr_id ORDER BY cnst_chrctrstc_strt_ts DESC rows between 1 following and 1 following) as equ_gender1,
...
FROM arc_mdm_Tbls.cnst_chrctrstc_abc
WHERE load_id=1024
qualify cnst_chrctrstc_end_dt= date '9999-12-31'
)act

The query performance is very low + correlated subquery

The query's aim is to get reserved rooms status is 3 or going to reserve in 30 to 45 minutes status in 2 or unreserved status in 1. reservation rooms are in RESEENH table and each reservation is in ORD_NOARCHIVE table which has begintime and endtime of reservation. So for each reservation room this query checks whether reservation is available at current time also its checks the meeting room parents and children. if children is reserved then parents are are blocked.
it takes 10 secs to fetch first 50 records.
with cte as
(
SELECT DISTINCT R.syscode,
R.behcode,
R.syscode AS FK_RESERVATIONUNIT, (
CASE
WHEN R.TYPE = 3 THEN '1'
WHEN R.TYPE = 1 THEN '2'
ELSE NULL
END ) AS LOCATION_TYPE,
R.sysobjalg AS FK_PROPERTY,
MP.syscode AS FK_MEASUREMENTPOINT,
MP.fk_plc_occupancy_state AS FK_PLC_OCCUPANCY_STATE,
F.syscode AS FK_FLOOR,
R.transitiontime,
r.type,
r.is_compoundreservationunit,
r.is_archived,
MP.fk_person,
os.transitionperiod
FROM reseenh R
--left outer join ordtrantbl RSS
--ON RSS.reservationunisyscode = R.syscode
left outer join objond F
ON F.syscode = R.fk_floor
left outer join pln_measurementpoint MP
ON MP.fk_reservationunit = R.syscode
AND MP.is_primary_measurement_point = 'T',
pln_ordersetting os
)
select cte.syscode,cte.behcode,cte.FK_RESERVATIONUNIT,
(CASE
WHEN O.begindatetime_user IS NULL THEN '1' --GREEN
WHEN O.begindatetime_user - (Nvl(cte.transitiontime, ( cte.transitionperiod ))/1440 ) > current_date THEN '2' -- ORANGE
WHEN O.begindatetime_user + (Nvl(cte.transitiontime, ( cte.transitionperiod )) /1440 ) > current_date THEN '3' -- RED
ELSE '3'
END ) AS LOCAVAILABILITY_STATUS_CODE,
cte.LOCATION_TYPE,
cte.FK_PROPERTY,
Coalesce(O.sysmelder, cte.fk_person) AS FK_PERSON,
O.syscode AS FK_ORDER,
O.ref_bostate_userdefined AS FK_ORDER_STATE_USER,
O.fk_bostate AS FK_ORDER_STATE_SYSTEM,
FK_MEASUREMENTPOINT,FK_PLC_OCCUPANCY_STATE,FK_FLOOR
from cte left outer join ord_noarchive O on O.syscode in
( SELECT MAX(ord.syscode) KEEP (DENSE_RANK FIRST ORDER BY ord.begindatetime_user) OVER (PARTITION BY ord.sysreseenh )
FROM ord_noarchive ORD
WHERE ( ( (
current_date >= ( ORD.begindatetime_user - ( Nvl(cte.transitiontime, ( cte.transitionperiod ))/1440) )
AND (
current_date - ( Nvl(cte.transitiontime, (cte.transitionperiod )) / 1440 ) ) <=ORD.enddatetime_user )
OR ( (
current_date + ( (
CASE
WHEN (
cte.TYPE = 1 ) THEN 30
ELSE 45
END ) / 1440 ) ) >= ( ORD.begindatetime_user - (Nvl(cte.transitiontime, ( cte.transitionperiod))/1440 ) )
AND (
current_date - ( Nvl(cte.transitiontime, ( cte.transitionperiod )) / 1440 ) ) < ORD.enddatetime_user ) )
AND ORD.sysreseenh IN
(
SELECT fk_reservationunit_parent
FROM pln_reservationunit_rut
WHERE fk_reservationunit_child IN
(
SELECT fk_reservationunit_child
FROM pln_reservationunit_rut
WHERE cte.is_compoundreservationunit = 'T'
AND fk_reservationunit_parent = cte.syscode)
UNION
SELECT cte.syscode
FROM dual
UNION
SELECT
CASE
WHEN cte.is_compoundreservationunit = 'T' THEN fk_reservationunit_child
ELSE fk_reservationunit_parent
END
FROM pln_reservationunit_rut
WHERE (
cte.is_compoundreservationunit = 'T'
AND fk_reservationunit_parent = cte.syscode )
OR (
cte.is_compoundreservationunit = 'F'
AND fk_reservationunit_child = cte.syscode ))
AND ORD.fk_bostate IN
(
SELECT syscode
FROM pln_bostate
WHERE pnname IN ( 'Requested',
'Made',
'AdministrativelyCompleted' )
AND fk_bodefinition = ref_bodefinition)
AND ORD.sysreseenh = O.sysreseenh
))
WHERE cte.is_archived = 'F'
AND cte.TYPE IN ( 1,
3 )
AND cte.fk_floor=495
No time to analyze the details of a very complex query, but my overall sense is that you are trying to do too many things at once. Separate the tasks. Check on room availability in one query, and check on the children/parent thing in a separate query.
Also, you could analyze the execution plan for the query and see what it bogging it down. My suspicion (again without time to really try to understand your query) is that at some point the mixing of tasks is translating into a many-to-many relationship where you have an intermediate result that is a cross product of rows between some of the tables in your query.

Resources