Oracle query displays data by month and year - sql

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.

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.

Expanding SQL query for multiple dates

I have a SQL query that includes a __DATE__ macro. A Python script replaces this macro with the current date and then the statement is executed thus giving one day's worth of data.
For the first item selected, I would like to use tblLabTestResult.CollectionDate instead of __DATE__.
I would like to include the prior 7 days instead of just the current day.
The desired output would be something similar to:
Date,Result,Total
2021-08-28,Detected,5
2021-08-28,Not Detected,9
2021-08-29,Detected,23
2021-08-29,Not Detected,6
2021-08-30,Detected,88
2021-08-30,Not Detected,26
Current query:
SELECT
'__DATE__' as Date,
tblLabTestResult.Result as Result,
Count(tblLabTestResult.Result) as Total
FROM
PncRegDb.dbo.tblLabTestResult as tblLabTestResult
WHERE
tblLabTestResult.TestName like '%cov%'
AND tblLabTestResult.TestName not like '%aoe%'
AND tblLabTestResult.TestName not like '%antibody%'
AND tblLabTestResult.CollectionDate >= '__DATE__'
AND tblLabTestResult.CollectionDate <= '__DATE__ 11:59:59 PM'
GROUP BY
tblLabTestResult.Result;
How can I change my SQL query to accommodate these requirements? I am using MS SQL Server.
You can use DATEADD() function to get the date from 7 days ago and use all dates between date-7days and date. I have updated where condition in your query below:
SELECT
'__DATE__' as Date,
tblLabTestResult.Result as Result,
Count(tblLabTestResult.Result) as Total
FROM
PncRegDb.dbo.tblLabTestResult as tblLabTestResult
WHERE
tblLabTestResult.TestName like '%cov%'
AND tblLabTestResult.TestName not like '%aoe%'
AND tblLabTestResult.TestName not like '%antibody%'
AND tblLabTestResult.CollectionDate between DATEADD(day, -7, '__DATE__') and '__DATE__ 11:59:59 PM'
GROUP BY
tblLabTestResult.Result;
A few points:
Columns that are not aggregated must be in the GROUP BY
You should be passing your date as a parameter
Best to use a half-open interval to compare dates (exclusive end-point), so #endDate is the day after the one you want
Use short, meaningful aliases to make your code more readable
It doesn't make sense to group and aggregate by the same column. If Result is a non-nullable column then Count(Result) is the same as Count(*)
If you want to group by whole days (and CollectionDate has a time component) then replace ltr.CollectionDate with CAST(ltr.CollectionDate AS date) in both the SELECT and GROUP BY
SELECT
ltr.CollectionDate as Date,
ltr.Result as Result,
COUNT(*) as Total
FROM
PncRegDb.dbo.tblLabTestResult as tblLabTestResult
WHERE
ltr.TestName like '%cov%'
AND ltr.TestName not like '%aoe%'
AND ltr.TestName not like '%antibody%'
AND ltr.CollectionDate >= #startdate
AND ltr.CollectionDate < #endDate
GROUP BY
ltr.CollectionDate, ltr.Result;

tdate issue I'm facing in SQL query

While fetching count from table by using following query
Select count(*)
from tab
where tdate = '17-05-19' ---> output 0
or
Select count(*)
from tab
where trunc(tdate) = '17-05-19' ---->output 0
If I use:
Select count(*)
from tab
where tdate >sysdate - 1 ---> it returns some count(yesterday+some of the today txn)
But here I want only yesterday txn whenever I fire this query.
But here I want only yesterday txn whenever I fire this query.
You may use this.
Select count (*) from tab where
tdate >= TRUNC(SYSDATE) - 1
AND tdate < TRUNC(SYSDATE)
The advantage of this over using TRUNC on the date column is that it will utilize an index if it exists over tdate
If you tried by using
Select count(*) from tab where trunc(tdate) = date'2019-05-17'
(or, you could use
Select count(*) from tab where to_char(tdate,'dd-mm-yy') = '17-05-19' by formatting through to_char function
or, you could use
Select count(*) from tab where trunc(tdate) = trunc(sysdate)-1 to get only the data for the day before
)
you'd get some results provided you have data for the date 17th May.
So, you need to provide a formatting for your literal as date'2019-05-17'(known as date literal) especially for Oracle DB, it might be used as '2019-05-17' without date part in MySQL as an example.
Btw, trunc function is used to extract the date portion, and remove the time part of a date type column value.
If your table is populated with huge data, therefore performance may matter, then you can even create functional index on trunc(tdate).
Demo

