Aggregation query takes more than hour Oracle - sql

SELECT
subs_key,
sum(ROUNDED_DATA_VOLUME) AS RDV_SUM,
CASE WHEN to_char(CALL_START_TIME , 'HH24:MI:SS') >= '00:00:00'
AND to_char(CALL_START_TIME , 'HH24:MI:SS') <= '07:00:00' THEN 'Night'
WHEN to_char(CALL_START_TIME , 'HH24:MI:SS') > '07:00:00'
AND to_char(CALL_START_TIME , 'HH24:MI:SS') <= '23:59:59' THEN 'Day'
END AS Tariff_flag
FROM DWH.FCT_USAGE_PREP_OGPRS_N
WHERE CALL_START_TIME >= to_date('2021-11-01', 'YYYY-MM-DD')
AND CALL_START_TIME <= to_date('2021-11-30', 'YYYY-MM-DD')
GROUP BY
SUBS_KEY,
CASE WHEN (to_char(CALL_START_TIME , 'HH24:MI:SS') >= '00:00:00'
AND to_char(CALL_START_TIME, 'HH24:MI:SS') <= '07:00:00') THEN 'Night'
WHEN (to_char(CALL_START_TIME , 'HH24:MI:SS') > '07:00:00'
AND to_char(CALL_START_TIME, 'HH24:MI:SS') <= '23:59:59') THEN 'Day'
END
My query takes more than hour and still running. Is there any way to optimize it?
UPD:
Execution Plan
Is that what Ankit asked?

You are grouping by a relatively complex function:
CASE WHEN (to_char(CALL_START_TIME , 'HH24:MI:SS') >= '00:00:00' AND to_char(CALL_START_TIME , 'HH24:MI:SS') <= '07:00:00') THEN 'Night'
WHEN (to_char(CALL_START_TIME , 'HH24:MI:SS') > '07:00:00' AND to_char(CALL_START_TIME , 'HH24:MI:SS') <= '23:59:59') THEN 'Day' END
If this particular query is important enough you could index this whole thing, but I suspect you would be better off getting the hour using extract.
CASE WHEN extract(hour from CALL_START_TIME) > 7 then 'Night' --midnight (inclusive) - 7am (exclusive)
else 'Day' --7am (inclusive) - midnight (exclusive)
END
For your where clause I would
I have no way to tell whether this will speed up your query. Or speed it up sufficiently for your use case. But you can try out the two queries and see if one of them is significantly faster than the other. Also, if you're frequently using times, it might make sense to index extract(hour from CALL_START_TIME), whereas an index on your entire case statement is only likely to get used in this one query.
Your question is how to speed up the query but when I have a query that takes hours to run I will often not bother to optimize it. It's long enough that you're unlikely to get the kind of speed-ups you need to have an application executing the query based on a user's request, and if a query takes 1 hour or 12, you likely need to plan when you run it.

Related

How to search for records with timestamp between two given time in Postgresql

