Oracle SQL - count by day - not a GROUP BY expression - sql

I have data which looks like this:
TIME ID
29/11/20 13:45:33,810000000 1234
06/01/21 13:45:33,810000000 5678
06/01/21 14:05:33,727000000 5678
That means, I have a column TIME and ID. What I want to do is to count all the entries by day and all the distinct IDs per day.
As result I would like to get this:
DAY COUNT(*) distinctID
29/11/20 1 1
06/01/21 2 1
I did this:
select trunc(to_char(TIME, ‘HH’),'DD/MM/YY'),
COUNT(*), count(distinct ID) as distinctID from CDRHEADER
where TIME>= date '2021-03-01'
group by trunc(TIME,'DD/MM/YY')
order by trunc(TIME,'DD/MM/YY');
As error I get: not a GROUP BY Expression.
Furthermore, I am also not sure about the date operations I executed and if they are correct.
NOTE: I would like to use the date entries as date values and not compare strings or something like this.
How can I get what I expect?

Hmmm . . . I think you want:
select trunc(time) as the_date,
count(*), count(distinct ID) as distinctID
from CDRHEADER
where time >= date '2021-03-01'
group by trunc(time)
order by trunc(time);
I'm not sure why you are using to_char() or 'HH'. If you really want to output the time as 'DD/MM/YYYY', then:
select to_char(trunc(time), 'DD/MM/YYYY') as the_date,
count(*), count(distinct ID) as distinctID
from CDRHEADER
where time >= date '2021-03-01'
group by trunc(time)
order by trunc(time);

Related

ORACLE SQL: Hourly Date to be group by day time and sum of the amount

