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

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.)

Related

Getting sum of a column that needs a distinct value from other column

I have this table where I wanted to get the sum of the balance column but each item should have a unique value from the date column.
I'm trying to find all the rows in the balance column that are the same and have the same date, and then find the sum of the balance column.
sample data with unique dates:
balance
date
700
2021-07-03
700
2021-09-03
300
2021-09-04
500
2021-09-05
query used goes like:
select distinct a.balance, a.date from table a where a.date between (some date) and (some other date)
I have tried:
select sum(a.balance), a.date from table a where a.date between (some date) and (some other date) group by a.date
but the balance column shows the sum of all of the values in the column but shows distinct dates as shown below.
balance
date
893938
2021-07-03
858585
2021-09-03
728366
2021-09-04
665322
2021-09-05
I guess this is a job for a subquery. So let's take your problem step by step.
I'm trying to find all the rows in the balance column that are the same and have the same date,
This subquery gets you that, I believe. It give the same result as SELECT DISTINCT but it also counts the duplicated rows.
SELECT COUNT(*) num_same_rows, balance, date
FROM `table`
WHERE a.datum BETWEEN '2021-01-01' AND '2021-09-01'
GROUP BY date, balance
and then find the sum of the balance column.
Nest the subquery like this.
SELECT SUM(balance) summed_balance, date
FROM (
SELECT COUNT(*) num_same_rows, balance, date
FROM `table`
WHERE a.datum BETWEEN '2021-01-01' AND '2021-09-01'
GROUP BY date, balance
) subquery
GROUP BY date
If you only want to consider rows that actually have duplicates, change your subquery to
SELECT COUNT(*) num_same_rows, balance, date
FROM `table`
WHERE a.datum BETWEEN '2021-01-01' AND '2021-09-01'
GROUP BY date, balance
HAVING COUNT(*) >= 1
Be careful here, though. You didn't tell us what you want to do, only how you want to do it. The way you described your problem calls for discarding duplicated data before doing the sums. Is that right? Do you want to discard data?
2nd query you posted looks OK - sort of.
However, I think that it is the fact that date column contains not only date, but also time (as DATE datatype in Oracle does). Therefore, I'd say that it is trunc you need. Something like this:
SELECT TRUNC (a.datum) datum,
SUM (a.balance) sum_balance
FROM table_a a
WHERE a.datum BETWEEN DATE '2021-01-01' AND DATE '2021-09-01'
GROUP BY TRUNC (a.datum)

Count number of ids by Month SQL

I have a table like this, I hope to count the number of ids by month. I used the following code but it does not work.
id date_time
1390880502018723840,2021-05-08
1390881127930372100,2021-05-08
1390881498270736386,2021-05-08
SELECT twitter.tweets.id
WHERE Month(twitter.tweets.date_time)=01 AND Year(twitter.tweets.date_time)=2021 ;
you have to use count() function and to_char to get year month part of date in one column:
SELECT count(witter.tweets.id)
WHERE to_char(twitter.tweets.date_time,'YYYY-MM')= '2021-01';
you can generalize it for all the month/year by using group by :
SELECT to_char(twitter.tweets.date_time,'YYYY-MM') , count(witter.tweets.id)
group by to_char(twitter.tweets.date_time,'YYYY-MM');
To get counts for all months since Jan 2021:
SELECT date_trunc('month', date_time), count(*)
FROM twitter.tweets
WHERE date_time >= '2021-01-01'
GROUP BY 1;
If id can be NULL (which should be disallowed for an id column), use the slightly more expensive count(id) instead.
Count of distinct IDs:
SELECT date_trunc('month', date_time), count(DISTINCT id)
FROM twitter.tweets
WHERE date_time >= '2021-01-01'
GROUP BY 1;
For only Jan 2021:
SELECT count(DISTINCT id)
FROM twitter.tweets
WHERE date_time >= '2021-01-01'
WHERE date_time < '2021-02-01';

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

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);

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

Find rows with similar date values

I want to find customers where for example, system by error registered duplicates of an order.
It's pretty easy, if reg_date is EXACTLY the same but I have no idea how to implement it in query to count as duplicate if for example there was up to 1 second difference between transactions.
select * from
(select customer_id, reg_date, count(*) as cnt
from orders
group by 1,2
) x where cnt > 1
Here is example dataset:
https://www.db-fiddle.com/f/m6PhgReSQbVWVZhqe8n4mi/0
CUrrently only customer's 104 orders are counted as duplicates because its reg_date is identical, I want to count also orders 1,2 and 4,5 as there's just 1 second difference
demo:db<>fiddle
SELECT
customer_id,
reg_date
FROM (
SELECT
*,
reg_date - lag(reg_date) OVER (PARTITION BY customer_id ORDER BY reg_date) <= interval '1 second' as is_duplicate
FROM
orders
) s
WHERE is_duplicate
Use the lag() window function. It allows to have a look hat the previous record. With this value you can do a diff and filter the records where the diff time is more than one second.
Try this following script. This will return you day/customer wise duplicates.
SELECT
TO_CHAR(reg_date :: DATE, 'dd/mm/yyyy') reg_date,
customer_id,
count(*) as cnt
FROM orders
GROUP BY
TO_CHAR(reg_date :: DATE, 'dd/mm/yyyy'),
customer_id
HAVING count(*) >1