Postgresql query between date ranges

I am trying to query my postgresql db to return results where a date is in certain month and year. In other words I would like all the values for a month-year.
The only way i've been able to do it so far is like this:
SELECT user_id
FROM user_logs
WHERE login_date BETWEEN '2014-02-01' AND '2014-02-28'
Problem with this is that I have to calculate the first date and last date before querying the table. Is there a simpler way to do this?
Thanks
With dates (and times) many things become simpler if you use >= start AND < end.
For example:
SELECT
user_id
FROM
user_logs
WHERE
login_date >= '2014-02-01'
AND login_date < '2014-03-01'
In this case you still need to calculate the start date of the month you need, but that should be straight forward in any number of ways.
The end date is also simplified; just add exactly one month. No messing about with 28th, 30th, 31st, etc.
This structure also has the advantage of being able to maintain use of indexes.
Many people may suggest a form such as the following, but they do not use indexes:
WHERE
DATEPART('year', login_date) = 2014
AND DATEPART('month', login_date) = 2
This involves calculating the conditions for every single row in the table (a scan) and not using index to find the range of rows that will match (a range-seek).
From PostreSQL 9.2 Range Types are supported. So you can write this like:
SELECT user_id
FROM user_logs
WHERE '[2014-02-01, 2014-03-01]'::daterange #> login_date
this should be more efficient than the string comparison
Just in case somebody land here... since 8.1 you can simply use:
SELECT user_id
FROM user_logs
WHERE login_date BETWEEN SYMMETRIC '2014-02-01' AND '2014-02-28'
From the docs:
BETWEEN SYMMETRIC is the same as BETWEEN except there is no
requirement that the argument to the left of AND be less than or equal
to the argument on the right. If it is not, those two arguments are
automatically swapped, so that a nonempty range is always implied.
SELECT user_id
FROM user_logs
WHERE login_date BETWEEN '2014-02-01' AND '2014-03-01'
Between keyword works exceptionally for a date. it assumes the time is at 00:00:00 (i.e. midnight) for dates.
Read the documentation.
http://www.postgresql.org/docs/9.1/static/functions-datetime.html
I used a query like that:
WHERE
(
date_trunc('day',table1.date_eval) = '2015-02-09'
)
or
WHERE(date_trunc('day',table1.date_eval) >='2015-02-09'AND date_trunc('day',table1.date_eval) <'2015-02-09')

How to group by a date column by month

I have a table with a date column where date is stored in this format:
2012-08-01 16:39:17.601455+0530
How do I group or group_and_count on this column by month?
Your biggest problem is that SQLite won't directly recognize your dates as dates.
CREATE TABLE YOURTABLE (DateColumn date);
INSERT INTO "YOURTABLE" VALUES('2012-01-01');
INSERT INTO "YOURTABLE" VALUES('2012-08-01 16:39:17.601455+0530');
If you try to use strftime() to get the month . . .
sqlite> select strftime('%m', DateColumn) from yourtable;
01
. . . it picks up the month from the first row, but not from the second.
If you can reformat your existing data as valid timestamps (as far a SQLite is concerned), you can use this relatively simple query to group by year and month. (You almost certainly don't want to group by month alone.)
select strftime('%Y-%m', DateColumn) yr_mon, count(*) num_dates
from yourtable
group by yr_mon;
If you can't do that, you'll need to do some string parsing. Here's the simplest expression of this idea.
select substr(DateColumn, 1, 7) yr_mon, count(*) num_dates
from yourtable
group by yr_mon;
But that might not quite work for you. Since you have timezone information, it's sure to change the month for some values. To get a fully general solution, I think you'll need to correct for timezone, extract the year and month, and so on. The simpler approach would be to look hard at this data, declare "I'm not interested in accounting for those edge cases", and use the simpler query immediately above.
It took me a while to find the correct expression using Sequel. What I did was this:
Assuming a table like:
CREATE TABLE acct (date_time datetime, reward integer)
Then you can access the aggregated data as follows:
ds = DS[:acct]
ds.select_group(Sequel.function(:strftime, '%Y-%m', :date_time))
.select_append{sum(:reward)}.each do |row|
p row
end