How to group by rather for date time? - sql

Let's consider I am having following data in my table:
User id date time
User1. 28-JUL-16 06:14:56
User1. 28-JUL-16 04:12:12
User2. 28-JUL -16 05:10:45
User3. 30-JUL-16 03:10:12
I want to find the count of users on date wise.
Please some help on this!

You can ignore the time portion of a date using the trunc() function, which defaults to converting the time part to midnight. You can then group by that.
with your_table (user_id, date_time) as (
select 'User1.', to_date('28-JUL-16 06:14:56', 'DD-MON-RR HH24:MI:SS') from dual
union all select 'User1.', to_date('28-JUL-16 04:12:12', 'DD-MON-RR HH24:MI:SS') from dual
union all select 'User2.', to_date('28-JUL-16 05:10:45', 'DD-MON-RR HH24:MI:SS') from dual
union all select 'User3.', to_date('30-JUL-16 03:10:12', 'DD-MON-RR HH24:MI:SS') from dual
)
select to_char(trunc(date_time), 'DD-MON-RR') as date_only, count(distinct user_id)
from your_table
group by trunc(date_time);
DATE_ONLY COUNT(DISTINCTUSER_ID)
------------------ ---------------------------------------
28-JUL-16 2
30-JUL-16 1
I've included distinct as it isn't clear if you want to count a user more than once n the same day; if you do then just remove that.
select to_char(trunc(date_time), 'DD-MON-RR') as date_only, count(user_id)
from your_table
group by trunc(date_time);
DATE_ONLY COUNT(USER_ID)
------------------ ---------------------------------------
28-JUL-16 3
30-JUL-16 1

Related

count the number of days, how many days remained active on an offer In Oracle Sql

I want to count the number of days, how many days remained active on an offer.
That is my Tbale:
CREATE TABLE myTable(u_id, , offer, status,status_date) as
SELECT 1, 'Offer_1', 'Active', TO_DATE('2021/12/01 21:02:44', 'yyyy/mm/dd hh24:mi:ss')
FROM dual
UNION ALL
SELECT 1, 'Offer_1', 'Deactive', TO_DATE('2022/02/01 21:02:44', 'yyyy/mm/dd hh24:mi:ss') FROM dual
UNION ALL
SELECT 1, 'Offer_1','Active', TO_DATE('2022/03/01 21:02:44', 'yyyy/mm/dd hh24:mi:ss') FROM dual
UNION ALL
SELECT 1, 'Offer_1','Deactive' TO_DATE('2022/04/01 21:02:44', 'yyyy/mm/dd hh24:mi:ss') FROM dual
UNION ALL
SELECT 1, 'Offer_2','Active', TO_DATE('2022/12/30 21:02:44', 'yyyy/mm/dd hh24:mi:ss') FROM dual
That is my script:
select distinct u_id,offer_id,
trunc(nvl(case when status = 'Deactive' then status_date end),sysdate) -
trunc(case when status = 'Active' then status_date end) date_diff
from myTable
but it gives me wrong result.
expected output:
u_id
offer
total_day
1
offer_1
93
1
offer_2
31
You can do it as follows :
select u_id, offer, sum(case when status = 'Active' then ceil(trunc(sysdate) - status_date) else ceil(status_date - trunc(sysdate)) end) as total_day
from myTable
group by u_id, offer
Result :
U_ID OFFER TOTAL_DAY
1 Offer_1 460
1 Offer_2 31
ceil used to round the specified number up (number of days in this case)
demo here
Provided 'Active' and 'Deactive' are always alternating, you can use LEAD to get the desctive date for each active date. At last aggregate and sum.
select
u_id,
offer,
trunc(sum(cast(next_status_date as date) - cast(status_date as date))) as total_days
from
(
select
u_id, offer, status, status_date,
coalesce
(
lead(status_date) over (partition by u_id, offer order by status_date),
sysdate
) as next_status_date
from mytable
)
where status = 'Active'
group by u_id, offer
order by u_id, offer;
Demo: https://dbfiddle.uk/YDVTqEiR

Column based on time range in Oracle