I have the following situation:
ID DATE_TIME AMOUNT
23 14-MAY-2021 10:47:01 5
23 14-MAY-2021 11:49:52 3
23 14-MAY-2021 12:03:18 4
How can get the sum of the amount and take the DATE by day not hourly?
Example:
ID DATE_TIME TOTAL
23 20210514 12
I tried this way but i got error:
SELECT DISTINCT ID, TO_CHAR(DATE_TIME, 'YYYYMMDD'), SUM(AMOUNT) AS TOTAL FROM MY_TABLE
WHERE ID ='23' AND DATE_TIME > SYSDATE-1
GROUP BY TOTAL, DATE_TIME
You don't need DISTINCT if you use GROUP BY - anything that is grouped must be distinct unless it joined to something else later on that caused it to repeat again
You were almost there too
SELECT ID, TO_CHAR(DATE_TIME, 'YYYYMMDD') AS DATE_TIME, SUM(AMOUNT) AS TOTAL
FROM MY_TABLE
WHERE ID ='23' AND DATE_TIME > SYSDATE-1
GROUP BY ID, TO_CHAR(DATE_TIME, 'YYYYMMDD')
You need to group by the output of the function, not the input. Not every database can GROUP BY aliases used in the select (technically the SELECT hasn't been done by the time the GROUP is done so the aliases don't exist yet, and you wouldnt group by the total because that's an aggregate (the result of summing up every various value in the group)
If you need to do further work with that date, don't convert it to a string.. Cut the time off using TRUNC:
SELECT ID, TRUNC(DATE_TIME) as DATE_TIME, SUM(AMOUNT) AS TOTAL
FROM MY_TABLE
WHERE ID ='23' AND DATE_TIME > SYSDATE-1
GROUP BY ID, TRUNC(DATE_TIME)
TRUNC can cut a date down to other parts, for example TRUNC(DATE_TIME, 'HH24') will remove the minutes and seconds but leave the hours
Convert the DATE column to a string with the required accuracy and then group on that:
SELECT ID,
TO_CHAR("DATE", 'YYYY-MM-DD'),
SUM(AMOUNT) AS TOTAL FROM MY_TABLE
WHERE ID ='23'
AND "DATE" > SYSDATE-1
GROUP BY ID, TO_CHAR("DATE", 'YYYY-MM-DD')
or truncate the value so that the time component is set to midnight for each date:
SELECT ID,
TRUNC("DATE"),
SUM(AMOUNT) AS TOTAL FROM MY_TABLE
WHERE ID ='23'
AND "DATE" > SYSDATE-1
GROUP BY ID, TRUNC("DATE")
(Note: DATE is a keyword and cannot be used as an identifier unless you use a quoted-identifier; and you would need to use the quotes, and the exact case, everytime you refer to the column. You would be better to rename the column to something else that is not a keyword.)

SQL count distinct # of calls 6 months prior to create date

Am trying to figure out the SQL to:
count # of distinct calls
made on an account 6 months prior to the account being created
I also need to CAST the date field.
I'm thinking something like:
case when (call_date as date format 'MM/DD/YYYY')
between (create_date as date format 'MM/DD/YYYY') and
(ADD_MONTHS, (create_date as date format 'MM/DD/YYYY), -6)
then COUNT (DISTINCT call_nbr) as calls
Here's a snippet of the data i am working with. The answer I require 3 Calls.
Note: both dates are flagged in the db table as DATE format.
Call_Nbr.....Call Date......Create Date
12345........03/14/2020....07/23/2020.....include in result set
12345........03/14/2020....07/23/2020.....exclude in result set
45678........02/14/2020....07/23/2020.....include in result set
91011........01/20/2020....07/23/2020.....include in result set
91211........01/24/2020....07/23/2020.....exclude in result set
12345........11/14/2019....07/23/2020.....exclude in result set
I think you want:
select count(distinct call_nbr) no_calls
from mytable
where call_date >= add_months(create_date, -6)
If you have a column that represnets the account_id, then you can use a group by clause to get the count of calls per account:
select account_id, count(distinct call_nbr) no_calls
from mytable
where call_date >= add_months(create_date, -6)
group by account_id
Edit: it seems like you want conditional aggregation instead:
select
account_id,
count(distinct case when call_date >= add_months(create_date, -6) then call_nbr end) no_calls
from mytable
group by account_id

Cumulative count on date data from datetime format

I have a table looks like:
ID entry_time
abc123 2020-05-29 10:29:18.000
def456 2020-05-30 13:12:43.000
...
I want to do cumulative count by date, so I did:
select entry_time, count (*) OVER (ORDER BY entry_time) as TOTAL_NUM from my_table;
It is okay, but it will count based on datetime format. I would like to count only on date (i.e. by day, don't care about time).
How would I do that?
Many thanks,
You can try by converting entry time to date.
select
convert(date, entry_time) as entry_time,
count (*) OVER (ORDER BY convert(date, entry_time)) as total_num
from my_table;
If you want one record per day, you can use aggregation and window functions:
select
date(entry_time) entry_day,
sum(count(*)) over(order by date(entry_time)) total_num
from mytable
group by date(entry_time)
order by entry_day
This assumes that your database supports the date(), that converts a datetime to a date (as in MySQL for example). If it does not, it sure has an alternative way to do this.
You can use convert or cast entry_time to Date
select entry_time, count (*) OVER (ORDER BY Convert(date,entry_time)) as TOTAL_NUM from my_table;
OR
select entry_time, count (*) OVER (ORDER BY Cast(entry_timeas as date)) as TOTAL_NUM from my_table;

how to find number of active users for say 1 day,2 days, 3 days.....postgreSQL

A distribution of # days active within a week: I am trying to find how many members are active for 1 day, 2days, 3days,…7days during a specific week 3/1-3/7.
Is there any way to use aggregate function on top of partition by?
If not what can be used to achieve this?
select distinct memberID,count(date) over(partition by memberID) as no_of_days_active
from visitor
where date between '"2019-01-01 00:00:00"' and '"2019-01-07 00:00:00"'
order by no_of_days_active
result should look something like this
#Days Active Count
1 20
2 32
3 678
4 34
5 3
6 678
7 2345
I think you want two levels of aggregation to count the number of days during the week:
select num_days_active, count(*) as num_members
from (select memberID, count(distinct date::date) as num_days_active
from visitor
where date >= '2019-01-01'::date and
date < '2019-01-08'::date
group by memberID
) v
group by num_days_active
order by num_days_active;
Note that I changed the date comparisons. If you have a time component, then between does not work. And, because you included time in the constant, I added an explicit conversion to date for the count(distinct). That might not be necessary, if date is really a date with no time component.
Piggybacking off of #Gordon's answer, I personally like using a with statement for the subqueries:
with dat as (
select distinct
memberID,
count(date) over(partition by memberID) as no_of_days_active
from visitor
where 1=1
and date between '2019-01-01'::date and '2019-01-07'::date
order by no_of_days_active
)
select
no_of_days_active,
count(no_of_days_active) no_of_days_active_cnt
from dat
group by no_of_days_active
order by no_of_days_active

SQL Count of date values that dont match hour and day in select statement

I have a problem unique to a business process. My user needs to know how many dates, counted, are before a specific end time that do not match on the hour or the day.
Here is an example.
AAA, 2016-03-15 16:00:28.967, 2016-03-15 16:02:58.487, 2016-03-17 14:01:24.243
In the example above id AAA has 3 entries. I need to count only the ones that don't have a matching hour and day. So the actual count should come out to be 2.
I have to do this all in SQL and can't use a CTE. It needs to be either a sub select or some type of join.
Something like this.
SELECT id, date, (
SELECT COUNT(*)
FROM x
WHERE day!=day
AND hour!=hour AND date < z
) AS DateCount
Results would be AAA, 2
I am thinking some type of recursive comparison but I am not sure how to accomplish this without a CTE.
In SQL Server you can try something like this:
SELECT id, CONVERT(VARCHAR(13), [date], 120) AS [Date], COUNT(*) AS DateCount
FROM YourTable
WHERE [date] < #ENDDATE
GROUP BY id, CONVERT(VARCHAR(13), [date], 120)
SELECT a AS current_a, COUNT(*) AS b,day AS day, hour as hour,
(SELECT COUNT(*)
FROM t
WHERE day != day
AND hour != hour
AND date < z ) as datecount
FROM t GROUP BY a ORDER by b DESC