How to round up a month-date based on certain parameters - sql

I need to round up a month-date based on certain parameters. For example: If I have a parameter where if a day in a given month is between the 6th and the 4th of the next month, I need my query to return the next months date. Is there a way to round up the month given these parameters without hard coding case whens for every single month ever?
SELECT case when date_trunc('day',li.created_at between '2019-03-06 00:00:00' and '2019-04-06 00:00:00' then '2019-04-01' end)
FROM line_items li

If you want the beginning of the month, but offset by 4 days, you can use date_trunc() and subtract some number of days (or add some number of days). You seem to want something like this:
select dateadd(month, 1, date_trunc('month', li.created_at - interval '4 day'))

Another approach is to create a canonical "dates" table that precomputes the mapping from a given date to a new date using your rounding scheme. The mapping could be done outside of redshift in a script and the table loaded in (or within redshift using a user defined function).

Related

Calculate the average time between two dates

I need to find the result of a calculation that is nothing more than the average time in days from creation to completion of a task.
In this case, using a Redshift database (looker).
I have two dates (2022/10/01 to 2022/10/21) and I need to find the average day of execution of the creation of an object from start to finish.
Previously, I was able to calculate the totals of objects created per day, but I can't bring up the average:
SELECT created::date, count(n1pk_package_id)
FROM dbt_dw.base_package
WHERE fk_company_id = 245821 and created >= '2022-10-01' and created < '2022-10-22'
GROUP BY created::date
ORDER BY created DESC
I'm not able to do the opposite way of the count to bring the average of the range of days.
Assumption:
There is a created column in your table
You want to know the 'average' of the created column
You could extract the number of days that each date is different from a base date, and then use that to determine the 'average date'. It would be something like this:
select
date '2022-10-01' + interval '1 day' * int(avg(created - date '2022-10-01'))
from table
It subtracts a date (any date will do) from created, finds the average of that value against all desired rows, converts it to days and adds it back to that same date.

How do I get the number of days in a month for the specific date in that row of data using SQL?

For example, if I have a data set including two columns, one which shows the month as a number and the other which shows the year (result of grouping my data using GROUP BY), I want to add another column called 'Days in the month' which will display the number of days in the respective month. Is there a way I can do this? Is there some function I can add in the SELECT clause?
I want to do this since there are further calculations I need to do with that number for each row.
In SQL Server 2012+, you can use:
select day(eomonth(datecol))
eomonth() gets the last day of the month. day() just returns the day of the month -- the number of days in the month, in this case.
For older SQL Server versions, I use the following:
DAY(DATEADD(MONTH, DATEDIFF(MONTH, -1, date_column)- 1, -1))
Much less elegant than the previous answer, but functional.

Modifying SYSDATE function