Is there a way to search through timestamp data in a database and select only data with timestamps between 8AM and 6PM?
Example timestamp format is 2021-06-14 14:01:26.839629, I want to do a search and only return results where time is after 8AM and before 6PM.
You can use (as per https://www.postgresql.org/docs/current/functions-datetime.html):
SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 20:38:40');
This will return the hour from the timestamp and you can also filter accordingly.
I would recommend:
where col::time >= '06:00:00' and col::time < '18:00:00'
select *
from MyTable
where CAST(Created as time) >= '08:00'
or CAST(Created as time) < '18:00'
Try this.

Error with selecting sysdate between time range

I want to fetch the data for sysdate-1 '00:00:00' between '23:59:59' time range. I have tried, but i am getting error.
This is my query..
select id_value, tn, LINE_TYPE_ID, ACCOUNT_TYPE_ID, PORT_ID, CURRENT_STATUS_ID, ERROR_CODE, ERROR_DESC, CRM_APP_CODE
from np_tn_dtls a
join np_port_req_dtls b on A.NP_TXN_ID=B.NP_TXN_ID
left join np_subscriber_dtls c on a.NP_TXN_ID=C.NP_TXN_ID
left join np_subscriber_id_dtls d on D.SUBSCRIBER_ID=C.SUBSCRIBER_ID
where (b.REQUEST_START_TIME between sysdate-1 '00:00:00'
AND sysdate '23:59:59') and (b.port_type_id != 2);
Please suggest me.
This expression is wrong:
between sysdate-1 '00:00:00'
AND sysdate '23:59:59'
Use trunc to round the date, so you can write this:
between trunc(sysdate-1) AND trunc(sysdate)
However, between is up to and including, so to prevent getting also request that happened exactly at midnight today, you can better write it like this:
b.REQUEST_START_TIME >= trunc(sysdate-1) AND
b.REQUEST_START_TIME < trunc(sysdate)
sysdate '23:59:59' is not a valid construction
use
b.REQUEST_START_TIME >= trunc(sysdate-1)
AND b.REQUEST_START_TIME < trunc(sysdate)

get data on particular timings of the day in a month in SQL

How can I retrieve data on time range where tickets issued between the times of 6am - 9:15am for the past month.
I tried this but was wrong.Its in oracle and to_char is not function name in SQL. how can i do that in sql.
select *
from [ICPS].[dbo].[tickets]
where t_date_time_issued > sysdate - 30
and to_char(t_date_time_issed, 'hh24:mi:ss') >= '06:00:00'
and to_char(t_date_time_issued, 'hh24:mi:ss') <= '09:15:00'
Assuming that you want it in SQL-Server("Its in oracle and to_char is not function name in SQL"), you can cast the datetme to time:
SELECT *
FROM [dbo].[tickets]
WHERE t_date_time_issued > DATEADD(mm, - 30, GetDate())
AND Cast(t_date_time_issued as TIME) between '06:00' and '09:10'
Demo
You can use to_timestamp() in stead of to_char. Details about to_timestamp() is: http://docs.oracle.com/cd/B28359_01/olap.111/b28126/dml_functions_2118.htm#OLADM696
Hope will help!
try this:
SELECT
*
FROM
[ICPS].[DBO].[tickets]
WHERE
t_date_time_issued BETWEEN add_months(TRUNC(SYSDATE, 'MM'), - 1) AND (
TRUNC(SYSDATE, 'MM') - (1/24/60/60))
AND TO_CHAR(t_date_time_issed, 'HH24:MI:SS') >= '06:00:00'
AND TO_CHAR(t_date_time_issed, 'HH24:MI:SS') <= '09:15:00'
SELECT *
FROM [ICPS].[dbo].[tickets]
WHERE convert (datetime,t_date_time_issued,101)
between convert(datetime,'2013/11/01',101) and convert (datetime,'2013/12/04',101)
AND datepart(hour,t_date_time_issued) between '06' and '09'

Oracle. Missing keyword when using case statement. Error 00905

I keep getting an error 'ORA-00905: missing keyword' with the following statement, ever since I introduced the CASE statement, but I can't figure out what is missing.
SELECT
CYCLE_S_FACT_MAIN.STARTTIME,
CYCLE_S_FACT_MAIN.ENDTIME
FROM
CYCLE_S_FACT_MAIN
WHERE
(
CYCLE_S_FACT_MAIN.ENDTIME >
(SELECT SYSDATE,
CASE SYSDATE
WHEN TO_CHAR(SYSDATE, 'HH') < 6 THEN CONCAT(TO_CHAR(SYSDATE, 'DD-MM-YYYY'), ' 06:00:00')
ELSE CONCAT(TO_CHAR(SYSDATE - INTERVAL '1' DAY, 'DD-MM-YYYY'), ' 06:00:00')
END AS SYSDATE
FROM DUAL
)
AND
CYCLE_S_FACT_MAIN.ENDTIME <= SYSDATE
)
You're mixing up the two forms of CASE expressions. There's a simple expression (when you're just wanting to compare expressions for equality):
CASE Expr1
WHEN Expr2 THEN ...
WHEN Expr3 THEN ...
ELSE ...
END
And there's a searched CASE expression, where you want to evaluate separate predicates:
CASE
WHEN Predicate1 THEN ...
WHEN Predicate2 THEN ...
ELSE ...
END
For a searched CASE, you don't specify an expression between CASE and the first WHEN.
Damien_The_Unbeliever is right about mixing case styles, but you also don't need the subquery at all, and the one you have is getting two columns back - which you can't compare with a single value. You can just do this:
WHERE
CYCLE_S_FACT_MAIN.ENDTIME > CASE
WHEN TO_NUMBER(TO_CHAR(SYSDATE, 'HH24')) < 6
THEN TRUNC(SYSDATE) + INTERVAL '6' HOUR
ELSE TRUNC(SYSDATE) - INTERVAL '1' DAY + INTERVAL '6' HOUR END
AND CYCLE_S_FACT_MAIN.ENDTIME <= SYSDATE
This leaves the comparison as between two dates, rather than relying on implcit conversions. I've also used HH24; using HH would treat times between midday and 6pm the same as those between midnight and 6am, which I'm prety sure you didn't intend.
Try as
SELECT
CYCLE_S_FACT_MAIN.STARTTIME,
CYCLE_S_FACT_MAIN.ENDTIME
FROM
CYCLE_S_FACT_MAIN
WHERE
(
CYCLE_S_FACT_MAIN.ENDTIME >
(SELECT SYSDATE,
CASE
WHEN TO_CHAR(SYSDATE, 'HH') < 6 THEN CONCAT(TO_CHAR(SYSDATE, 'DD-MM-YYYY'), ' 06:00:00')
ELSE CONCAT(TO_CHAR(SYSDATE - INTERVAL '1' DAY, 'DD-MM-YYYY'), ' 06:00:00')
END AS "MY_SYSDATE"
FROM DUAL
)
AND
CYCLE_S_FACT_MAIN.ENDTIME <= SYSDATE
)
There two possible mistakes, one is it is expecting as CASE WHEN not as CASE sysdate WHEN and second one is sysdate as alias which is not possible to use as alias name.
SELECT TO_CHAR(SYSDATE,'HH'),
CASE
WHEN TO_CHAR(SYSDATE,'HH') < 6
THEN CONCAT(TO_CHAR(SYSDATE, 'DD-MM-YYYY'), ' 06:00:00')
ELSE CONCAT(TO_CHAR(SYSDATE - INTERVAL '1' DAY, 'DD-MM-YYYY'), ' 06:00:00')
END "sysdate" ,
TO_CHAR(SYSDATE, 'HH'),
CONCAT(TO_CHAR(SYSDATE, 'DD-MM-YYYY'), ' 06:00:00')
FROM dual;
12 24-07-2013 06:00:00 12 25-07-2013 06:00:00

Displaying results based on when the report is printed

I'm creating an Oracle Report and I would like to display certain results based on when I print the report. There is a field called apply_date. For example, if I print the report <= sysdate of 3/15 then I only want to display the records that have an apply_date of 3/1 - 3/15. This also goes for printing on the 30th of each month. If I print the report after 3/15 then it would only show me the results that have an apply_date of >= 3/16.
You want a where clause such as this:
where (to_char(sysdate, 'DD') <= '15' and
to_char(apply_date, 'YYYY-MM') = to_char(sysdate, 'YYYY-MM') and
to_char(apply_date, 'DD') between '00' and '15'
) or
(to_char(sysdate, 'DD') >= '16' and
to_char(apply_date, 'YYYY-MM') = to_char(sysdate, 'YYYY-MM') and
to_char(apply_date, 'DD') >= '16'
)
In order to make the best use of indexes and to give the optimiser the best estimate of cardinality I'd try to build the SQL so that the predicate does not rely on functions applied to the apply_date:
where apply_date >= case
when extract(day from sysdate) < 16
then trunc(sysdate,'MM')
else trunc(sysdate,'MM')+16
end
and apply_date < case
when extract(day from sysdate) >= 16
then add_months(trunc(sysdate,'MM'),1)
else trunc(sysdate,'MM')+16
end
On execution the R.H.S. of the predicates will be transformed to:
where apply_date >= <date>
and apply_date < <date>