How to get end time of the current year - sql

example, this year is 2020, and the end time of the year islike this
'2020-12-31 23:59:59'
How to select those kind of value?
select endtimeofthisyear()

I understand you want last second of current year. Compute it as 1 s subtracted from first second of next year.
select date_trunc('year', now()) + interval '1 year' - interval '1 second'
Note: currently this is equivalent to concatenating hardcoded string ...23:59:59. If PG handled leap seconds (which AFAIK currently doesn't), it is more likely the leap second would be taken into consideration using expression above.

I can think of no good reason for looking for the last second of a year. If you are filtering by year, then use:
where date >= '2020-01-01' and date < '2021-01-01'
If you are constructing a table with time-tiling -- effective and end dates -- then make the first date inclusive and the second exclusive. Then the next effective date is the previous row's end date -- there is no gap.
You would query a table as:
where <some value> >= eff_dt and <some value> < end_dt
One issue in trying to get the last "moment" is that time is continuous (well, I suppose that is a fundamental question about the universe, but it is how we measure it). If you aim for the last second, you will miss times that occur during the last second, such as 2020-12-31 23:59:59.555.

Since every year ends on the 31.12. 23:59:59, just get the current_date, extract the year and add it.
date_trunc('year', now()) + '-12-31 23:59:59'

Related

Countdown the days and months within Postgres

I know of date_part('days', age(release_date)), which will show you days of the age of the release_date col (timestamp). For example, if the release date is 1994-05-30, the date_part calculation would yield 5 days.
However, how can I find out from a countdown perspective, ie, for another release. There are 2 days left till the anniversary of this release hits? Is it just a matter of 365 - date_part('days', age(release_date)), for example? Or is there a better way?
Transpose the release date to the current year and subtract the current date from it. Assuming release_date is an actual date:
SELECT *
, (release_date + (date_trunc('year', LOCALTIMESTAMP)
- date_trunc('year', release_date)))::date
- CURRENT_DATE AS days_till_aniversary
FROM release;
db<>fiddle here
There is a reason for LOCALTIMESTAMP in one spot and CURRENT_DATE in the other. This way, the calculation is done without involving time zones. (Except that either depends on the time zone setting of your session to begin with.) And subtracting dates yields an integer, signifying the difference in days.
Produces negative numbers past anniversaries this year.

Date Functions Trunc (SysDate)

I am running the below query to get data recorded in the past 24 hours. I need the same data recorded starting midnight (DATE > 12:00 AM) and also data recorded starting beginning of the month. Not sure if using between will work or if there is better option. Any suggestions.
SELECT COUNT(NUM)
FROM TABLE
WHERE
STATUS = 'CNLD'
AND
TRUNC(TO_DATE('1970-01-01','YYYY-MM-DD') + OPEN_DATE/86400) = trunc(sysdate)
Output (Just need Count). OPEN_DATE Data Type is NUMBER. the output below displays count in last 24 hours. I need the count beginning midnight and another count starting beginning of the month.
The query you've shown will get the count of rows where OPEN_DATE is an 'epoch date' number representing time after midnight this morning*. The condition:
TRUNC(TO_DATE('1970-01-01','YYYY-MM-DD') + OPEN_DATE/86400) = trunc(sysdate)
requires every OPEN_DATE value in your table (or at least all those for CNLD rows) to be converted from a number to an actual date, which is going to be doing a lot more work than necessary, and would stop a standard index against that column being used. It could be rewritten as:
OPEN_DATE >= (trunc(sysdate) - date '1970-01-01') * 86400
which converts midnight this morning to its epoch equivalent, once, and compares all the numbers against that value; using an index if there is one and the optimiser thinks it's appropriate.
To get everything since the start of the month you could just change the default behaviour of trunc(), which is to truncate to the 'DD' element, to truncate to the start of the month instead:
OPEN_DATE >= (trunc(sysdate, 'MM') - date '1970-01-01') * 86400
And the the last 24 hours, subtract a day from the current time instead of truncating it:
OPEN_DATE >= ((sysdate - 1) - date '1970-01-01') * 86400
db<>fiddle with some made-up data to get 72 back for today, more for the last 24 hours, and more still for the whole month.
Based on your current query I'm assuming there won't be any future-dated values, so you don't need to worry about an upper bound for any of these.
*Ignoring leap seconds...
It sounds like you have a column that is of data type TIMESTAMP and you only want to select rows where that TIMESTAMP indicates that it is today's date? And as a related problem, you want to find those that are the current month, based on some system values like CURRENT TIMESTAMP and CURRENT DATE? If so, let's call your column TRANSACTION_TIMESTAMP instead of (reserved word) DATE. Your first query could be:
SELECT COUNT(NUM)
FROM TABLE
WHERE
STATUS = 'CLND'
AND
DATE(TRANSACTION_TIMESTAMP)=CURRENT DATE
The second example of finding all for the current month up to today's date could be:
SELECT COUNT(NUM)
FROM TABLE
WHERE
STATUS = 'CLND'
AND
YEAR(DATE(TRANSACTION_TIMESTAMP)=YEAR(CURRENT DATE) AND
MONTH(DATE(TRANSACTION_TIMESTAMP)=MONTH(CURRENT DATE) AND
DAY(DATE(TRANSACTION_TIMESTAMP)<=DAY(CURRENT DATE)

How to fix a datetime restriction problem in a sql query?

I'm developing a SQL Query, as a restriction, I want that the query returns data from the first day of the last month until now.
For example: If the query is executed today, the query will only return data entered from 01/03/2019 until today.
To do this, i created the following restriction:
...
SF1010.F1_DTDIGIT>=concat(YEAR(GETDATE()),'0',month(GETDATE())-1,'01') AND
...
The problem is in the months 01, 11 and 12:
If the month is "11", the algorithm will return "1901001" and not "191001".
If the month is "01", the algorithm will return "190001" and not "181201".
Thanks for any help.
SF1010.F1_DTDIGT BETWEEN $yourDate AND date_add($yourDate,interval -DAY($yourDate)+1 DAY)
This gets dates between your date and the first day of the month. first day logic works by subtracting the DAY part to get first of month.
This query will do the comparison of your DTDIGIT with the first day of the previous month in the DATE format:
SF1010.F1_DTDIGIT >= STR_TO_DATE(CONCAT(YEAR(DATE_SUB(NOW(), INTERVAL 1 MONTH)),'-',MONTH(DATE_SUB(NOW(), INTERVAL 1 MONTH)),'-','1'), '%Y-%m-%d')
Explanation
DATE_SUB(NOW(), INTERVAL 1 MONTH) returns the date exactly one month ago. We use that date to get the previous month
YEAR() and MONTH() functions use the date explained above
STR_TO_DATE() function converts a string representing a date to the
MySQL DATE format, using the mask (in this example, it's
'%Y-%m-%d').
How about this?
SF1010.F1_DTDIGT >= date_add(date_add(curdate(), interval 1 - day(curdate()) day), interval -1 month)
This assumes the date is not in the future. You can add another condition if that is possible.
If you happen to be using SQL Server, you can do this weird form of date arithmetic:
SF1010.F1_DTDIGT >= dateadd(month, datediff(month, 0, getdate()) - 1, 0)

Get average for "last month" only

Pretty new to SQL and have hit a roadblock.
I have this query, which works fine:
SELECT
(COUNT(*)::float / (current_date - '2017-05-17'::date)) AS "avg_per_day"
FROM "table" tb;
I now want it to include only data from the last month, not all time.
I've tried doing something along the lines of:
SELECT
(COUNT(*)::float / (current_date - (current_date - '1 month' ::date)) AS "avg_per_day"
FROM "table" tb;
The syntax is clearly wrong, but I am not sure what the right answer is. Have googled around and tried various options to no avail.
I can't use a simple AVG because the number I require is an AVG per day for the last month of data. Thus I've done a count of rows divided by the number of days since the first occurrence to get my AVG per day.
I have a column which tells me the date of the occurrence, however there are multiple rows with the same date in the dataset. e.g.
created_at
----------------------------
Monday 27th June 2017 12:00
Monday 27th June 2017 13:00
Tuesday 28th June 2017 12:00
and so on.
I am counting the number of occurrences per day and then need to work out an average from that, for the last month of results only (they date back to May).
The answer depends on the exact definition of "last month" and the exact definition of "average count".
Assuming:
Your column is defined created_at timestamptz NOT NULL
You want the average number of rows per day - days without any rows count as 0.
Cover 30 days exactly, excluding today.
SELECT round(count(*)::numeric / 30, 2) -- simple now with a fixed number of days
FROM tbl
WHERE created_at >= (now()::date - 30)
AND created_at < now()::date -- excl. today
Rounding is optional, but you need numeric instead of float to use round() this way.
Not including the current day ("today"), which is ongoing and may result in a lower, misleading average.
If "last month" is supposed to mean something else, you need to define it exactly. Months have between 28 and 31 days, this can mean various things. And since you obviously operate with timestamp or timestamptz, not date, you also need to be aware of possible implications of the time of day and the current time zone. The cast to date (or the definition of "day" in general) depends on your current timezone setting while operating with timestamptz.
Related:
Ignoring timezones altogether in Rails and PostgreSQL
Select today's (since midnight) timestamps only
Subtract hours from the now() function
I think you just need a where clause:
SELECT
(COUNT(*)::float / (current_date - (current_date - '1 month' ::date)) AS "avg_per_day"
FROM "table" tb
WHERE created_at > (current_date - '1 month' ::date)
I believe Postgresql and other RDBMS has AVG() to calculate average.
SELECT AVG(tb.columnName) AS avg_per_month
FROM someTable tb
WHERE
tb.createdDate >= [start date of month] AND
tb.createdDate <= [end date of month]
Edit: I subtract current date with INTERVAL. I am on mobile phone so I cannot test.
SELECT
(COUNT(*)::float / (current_date - ( current_date - INTERVAL '1 month')) AS "avg_per_day"
FROM "table" tb;

SQL +/- number meaning?

I could not find the meaning of the following SQL command:
where date between to_date('2013-03-01', 'yyyy-mm-dd') and trunc(sysdate, 'mm') -1
What does the "-1" mean / does?
The other example is
trunc(months_between(date1, date2))+1
I have searched for this, but could not find a thing.
Thank you for advice!
As others have answered, "date - 1" subtracts one day from the date. Here's more detail on your specific SQL snippets:
where date between to_date('2013-03-01', 'yyyy-mm-dd') and trunc(sysdate, 'mm') -1`
This evaluates to "date between 3/1/2013 and the end of last month"
TRUNC(some date, 'MM') chops the date to the beginning of the month
TRUNC(SYSDATE, 'MM') returns the beginning of the current month
TRUNC(SYSDATE, 'MM')-1 returns the last day of the previous month
trunc(months_between(date1, date2))+1
This is giving the number of full months between date1 and date2, treating any fraction of a month as a whole month. For example, if you gave it the dates 7/28/2013 and 7/29/2013 it would report one month, and it would also report one month if you gave it 7/1/2013 and 7/31/2013.
The MONTHS_BETWEEN function returns, as it implies, the number of months between two dates. The return value will have decimal places - for example a return value of 1.5 means one and a half months.
The TRUNC function, when applied against a numeric, will chop off all its decimals, so TRUNC(1.9999999) will return 1.
+1 is way to add a day to the date
-1 is way to remove a day to the date
In your specific case:
the instruction trunc(sysdate, 'mm') -1 remove one month to the date, in this case is one month before the current date.
the instruction trunc(months_between(date1, date2))+1 compute the difference in month between the two dates and then adds one.
Give a look at this SQLFiddle
it is a lazy way of adding or subtracting day(s)