I have a code below but it throws an error.
How do I get the date 12 weeks from 2018-01-01 and use the case statement?
select
case when
date between cast('2018-01-01' as date) and DATE_ADD('week',12,cast('2018-01-01' as date)) -interval '1' day
then 'in 12 weeks' as period
from aaa limit 1
Your case statement misses closing end:
WITH dataset AS (
SELECT * FROM (VALUES
(DATE '2018-01-03'),
(DATE '2018-04-04')
) AS t (date))
SELECT
CASE
WHEN date BETWEEN Cast('2018-01-01' AS date) AND date_add('week', 12, cast('2018-01-01' AS date)) - INTERVAL '1' day
THEN 'in 12 weeks'
END AS period
FROM
dataset
LIMIT
1
Related
Date
ID
Value
2022-10-07 17:30:00.000
1
1
2022-10-10 10:00:00.000
2
2
2022-10-12 08:31:42.000
3
1
I want to find date difference from two rows with few conditions in MS SQL
Difference should be from 9am - 6pm (exclude rest of the time)
Also Exclude weekends.
For example, Date Diff from first row will be 1 hr 30 mins.
I am using this query:
DATEDIFF(MINUTE, LAG(date) OVER (ORDER BY date), date)
How can I add more conditions to this?
First things first, let's compute the values we need to handle, namely the current date (that we already have as a field) and the previous date (using the LAG window function, as you did in your attempt).
WITH cte AS (
SELECT [date] AS curDate,
LAG([date]) OVER(ORDER BY date) AS prevDate
FROM tab
)
CASE 1: prevDate's day is equal to curDate's day
In this case we just need to apply the difference in minutes between the two dates as follows:
CASE WHEN CONVERT(DATE, curDate) = CONVERT(DATE, prevDate)
THEN DATEDIFF(MINUTE, prevDate, curDate)
CASE 2: prevDate's day is not equal to curDate's day
Here we need to compute three things:
the difference in time between endtime (18:00:00) and prevDate's time
DATEDIFF(MINUTE, CAST(prevDate AS TIME), '18:00:00')
the difference in time between starttime (9:00:00) and curDate's time
DATEDIFF(MINUTE, '9:00:00', CAST(curDate AS TIME))
the difference in days between curDate and prevDate. For this last one there's the caveat regarding the weekend days though. We can solve this problem by checking if the day of week of curDate is smaller than the day of week of prevDate (if prevDate's working date is Friday and curDate's working date is Monday, we will have dayofweek = 2 for Monday and dayofweek = 6 for Friday, whereas 2-6<0). If the result is smaller than 0, then we need to subtract 3 days of work (multiplied by 9 days of working activity for each day - 18:00:00-9:00:00).
DATEDIFF(MINUTE, '9:00:00', CAST(curDate AS TIME)) +
DATEDIFF(MINUTE, CAST(prevDate AS TIME), '18:00:00') +
9*(DATEDIFF(DAY, prevDate, curDate) -
CASE WHEN DATEPART(WEEKDAY, curDate) - DATEPART(WEEKDAY, prevDate) > 1
THEN 0
ELSE 3 END
)
Hence the Final Query would be the following one:
WITH cte AS (
SELECT [date] AS curDate,
LAG([date]) OVER(ORDER BY date) AS prevDate
FROM tab
)
SELECT curDate,
CASE WHEN CONVERT(DATE, curDate) = CONVERT(DATE, prevDate)
THEN DATEDIFF(MINUTE, prevDate, curDate)
ELSE DATEDIFF(MINUTE, '9:00:00', CAST(curDate AS TIME)) +
DATEDIFF(MINUTE, CAST(prevDate AS TIME), '18:00:00') +
9*(DATEDIFF(DAY, prevDate, curDate) -
CASE WHEN DATEPART(WEEKDAY, curDate) - DATEPART(WEEKDAY, prevDate) > 1
THEN 0
ELSE 3 END)
END
FROM cte
Check the demo here.
I have a query that can create a table with dates like below:
with digit as (
select 0 as d union all
select 1 union all select 2 union all select 3 union all
select 4 union all select 5 union all select 6 union all
select 7 union all select 8 union all select 9
),
seq as (
select a.d + (10 * b.d) + (100 * c.d) + (1000 * d.d) as num
from digit a
cross join
digit b
cross join
digit c
cross join
digit d
order by 1
)
select (last_day(sysdate)::date - seq.num)::date as "Date"
from seq;
How could this be changed to generate only dates
Thanks
demo:db<>fiddle
WITH dates AS (
SELECT
date_trunc('month', CURRENT_DATE) AS first_day_of_month,
date_trunc('month', CURRENT_DATE) + interval '1 month -1 day' AS last_day_of_month
)
SELECT
generate_series(first_day_of_month, last_day_of_month, interval '1 day')::date
FROM dates
date_trunc() truncates a type date (or timestamp) to a certain date part. date_trunc('month', ...) removes all parts but year and month. All other parts are set to their lowest possible values. So, the day part is set to 1. That's why you get the first day of month with this.
adding a month returns the first of the next month, subtracting a day from this results in the last day of the current month.
Finally you can generate a date series with start and end date using the generate_series() function
Edit: Redshift does not support generate_series() with type date and timestamp but with integer. So, we need to create an integer series instead and adding the results to the first of the month:
db<>fiddle
WITH dates AS (
SELECT
date_trunc('month', CURRENT_DATE) AS first_day_of_month,
date_trunc('month', CURRENT_DATE) + interval '1 month -1 day' AS last_day_of_month
)
SELECT
first_day_of_month::date + gs
FROM
dates,
generate_series(
date_part('day', first_day_of_month)::int - 1,
date_part('day', last_day_of_month)::int - 1
) as gs
This answers the original version of the question.
You would use generate_series():
select gs.dte
from generate_series(date_trunc('month', now()::date),
date_trunc('month', now()::date) + interval '1 month' - interval '1 day',
interval '1 day'
) gs(dte);
Here is a db<>fiddle.
I'm trying to create a query to only return data where date is minus 3 days from the current date. I've tried:
date <= DATE_ADD(CURRENT_DATE(), -3, 'DAY')
But this returns Error: Expected INTERVAL expression
See WHERE clause in below example
#standardSQL
WITH yourTable AS (
SELECT i, date
FROM UNNEST(GENERATE_DATE_ARRAY('2017-04-15', '2017-04-28')) AS date WITH OFFSET AS i
)
SELECT *
FROM yourTable
WHERE date <= DATE_SUB(CURRENT_DATE(), INTERVAL 3 DAY)
-- ORDER BY date
Btw, in case if you are still with Legacy SQL - see below example
#legacySQL
SELECT *
FROM -- yourTable
(SELECT 1 AS id, DATE('2017-04-20') AS date),
(SELECT 2 AS id, DATE('2017-04-21') AS date),
(SELECT 3 AS id, DATE('2017-04-22') AS date),
(SELECT 4 AS id, DATE('2017-04-23') AS date),
(SELECT 5 AS id, DATE('2017-04-24') AS date),
(SELECT 6 AS id, DATE('2017-04-25') AS date)
WHERE TIMESTAMP(date) <= DATE_ADD(TIMESTAMP(CURRENT_DATE()), -3, 'DAY')
-- ORDER BY date
This works with a string formatted date.
DATE(TIMESTAMP(date)) <= DATE_SUB(CURRENT_DATE(), INTERVAL 3 DAY)
Just tested this and seems to work.
I added this :
and DATE(TIMESTAMP(datevalue)) >= DATE_SUB(CURRENT_DATE(), INTERVAL 21 DAY)
and managed to get all records greater than last 21 days worth. Only thing I changed from #ericbrownaustin 's code was changed the 'date' in the first piece of code in the second set of parenthesis.
I got a date that I want to find the all records in the past that got the same month and day.
The problem accrues when there is no such date in the same year. For example, the 29th February.
My goal is to get the nearest date from below the date that does not exist.
This is my currently query with the date 2012-02-29:
SELECT date, amount
FROM table_name
WHERE
EXTRACT(MONTH FROM date) = EXTRACT(MONTH FROM DATE('2012-02-29') )
AND EXTRACT(DAY FROM date) = EXTRACT(DAY FROM DATE('2012-02-29') )
AND date < '2012-02-29'
ORDER BY date DESC LIMIT 10;
If I understand correctly, you want one date per year with the property that that day is nearest to the given date.
I would suggest using distinct on:
select distinct on (date_trunc('year', date)) t.*
from table_name t
order by date_trunc('year', date),
abs(date_part('day, (date -
(date '2012-02-29' -
(extract(year from date '2012-02-29') - extract(year from date)) * interval '1 year'
)
)
)
)
);
EDIT:
An example of working code:
select distinct on (date_trunc('year', date)) t.*
from table_name t
order by date_trunc('year', date),
abs(date_part('day', date - (date '2012-02-29' -
((extract(year from date '2012-02-29') - extract(year from date)) * interval '1 year')
)
))
I want to have this query:
SELECT DATE(DATE_SUB(DATE('2010-09-10'), (CASE DATETYPE WHEN 'H' THEN INTERVAL 1 WEEK ELSE INTERVAL 1 YEAR END CASE))) AS wdt
MySQL says it's invalid
also I have tried
SELECT _DATE AS wdt
UNION ALL
CASE DATETYPE
WHEN 'H' THEN SELECT DATE(DATE_SUB(_DATE, INTERVAL 1 YEAR)) AS wdt ;
ELSE SELECT DATE(DATE_SUB(DATE('2010-09-10'), INTERVAL 1 WEEK )) AS wdt;
END CASE;
UNION ALL
SELECT DATE(DATE_SUB(_DATE, INTERVAL 2 WEEK)) AS wdt
which doesn't work also, error in query syntax.
How can I select interval 1 year for dates that are Holidays.
Using two DATE_SUB operations would work:
SELECT IF (DATETYPE = 'H',
DATE_SUB(DATE('2010-09-10'), INTERVAL 1 WEEK),
DATE_SUB(DATE('2010-09-10'), INTERVAL 1 YEAR))
as wdt;