I have a sales table with created datetime, my business hours are from 9 AM to 2 AM in the night on the following day. I am trying to convert the dates into my business date.
01/08/22 09:39:12.000000000 AM +04:00
Lets say I have a sale at 1 AM, this sale has to be considered in the previous day.
Any function that can help me solve this issue would be appreciated
It might be a bit of an overkill, but you could just use EXTRACT:
WITH dat AS
(
SELECT to_date('01/08/22 09:39:12','DD/MM/YY HH24:MI:SS') AS t_stmp FROM dual UNION ALL
SELECT to_date('02/08/22 01:03:15','DD/MM/YY HH24:MI:SS') FROM dual UNION ALL
SELECT to_date('02/08/22 08:27:33','DD/MM/YY HH24:MI:SS') FROM dual UNION ALL
SELECT to_date('02/08/22 14:11:51','DD/MM/YY HH24:MI:SS') FROM dual UNION ALL
SELECT to_date('02/08/22 02:01:15','DD/MM/YY HH24:MI:SS') FROM dual
)
SELECT CASE WHEN EXTRACT(HOUR FROM CAST(t_stmp AS TIMESTAMP)) BETWEEN 2 AND 8 THEN -1
ELSE 0
END + TRUNC(t_stmp,'DD') AS business_date
FROM dat;
business_date
01.08.2022
02.08.2022
01.08.2022
02.08.2022
01.08.2022
It looks like you just need to make a 2 hour shift to get your sales in the right date. You can add or substract hours from DATE/DATETIME/TIMESTAMP data type. If your column is TIMESTAMP then it would be like this:
-- when selecting data for date of sales
SELECT TRUNC(your_column_name - INTERVAL '2' HOUR, 'dd') "SALE_DATE"
-- And/Or
WHERE TRUNC(your_column_name - INTERVAL '2' HOUR, 'dd') = :DATE_OF_SALES
-- TRUNC function always returns DATE datatype
--
-- The opposite conversion would be
CAST(your_datetime_column + INTERVAL '2' HOUR as TIMESTAMP) ...
Here is the small sample with result:
SELECT
to_char(SYSDATE, 'dd.mm.yyyy hh24:mi:ss') "DATETIME",
to_char(SYSDATE - INTERVAL '2' HOUR, 'dd.mm.yyyy hh24:mi:ss') "DATETIME_MINUS_2H",
to_char(SYSDATE + INTERVAL '2' HOUR, 'dd.mm.yyyy hh24:mi:ss') "DATETIME_PLUS_2H",
to_char(SYSDATE - INTERVAL '10' HOUR, 'dd.mm.yyyy hh24:mi:ss') "DATETIME_MINUS_10H"
FROM
DUAL
--
-- R e s u l t
--
-- DATETIME DATETIME_MINUS_2H DATETIME_PLUS_2H DATETIME_MINUS_10H
-- ------------------- ------------------- ------------------- -------------------
-- 07.08.2022 09:58:38 07.08.2022 07:58:38 07.08.2022 11:58:38 06.08.2022 23:58:38
The last column now has the date from day before.

How to retrieve rows between hours

I want to get all rows from my table, the table have one column with the following date type '14/07/2017 05:01:35 p.m.' between specific hours. Like between '00:01:00 am' and '01:00:00 am'.
I'm running Oracle Database 11g Release 2
select ID, CREATION_TIME
from my_table
where ID = 4 and
CREATION_TIME between to_date('29/04/2017 12:01:00', 'DD/MM/YYYY HH:MI:SS[AM]') and to_date('29/04/2019 01:00:00', 'DD/MM/YYYY HH:MI:SS[AM]')
order by creation_time asc;
I want to select hours instead of dates.
If you mean (from your last comment) that you want to get all records that are between the dates of Jan 1st 2019 and Apr 4th 2019, but only if the time portion of the recod is between 12:01AM and 1:00AM, then you could try this:
select ID, CREATION_TIME
from my_table
where ID = 4
and CREATION_TIME between to_date('01/01/2017', 'DD/MM/YYYY')
and to_date('04/04/2019', 'DD/MM/YYYY')
and CREATION_TIME BETWEEN TO_DATE(TO_CHAR(CREATION_TIME, 'MM/DD/YYYY') || ' 00:01:00', 'MM/DD/YYYY HH24:MI:SS')
AND
TO_DATE(TO_CHAR(CREATION_TIME, 'MM/DD/YYYY') || ' 01:00:00', 'MM/DD/YYYY HH24:MI:SS')
order by creation_time asc;

get count of records in every hour in the last 24 hour