In one of my SQL queries, I am using
[... and z.READ_TIMESTAMP > TIMESTAMP_TO_EPOCH(TRUNC(SYSDATE-3)]
If I want the date to be exactly 5/31/2017, will I use 'SYSDATE' (date-n) function or some other expression? or how can a modify my query for 5/31/2017
If you want the date to be exactly 5/31/2017 then use TO_DATE() or TO_TIMESTAMP() depending on which data type you need (date or timestamp). As you are using SYSDATE already the the date data type should work.
-- e.g.
select
to_date('5/31/2017','mm/dd/yyyy')
, to_timestamp('5/31/2017','mm/dd/yyyy')
from dual
...
and z.READ_TIMESTAMP > TIMESTAMP_TO_EPOCH(to_date('5/31/2017','mm/dd/yyyy'))
HOWEVER
I suspect you may want more than just a way to establish a fixed date. For example are you asking for "how do I get that last day of the previous month?" which perhaps can be satisfied by using >= and the first day of current month like this:
...
and z.READ_TIMESTAMP >= TIMESTAMP_TO_EPOCH(trunc(sysdate,'MM'))
or if it really is the last day of the previous month can be achieved with a combination of LAST_DAY() and ADD_MONTHS()
and z.READ_TIMESTAMP >
TIMESTAMP_TO_EPOCH( last_day(add_months(trunc(sysdate,'MM'),-1)) )
Without knowing a great deal more about the nature of your data and query purpose please do note that each date you use when "truncated" also has the time set to 00:00:000 - so IF you data contains time within a day other than 00:00:00 then these 2 queries might NOT produce the same result
.... datetimecolumn > to_date('05/31/2017','mm/dd/yyyy') -- "a"
.... datetimecolumn >= to_date('06/01/2017','mm/dd/yyyy') -- "b"
For example "a" the entire 24 hour duration of 05/31/2017 would be included in the results, but for example "b" that same 24 hour duration would be excluded from results. In my experience the last day of any month isn't really the best method for locating date/time based data, instead usually it is the first day of the next month that produces the correct result.

How to get records between from and to date, when dates are for the same month/year?

I am trying to create a query to that can get some records in a table that is between a from and to date, with the dates being in month/year only. The problem that I am having is trying to get the records when the from and to dates are for the same month/year.
Here is a example of the issue that I am having:
select start_date
from job
where trunc(start_date) between to_date('05-2016','mm-yyyy') and to_date('05-2016','mm-yyyy')
In the job table, there are records with start_date in the month of May, but in order to see them I need to set the to date to '06-2016'. Is there way to get all of the records with a start_date in the month of May by just specifying that the from and to dates is 05-2016?
In your example you are selecting all start_date's between 5/1/2016 and 5/1/2016.
It seems like you want to capture everything in a month, but you are not specifying a format to truncate. Without specifying 'Month' in the Trunc() you are truncating to the day. When you truncate to Month you can now, actually just set it equal to the to_date() rather than between:
select start_date
from job
where trunc(start_date,'Month') = to_date('05-2016','mm-yyyy')
Here is some information on Trunc(date, [fmt]). when the fmt argument is left blank Trunc() defaults to 'round' to the nearest day but there are many other options.
If you want to specify ranges greater than a Month you can use between (but note, this is from the first day of the first to_date() to the first day of the second 'to_date()':
select start_date
from job
where trunc(start_date)
between to_date('06-2016','mm-yyyy')
and to_date('09-2016','mm-yyyy')
In this example all Start_dates would populate between 6/1/2016 and 9/1/2016.
I think the most accurate way to do this would be:
select start_date
from job
where trunc(start_date)
between to_date('06-01-2016','mm-dd-yyyy')
and to_date('09-30-2016','mm-dd-yyyy')
How about?
select start_date
from job
where trunc(start_date, 'mm') between
to_date('05-2016', 'mm-yyyy')
and to_date('05-2016', 'mm-yyyy')
Oracle has no way of interpolating the date on the right end of your between as falling at the end of the month. When to_date() is missing a day value in the format it simply supplies the 1st as the default value. Not sure if that's the behavior your were anticipating.
If instead you truncate dates by month (rather than day) then the comparisons will only involve dates falling on the first of the month. With the dates collapsed that way you can then treat a start and end of the two identical values as an inclusive range. Presumably you'll replace the hard-coded dates with parameters of some form and this works for wider ranges as well. Of course, the between can be just an equality test if you're always querying on a single month. And this isn't going to use an index on your column so it's not necessarily the most efficient.
I think this is what you're looking for. Is there a reason you need to supply the date value(s) in that format? Perhaps there's a better way to approach this using a little date math.
Try like this:
select start_date
from job
where trunc(start_date) between to_date('05-2016','mm-yyyy')
and dateadd('d', -1, dateadd('m', 1, to_date('05-2016','mm-yyyy')))
In order to see an entire month worth of dates, your date range in the between clause must be a full month long.

Is there a way to search a SQL Query with Month Numbers, and not Month Name?

I am trying to use the actual numerical value for the month on a sql query to pull results. Is there any way to do this without having a function to change the numbers to actual month names, then back to month numbers? The following code works for Names, what works for numbers?
datename(month,(convert(datetime,DTSTAMP)))=
'October'
month,(convert(datetime,DTSTAMP)) should do it, but why on earth are you not storing the data correctly as a datetime to begin with? All that additional conversion stuff to use the dates adds unnecessary load to your server and slows down your application.
Datepart is an alternative to the month command and it is more flexable as you can extract other parts of the date.
DATEPART(mm, convert(datetime,DTSTAMP))
Gets Month Number of Date
CONVERT(VARCHAR(2) ,DTSTAMP ,110)
here, you can search with diff options like:
DATE_SUB(CURDATE(), INTERVAL 0 DAY)
DATE_SUB(CURDATE(), INTERVAL 1 MONTH)
DATE_SUB(CURDATE(), INTERVAL 1 YEAR)
as per your requirement.