Oracle Count number of records each hour [duplicate] - sql

This question already has answers here:
Counting number of records hour by hour between two dates in oracle
(5 answers)
Closed 8 years ago.
I'm trying to get the number of records created each hour but running into trouble with getting the results to group correctly. The idea is similiar to: How to count number of records per day?
However, the field I'm using to Group by is a Date-time field that records down to the second. This seems to be causing trouble with the Group By statement, as when the query returns, there is one row for each second in the specified time period, which is way too much data and will make the work I want to do with the results more difficult than it needs to be (if for no other reason that it's too many rows to fit on one Excel sheet).
My current code is:
SELECT ASD, Count(ASD) Num_CR
From DB_Name.Table_Name fcr
Where trunc(fcr.ASD) > to_Char('31-DEC-2014')
And trunc(fcr.ASD) < to_Char('31-JAN-2015')
And fcr.Status_Code = 'C'
Group By ASD
Order By ASD;
I've tried changing the Group By to be trunc(ASD), but that results in Toad throwing this error: ORA-00979: not a GROUP BY expression.
Thanks in advance!

When you use aggregation anything in the select and order by clauses must match what's in the group by clause:
SELECT trunc(ASD,'hh'), Count(ASD) Num_CR
From DB_Name.Table_Name fcr
Where trunc(fcr.ASD) > to_date('31-DEC-2014')
And trunc(fcr.ASD) < to_date('31-JAN-2015')
And fcr.Status_Code = 'C'
Group By trunc(ASD,'hh')
Order By trunc(ASD,'hh');
When applied to a date, trunc will truncate to the day. To truncate to a different level, specify the format of the element you'd like to truncate to as the second argument (e.g. 'hh' will truncate to the hour; 'mm' will truncate to the month).

SELECT to_char(ASD,'DD-MM-YYYY HH'), Count(ASD) Num_CR
From DB_Name.Table_Name fcr
Where trunc(fcr.ASD) > to_Char('31-DEC-2014')
And trunc(fcr.ASD) < to_Char('31-JAN-2015')
And fcr.Status_Code = 'C'
Group By to_char(ASD,'DD-MM-YYYY HH')
Order By to_char(ASD,'DD-MM-YYYY HH');
Quick and dirty :)

First off, why are you doing to_char on something that's already a string? Secondly, why are you trying to compare something that's (presumably) a DATE column to a string? That way lies madness...
I think you're after something like:
SELECT trunc(ASD, 'hh') asd_hr, Count(ASD) Num_CR
From DB_Name.Table_Name fcr
Where trunc(fcr.ASD) > to_date('31/12/2014', 'dd/mm/yyyy')
And trunc(fcr.ASD) < to_date('31/01/2015', 'dd/mm/yyyy')
And fcr.Status_Code = 'C'
Group By trunc(ASD, 'hh')
Order By trunc(ASD, 'hh');
Also worth noting, did you mean to exclude the last day of January from your query? If so, then fine, but if not, then perhaps you should change it to to_date('01/02/2015', 'dd/mm/yyyy')

Related

How to Group by Current day and Count Rows?

Hello I have table "os_txn.pay_link" and inside there are many columns.
What I want to do is that I want to count the row numbers by looking at "merchant_id" column for the current day.
So for example what I am looking for an output is that today one of "merchant_id" has
"8" rows. So I want to know the number of rows of the "merchant_id" column for current day.
I think I should use count(*) in view with select statement but couldnt succeed about syntax. So I am open your suggestions thank you.
If I understood you correctly, a simple option would be
select merchant_id, count(*)
from os_txn.pay_link
where date_column = trunc(sysdate)
group by merchant_id;
presuming that date_column contains date only (i.e. for today, 8th of October 2022, that's its value - no hours, minutes or seconds).
If date column contains time component, again - a simple option - would be
select merchant_id, count(*)
from os_txn.pay_link
where trunc(date_column) = trunc(sysdate)
group by merchant_id;
If there's an index on date_column, then such a code wouldn't use it (unless it is a function-based index) so you'd rather modify it to
where date_column >= trunc(sysdate)
and date_column < trunc(sysdate + 1)
If that's not it, do post sample data and desired result.

Oracle query displays data by month and year

I want to display the amount of data by month and year. This is an example of displaying data by date:
select count(*) from db.trx where trxdate = to_date('2018-04-23','yyyy-mm-dd')
When I try to display the amount of data by month and year, no query results appear. Is there something wrong with the query?
The query:
select count(*) from db.trx where trxdate = to_date('2018-04','yyyy-mm')
You need to apply the function to trxdate. Using your logic:
SELECT Count(*)
FROM olap.trxh2hpdam
WHERE To_char(trxdate, 'YYYY-MM') = '2018-04';
However, I strongly recommend that you use direct date comparisons:
WHERE trxdate >= date '2018-04-01'
AND
trxdate < date '2018-05-01'
This will allow the database to use an index on trxdate.
There are a couple of ways of accomplishing what you're trying to do. Which one works for you will depend on your database design (for example, the indexes you've created). One way might be this:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE TRUNC(trxdate, 'MONTH') = DATE'2018-04-01';
This will round the date down to the first of the month (and, of course, remove any time portion). Then you simply compare it to the first of the month for which you want the data. However, unless you have an index on TRUNC(trxdate, 'MONTH'), this may not be the best course of action; if trxdate is indexed, you'll want to use:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE trxdate >= DATE'2018-04-01'
AND trxdate < DATE'2018-05-01';
There are a number of functions at your disposal in Oracle (e.g. ADD_MONTHS()) in the event that the date you use in your query is supposed to be dynamic rather than static.
Just FYI, there is no reason not to use ANSI date literals when trying to retrieve data by day as well. I'm not sure your original query is a good example of getting data for a particular day, since the Oracle DATE datatype does at least potentially include a time:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE trxdate >= DATE'2018-04-23'
AND trxdate < DATE'2018-04-24';
or:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE TRUNC(trxdate) = DATE'2018-04-23';
EDIT
In case the month and year are dynamic, I would build a date from them (e.g., TO_DATE('<year>-<month>-01', 'YYYY-MM-DD')) and then use the following query:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE trxdate >= TO_DATE('<year>-<month>-01', 'YYYY-MM-DD')
AND trxdate < ADD_MONTHS( TO_DATE('<year>-<month>-01', 'YYYY-MM-DD'), 1 );
Hope this helps.