i need number of records in each hour in the last 24 hours, i need my query to show 0 if there are no records in any of the particular hour for that day, i am just able to get data for hours that are in table.
SELECT TRUNC(systemdate,'HH24') + (trunc(to_char(systemdate,'mi')/10)*10)/24/60 AS date1,
count(*) AS txncount
FROM transactionlog
GROUP BY TRUNC(systemdate,'HH24') + (trunc(to_char(systemdate,'mi')/10)*10)/24/60 order by date1 desc;
result:
What should i do to get data in each hour of the last 24 hours?
Expected data:
record count in each hour for last 24 hours , starting from current date time.. if no record exist in that particular hour, 0 is shown.
The following might be what you need. It seems to work when I run it against the all_objects view.
WITH date_range
AS (SELECT TRUNC(sysdate - (rownum/24),'HH24') as the_hour
FROM dual
CONNECT BY ROWNUM <= 1000),
the_data
AS (SELECT TRUNC(created, 'HH24') as cr_ddl, count(*) as num_obj
FROM all_objects
GROUP BY TRUNC(created, 'HH24'))
SELECT TO_CHAR(dr.the_hour,'DD/MM/YYYY HH:MI AM'), NVL(num_obj,0)
FROM date_range dr LEFT OUTER JOIN the_data ao
ON ao.cr_ddl = dr.the_hour
ORDER BY dr.the_hour DESC
The 'date_range' generates a record for each hour over the past 24.
The 'the_data' does a count of the number of records in your target table based on the date truncated to the hour.
The main query then outer joins the two of them showing the date and the count from the sub-query.
I prefer both parts of the query in their own CTE because it makes the actual query very obvious and 'clean'.
In terms of your query you want this;
WITH date_range
AS (SELECT TRUNC(sysdate - (rownum/24),'HH24') as the_hour
FROM dual
CONNECT BY ROWNUM <= 24),
the_data
AS (SELECT TRUNC(systemdate, 'HH24') as log_date, count(*) as num_obj
FROM transactionlog
GROUP BY TRUNC(systemdate, 'HH24'))
SELECT TO_CHAR(dr.the_hour,'DD/MM/YYYY HH:MI AM'), NVL(trans_log.num_obj,0)
FROM date_range dr LEFT OUTER JOIN the_data trans_log
ON trans_log.log_date = dr.the_hour
ORDER BY dr.the_hour DESC
You could use this:
WITH transactionlog AS
(
SELECT TO_DATE('03/05/2018 01:12','dd/mm/yyyy hh24:mi') AS systemdate, 60 AS value
FROM dual UNION ALL
SELECT TO_DATE('03/05/2018 01:32','dd/mm/yyyy hh24:mi'), 35 FROM dual UNION ALL
SELECT TO_DATE('03/05/2018 09:44','dd/mm/yyyy hh24:mi'), 31 FROM dual UNION ALL
SELECT TO_DATE('03/05/2018 08:56','dd/mm/yyyy hh24:mi'), 24 FROM dual UNION ALL
SELECT TO_DATE('03/05/2018 08:02','dd/mm/yyyy hh24:mi'), 98 FROM dual
)
, time_range AS
(
SELECT TRUNC(sysdate, 'hh24') - 23/24 + (ROWNUM - 1) / 24 AS time1
FROM all_objects
WHERE ROWNUM <= 24
)
SELECT TO_CHAR(r.time1, 'mm/dd/yyyy hh:mi AM') AS date1,
COUNT(t.systemdate) AS txncount
FROM time_range r
LEFT JOIN transactionlog t
ON r.time1 = TRUNC(t.systemdate, 'hh24') --+ 1/24
GROUP BY r.time1
ORDER BY r.time1;
If 01:12 AM means 02:00 AM in result, then omit the comment code.
Reference: Generating Dates between two date ranges_AskTOM
Edited: For OP, you only need this:
WITH time_range AS
(
SELECT TRUNC(sysdate, 'hh24') - 23/24 + (ROWNUM - 1) / 24 AS time1
FROM all_objects
WHERE ROWNUM <= 24
)
SELECT TO_CHAR(r.time1, 'mm/dd/yyyy hh:mi AM') AS date1,
COUNT(t.systemdate) AS txncount
FROM time_range r
LEFT JOIN transactionlog t
ON r.time1 = TRUNC(t.systemdate, 'hh24') --+ 1/24
GROUP BY r.time1
ORDER BY r.time1;
You need to write a last 24 hours calendar table,then LEFT JOIN calendar table by Original table.
count(t.systemdate) need to count t.systemdate because t.systemdate might be NULL
connect by create last 24 hours calendar table
on clause TO_CHAR(t.systemdate,'YYYY/MM/DD hh24','nls_language=american') make sure the dateformat language are the same.
You can try this.
WITH Hours as
(
select sysdate + (level/24) dates
from dual
connect by level <= 24
)
SELECT TO_CHAR(h.dates,'YYYY-MM-DD HH24') AS dateHour, count(t.systemdate) AS totlecount
FROM Hours h
LEFT JOIN transactionlog t
on TO_CHAR(t.systemdate,'YYYY/MM/DD hh24','nls_language=american')
= TO_CHAR(h.dates,'YYYY/MM/DD hh24','nls_language=american')
GROUP BY h.dates
ORDER BY h.dates
sqlfiddle:http://sqlfiddle.com/#!4/73db7/2
CTE Recursive Version
You can also use CTE Recursive to write a calendar table
WITH Hours(dates,i) as
(
SELECT sysdate,1
FROM DUAL
UNION ALL
SELECT sysdate + (i/24),i+1
FROM Hours
WHERE i<24
)
SELECT TO_CHAR(h.dates,'YYYY-MM-DD HH24') AS dateHour, count(t.systemdate) AS totlecount
FROM Hours h
LEFT JOIN transactionlog t
on TO_CHAR(t.systemdate,'YYYY/MM/DD hh24','nls_language=american')
= TO_CHAR(h.dates,'YYYY/MM/DD hh24','nls_language=american')
GROUP BY h.dates
ORDER BY h.dates
sqlfiddle:http://sqlfiddle.com/#!4/73db7/7

How to use round and trunc to get dd:mm:yy:hh

I am using oracle 11g and I have normal timestamps (starttime) which produce an output as follows:
23.09.14 05:15:00,000000000
Now I want an output like
23.09.14 05
Also ok would be:
23.09.14 05:00:00,000000000
but when I use something like
round(starttime, 'HH') or trunc(starttime ,'HH24') I always get
23.09.14
with no hours at all.
Looking around here at stackoverflow I found
substr(TO_CHAR(starttime),0,LENGTH(TO_CHAR(starttime))-13)
which produces the correct output as char but when I want to sort dates it wont work because it sorts alphabetically. (so for example, 1.3., 1.4, 1.5.... instead of 1.3., 2.3., 3.3,...),
Any idea how I can get a timestamp which is rounded to the full hour?
I will have to use the statement in a group by clause. The complete statement would look like:
select round(starttime, 'HH24'), sum(counter) from wmsconsolidationorderdwct group by round(starttime, 'HH24') order by round(starttime, 'HH24') desc;
So I cannot display the rounded time and sort by the full timestamp since this would violate the group by clause.
This will truncate to the hour:
trunc(SYSTIMESTAMP) + extract(hour from SYSTIMESTAMP)/24
Edit:
I just tried it and
SELECT TRUNC(SYSTIMESTAMP ,'HH24') FROM DUAL;
returns the correct result.
Fiddle
If your purpose is to display, then use TO_CHAR with desired format model.
For example,
SQL> SELECT TO_CHAR(SYSTIMESTAMP, 'DD.MM.YY HH24') FROM dual;
TO_CHAR(SYS
-----------
28.05.15 15
SQL>
If your purpose is to do date arithmetic then you need to leave the data type as date.
For example,
SQL> alter session set nls_date_format='DD-MM-YYYY HH24:MI:SS'
2 /
Session altered.
SQL> SELECT TRUNC(SYSTIMESTAMP ,'HH24') FROM DUAL
2 /
TRUNC(SYSTIMESTAMP,
-------------------
28-05-2015 15:00:00
SQL>
If you have a timestamp object:
select my_number from(
SELECT TO_NUMBER(TO_CHAR(TO_DATE (TO_CHAR (SYSTIMESTAMP, 'DD.MM.YY HH24:MI'),
'DD.MM.YY HH24:MI'
),'HH24')) AS my_number
FROM DUAL)
order by 1
This could be simplified to:
select my_number from(
SELECT TO_NUMBER(TO_CHAR(SYSTIMESTAMP, 'HH24')) AS my_number
FROM DUAL)
order by 1