sql query to get today new records compared with yesterday

i have this table:
COD (Integer) (PK)
ID (Varchar)
DATE (Date)
I just want to get the new ID's from today, compared with yesterday (the ID's from today that are not present yesterday)
This needs to be done with just one query, maximum efficiency because the table will have 4-5 millions records
As a java developer i am able to do this with 2 queries, but with just one is beyond my knowledge so any help would be so much appreciated
EDIT: date format is dd/mm/yyyy and every day each ID may come 0 or 1 times
Here is a solution that will go over the base data one time only. It selects the id and the date where the date is either yesterday or today (or both). Then it GROUPS BY id - each group will have either one or two rows. Then it filters by the condition that the MIN date in the group is "today". Those are the id's that exist today but did not exist yesterday.
DATE is an Oracle keyword, best not used as a column name. I changed that to DT. I also assume that your "dt" field is a pure date (as pure as it can be in Oracle, meaning: time of day, which is always present, is 00:00:00).
select id
from your_table
where dt in (trunc(sysdate), trunc(sysdate) - 1)
group by id
having min(dt) = trunc(sysdate)
;
Edit: Gordon makes a good point: perhaps you may have more than one such row per ID, in the same day? In that case the time-of-day may also be different from 00:00:00.
If so, the solution can be adapted:
select id
from your_table
where dt >= trunc(sysdate) - 1 and dt < trunc(sysdate) + 1
group by id
having min(dt) >= trunc(sysdate)
;
Either way: (1) the base table is read just once; (2) the column DT is not wrapped within any function, so if there is an index on that column, it can be used to access just the needed rows.
The typical method would use not exists:
select t.*
from t
where t.date >= trunc(sysdate) and t.date < trunc(sysdate + 1) and
not exists (select 1
from t t2
where t2.id = t.id and
t2.date >= trunc(sysdate - 1) and t2.date < trunc(sysdate)
);
This is a general solution. If you know that there is at most one record per day, there are better solutions, such as using lag().
Use MINUS. I suppose your date column has a time part, so you need to truncate it.
select id from mytable where trunc(date) = trunc(sysdate)
minus
select id from mytable where trunc(date) = trunc(sysdate) - 1;
I suggest the following function index. Without it, the query would have to full scan the table, which would probably be quite slow.
create idx on mytable( trunc(sysdate) , id );

working with a date in SQL

i know this query is not right, and kind of jumbled. but it sort of displays what i want to do. what I'm trying to figure out is how to use the current date in a query. basically i want to subtract a stored date from the current date and if the result is < 30 do something. but i obviously don't know how to work with dates.... i am assuming that it shouldn't be a char value, but if i just use sys date oracle gives me a table error.
select e.STUDENT_ID
from COURSES c, CLASS_ENROLLMENT e, (SELECT TO_CHAR (SYSDATE, 'MM-DD-YYYY') as now
FROM DUAL) t
where t - c.END_DATE <= 30;
Assuming the rest of your query is correct this should solve your date problem:
select e.STUDENT_ID
from COURSES c, CLASS_ENROLLMENT e
where to_date(to_char(sysdate, 'DD-MON-RR')) - c.END_DATE <= 30;
You don't need to select sysdate from dual unless you just want to display it for one reason or another without querying something else. You can just specify it as sysdate as part of a any query anywhere.
The reason I converted it to a character and then to a date in this case is just to remove the time from sysdate, this way it will be 30 days from the given day, regardless of time. If you didn't care about time you could just say sysdate - c.end_date <=30
As an fyi - you probably need to add join conditions between the COURSES and CLASS_ENROLLMENT tables. The above should not result in a sql error and should do you want with respect to the date of the records, but it's unlikely to be what you want (in full).

SQL count for the current 7 days

I want to get a list of the number of orders entered to our database for the last 7 days. I've tried repeating the below but it becomes some error messages about incorrect format, so I'm wondering what's the correct method.
To get order amount for current day I use SELECT COUNT(order_number) FROM orders WHERE created = TO_CHAR(sysdate, 'DD-MON-YYYY');
I want a table like:
Date Total Orders
sysdate 500
sysdate-1 400
sysdate-2 300
etc. for the last 7 days. Is it possible?
I believe the following would work for you:
Select created, count(ordernumber)
From orders
Where to_date(created, 'DD-MON-YYYY') between trunc(sysdate-7) and trunc(sysdate)
Group by created
Order by to_date(created, 'DD-MON-YYYY') desc
Note, if you can change it I would seriously consider using a DATE column for created.
You should have mentioned the specific error. I guess created is a date field and you are trying to compare it with a string. If this is the case, here is the statement needed. TRUNC removes the time part from the date.
SELECT TRUNC(created), COUNT(order_number)
FROM orders
WHERE TRUNC(created) BETWEEN TRUNC(sysdate) - 6 AND TRUNC(sysdate)
GROUP BY TRUNC(created)
ORDER BY TRUNC(created);