I found that there is a function last_day for last day of month, and date_part(dow, date) for numeric day of week starting with Sunday, but I am trying to take a date, and get the first day of that week.
Meaning: if date='2018-02-14' then result should be '2018-02-11'.
Any ideas?
You simply want to subtract the dow value from the current date.
select dateadd(d, -datepart(dow, my_date), my_date)
from (select date('2018-02-14') as my_date)
> 2018-02-11 00:00:00.0
For example, if dow is 3 for 2018-02-14 - a Wednesday - you can subtract 3 days to get back to "day 0".
There's also the date_trunc function which will truncate everything after a given datepart. This is a little clunky, and will only set you back to the previous Monday, not Sunday.
select date_trunc('week', my_date)
from (select date('2018-02-14') as my_date)
Not sure if there is a more efficient solution but:
date_trunc('week',my_date + '1 day'::interval)::date - '1 day'::interval as week_start
If you want to get First day of week with week start day is any day in the week (Monday, Tuesday, ...). You can use this way:
day_of_week_index mapping:
{
'monday': 1,
'tuesday': 2,
'wednesday': 3,
'thursday': 4,
'friday': 5,
'saturday': 6,
'sunday': 7
}
Query Template:
SELECT
CASE
WHEN extract(ISODOW FROM datetime_column) < day_of_week_index THEN cast(date_trunc('week', datetime_column) AS date) - 8 + day_of_week_index
ELSE cast(date_trunc('week', datetime_column) AS date) - 1 + day_of_week_index
END
FROM table_name;
Example:
Get First day of week with week start day is Wednesday
SELECT
CASE
WHEN extract(ISODOW FROM TIMESTAMP '2021-12-03 03:00:00') < 3 THEN cast(date_trunc('week', TIMESTAMP '2021-12-03 03:00:00') AS date) - 8 + 3
ELSE cast(date_trunc('week', TIMESTAMP '2021-12-03 03:00:00') AS date) - 1 + 3
END;
=> Result:
2021-12-01
Note: You can change the day_of_week_index following the above mapping to determine the week start day (Monday, Tuesday, ..., Sunday).
Related
At my work we run a report a couple times a week to pull some information from BigQuery.
We run the report every Monday and Thursday.
I'd like to automate the report to run on these days and want to know if I can put in some logic so that if I run the report on a Monday, it runs the data for the previous business week (Sunday - Saturday), and if I run the report on a Thursday, it runs the report for the current business week so far (Sunday - Wednesday).
On another report where I only run the report for previous week I use:
select last_day(current_date - 14, week(monday)) as lw_week_start, last_day(current_date - 7, week(sunday)) as lw_week_end
And to get the current week dates I can use:
select last_day (current_date -7, week(monday)), (current_date -1)
So can I put both of these in my query, and use some sort of logic to say, if I run on a Monday use the first one, if I run on a Thursday, use the second one?
Thanks
You can define the period as a CTE (or if you prefer as variables) and then use that information in the query:
with period as (
select (case when extract(dayofweek from current_date) = 2
then last_day(date_add(current_date, interval -14 day), week(monday))
when extract(dayofweek from current_date) = 5
then last_day(date_add(current_date, interval -7 day), week(monday))
end) as lw_week_start,
(case when extract(dayofweek from current_date) = 2
then last_day(date_add(current_date, interval -7 day), week(sunday)
when extract(dayofweek from current_date) = 5
then date_add(current_date, interval -1 day)
end) as lw_week_end
)
select . . .
from period cross join
. . .
Notes:
This only includes Mondays and Thursdays. I imagine you want to extend this to the other days of the week.
current_date is the current date UTC. You might want to include your timezone:
select current_date('America/New_York')
/* if current_date is monday then it will return previous week report
else it will give report for present week for any other current_date */
IF (EXTRACT (DAYOFWEEK FROM CURRENT_DATE)) = 2 THEN
select last_day(current_date - 14, week(monday)) as lw_week_start, last_day(current_date - 7, week(sunday)) as lw_week_end;
ELSE
select last_day (current_date -7, week(monday)) as week_start, (current_date -1) as previous_day ;
END IF
Scripting on BigQuery
BigQuery Date fuctions
Simply add below to your where clause
where your_date_column in unnest(
case extract(dayofweek from current_date())
when 2 then generate_date_array(last_day(current_date() - 14, week(monday)), last_day(current_date() - 7, week(sunday)))
when 5 then generate_date_array(last_day (current_date() - 7, week(monday)), current_date() - 1)
end
)
How to query (SELECT) in Postgresql, so that the results of a column with different dates, are between Sunday and Saturday of the current week.
Query fake example:
SELECT * FROM table WHERE datecolumn BETWEEN CURRENT WEEK
In another query, I have the number of the week in the year. How to make a SELECT for these dates, applying in the WHERE clause the specific week number in the specific year.
Query fake example:
SELECT * FROM table WHERE datecolumn BETWEEN WEEK15 FROM year 2020
Perhaps you can use something like this:
SELECT *
FROM table
WHERE
EXTRACT(week FROM datecolumn) = EXTRACT(week FROM NOW())
AND
EXTRACT(isoyear FROM datecolumn) = EXTRACT(isoyear FROM NOW())
The week is ISO-8601 week number. By definition, ISO weeks start on Mondays and the first week of a year contains January 4 of that year. In other words, the first Thursday of a year is in week 1 of that year.
In the ISO week-numbering system, it is possible for early-January dates to be part of the 52nd or 53rd week of the previous year, and for late-December dates to be part of the first week of the next year.
For example, 2005-01-01 is part of the 53rd week of year 2004, and 2006-01-01 is part of the 52nd week of year 2005, while 2012-12-31 is part of the first week of 2013.
It's recommended to use the isoyear field together with week to get consistent results.
If you need custom (non-ISO) week numbering - you will have to craft your own calculation.
I would recommend the following pair of conditions:
where
date_column >= current_date - extract(dow from current_date) * interval '1 day'
and date_column < current_date - (extract(dow from current_date) - 8) * interval '1 day'
Postgres' date_trunc(week, ...) starts weeks on Monday, so we need something a little more complicated, using extract(dow from ...), which returns 0 on Sundays.
The advantage of this approach is that it is SARGeable, since no function is applied to the column being filtered. This means that this would happily take advantage of an index on the date column.
I would use date_trunc(), but like this. For the current week:
where datecolumn >= date_trunc('week', now()) and
datecolumn < date_trunc('week', now()) + interval '1 week'
For the nth week of the year, this is trickier. I think this does what you want:
where datecolumn >= (date_trunc('week', now()) -
(extract(week from now()) - 1) * interval '1 week' +
<n> * interval '1 week'
) and
datecolumn < (date_trunc('week', now()) -
(extract(week from now()) - 1) * interval '1 week' +
(<n> + 1) * interval '1 week'
)
Both of these are structured so the computations are NOT on the columns, so they are compatible with using indexes.
I have a table which has all the purchases of my costumers. I want to select all entries from the last week, (week start from Sunday).
id value date
5907 1.20 "2015-06-05 09:08:34-03"
5908 120.00 "2015-06-09 07:58:12-03"
I've tried this:
SELECT id, valor, created, FROM compras WHERE created >= now() - interval '1 week' and parceiro_id= '1'
But I got the data from the last week including data from this week, I only want data from the last week.
How to get data only from last week ?
This condition will return records from Sunday till Saturday last week:
WHERE created BETWEEN
NOW()::DATE-EXTRACT(DOW FROM NOW())::INTEGER-7
AND NOW()::DATE-EXTRACT(DOW from NOW())::INTEGER
There is an example:
WITH compras AS (
SELECT ( NOW() + (s::TEXT || ' day')::INTERVAL )::TIMESTAMP(0) AS created
FROM generate_series(-20, 20, 1) AS s
)
SELECT to_char( created, 'DY'::TEXT), created
FROM compras
WHERE created BETWEEN
NOW()::DATE-EXTRACT(DOW FROM NOW())::INTEGER-7
AND NOW()::DATE-EXTRACT(DOW from NOW())::INTEGER
In answer to #d456:
Wouldn't using BETWEEN include midnight on Sunday at both ends of the interval?
That right, BETWEEN includes midnight on Sunday at both ends of the interval. To exclude midnight on Sunday at end of interval it is necessary to use operators >= and <:
WITH compras AS (
SELECT s as created
FROM generate_series( -- this would produce timestamps with 20 minutes step
(now() - '20 days'::interval)::date,
(now() + '20 days'::interval)::date,
'20 minutes'::interval) AS s
)
SELECT to_char( created, 'DY'::TEXT), created
FROM compras
WHERE TRUE
AND created >= NOW()::DATE-EXTRACT(DOW FROM NOW())::INTEGER-7
AND created < NOW()::DATE-EXTRACT(DOW from NOW())::INTEGER
Postgres by default starts weeks on a Sunday, so you are in luck. You can use date_trunc() to get the beginning of the previous week:
WHERE (created >= date_trunc('week', CURRENT_TIMESTAMP - interval '1 week') and
created < date_trunc('week', CURRENT_TIMESTAMP)
)
EDIT:
Postgres by default starts week for date_trunc on Monday, but for dow on Sunday. So, you can do what you want by using that logic, which Nicolai has in his answer.
I used following query to get current week
select extract(week from current_timestamp) and it is showing 34 thats fine.
But how do i get the current week number of the current month.
You can find the first day of this week with:
trunc('week', current_date)
And the first day of the first week of this month with:
trunc('week', date_trunc('month', current_date))
Subtract the two to find the in-month weeknumber:
extract('day' from date_trunc('week', current_date) -
date_trunc('week', date_trunc('month', current_date))) / 7 + 1
Try the following
SELECT to_char('2016-05-01'::timestamp, 'W');
You can find week number by using day as well like:
select ((date_part('day', current_date)::integer - 1) / 7) +1;
Im not sure on how does this work on postgreSql (http://www.w3cyberlearnings.com/PostgreSQL_DATE_PART)
but in sql server the example is something like this...
>SELECT date_part('week', date)
This will give accurate results
CREATE OR REPLACE FUNCTION week_no(date)
RETURNS integer AS
$BODY$
SELECT
CASE WHEN EXTRACT(DAY FROM $1::TIMESTAMP)::INTEGER = 1
THEN 1
ELSE extract(week from $1:: TIMESTAMP)::integer
- extract(week from ( date_trunc('month', $1::TIMESTAMP) + interval '1 day' ) )::integer + 1
END
$BODY$
LANGUAGE sql IMMUTABLE STRICT
COST 100;
Example: week_no('2017-01-01') = 1
Maybe late.. but this works too
where cast(call_start as Date) = Date 'today'
or cast(call_start as Date)= Date 'today' -1
or cast(call_start as Date)= Date 'today' -2
or cast(call_start as Date)= Date 'today' -3
or cast(call_start as Date)= Date 'today' -4
or cast(call_start as Date)= Date 'today' -5
or cast(call_start as Date)= Date 'today' -6
or cast(call_start as Date)= Date 'today' -7
;
this gives me it
I am using PostgreSQL 8.3. I have a table like this:
id regist_time result
-----------------------------------
1 2012-07-09 15:00:08 3
2 2012-07-25 22:24:22 7
4 2012-07-07 22:24:22 8
regist_time's data type is timestamp.
I need to find a week time interval(start to end)
and sum(result) as num.
I want to get the result as:
week num
---------------------------------
7/1/2012-7/7/2012 10
7/8/2012-7/14/2012 5
7/15/2012-7/21/2012 3
7/22/2012-7/28/2012 11
I can get the week number just in this year:
SELECT id,regis_time, EXTRACT(WEEK FROM regis_time) AS regweek
FROM tba
The key part is
EXTRACT(WEEK FROM regis_time)
extract function can only get the week number in this year, how can I get start time to end time in one week?
You can use date_trunc('week', ...).
For example:
SELECT date_trunc('week', '2012-07-25 22:24:22'::timestamp);
-> 2012-07-23 00:00:00
Then, you can convert this into a date, if you're not interested in a start time.
To get the end date too:
SELECT date_trunc('week', '2012-07-25 22:24:22'::timestamp)::date
|| ' '
|| (date_trunc('week', '2012-07-25 22:24:22'::timestamp)+ '6 days'::interval)::date;
-> 2012-07-23 2012-07-29
(I've used the default formatting here, you can of course adapt this to use MM/DD/YYYY.)
Note that, if you want to make comparisons on timestamps, instead of using (date_trunc('week', ...) + '6 days'::interval, you might want to add an entire week and use a strict comparison for the end of the week.
This will exclude y timestamps on the last day of the week (since the cut-off time is midnight on the day).
date_trunc('week', x)::date <= y::timestamp
AND y::timestamp <= (date_trunc('week', x) + '6 days'::interval)::date
This will include them:
date_trunc('week', x)::date <= y::timestamp
AND y::timestamp < (date_trunc('week', x) + '1 week'::interval)
(That's in the rare cases when you can't use date_trunc on y directly.)
If your week starts on a Sunday, replacing date_trunc('week', x)::date with date_trunc('week', x + '1 day'::interval)::date - '1 day'::interval should work.
select date_trunc('week', regist_time)::date || ' - ' ||
(date_trunc('week', regist_time) + '6 days') ::date as Week,
sum(result) Total
from YourTable
group by date_trunc('week', regist_time)
order by date_trunc('week', regist_time)
See proof of concept at SQLFiddle: http://sqlfiddle.com/#!1/9e821/1
This can help, a query to get all days of current week.
select cast(date_trunc('week', current_date) as date) + i
from generate_series(0,6) i
2015-08-17
2015-08-18
2015-08-19
2015-08-20
2015-08-21
To get week start and end date (as 0 for Monday and 4 for Friday):
select cast(date_trunc('week', current_date) as date) + 0 || '-->' || cast(date_trunc('week', current_date) as date) + 4;
2015-08-17-->2015-08-21
It is
select to_date('2015-07', 'IYYY-IW');
use it in postgres
it will return
2015-02-09
If you want to get week start and end date with week start day is any day in the week (Monday, Tuesday, ...). You can use this way:
day_of_week_index mapping:
{
'monday': 1,
'tuesday': 2,
'wednesday': 3,
'thursday': 4,
'friday': 5,
'saturday': 6,
'sunday': 7
}
Query template:
SELECT
concat(
CASE
WHEN extract(ISODOW FROM datetime_column) < day_of_week_index THEN cast(date_trunc('week', datetime_column) AS date) - 8 + day_of_week_index
ELSE cast(date_trunc('week', datetime_column) AS date) - 1 + day_of_week_index
END, ' - ',
CASE
WHEN extract(ISODOW FROM datetime_column) < day_of_week_index THEN cast(date_trunc('week', datetime_column) AS date) - 8 + day_of_week_index + 6
ELSE cast(date_trunc('week', datetime_column) AS date) - 1 + day_of_week_index + 6
END)
FROM table_name;
Example:
Get week start and end date with week start day is Tuesday:
SELECT
concat(
CASE
WHEN extract(ISODOW FROM TIMESTAMP '2021-12-01 03:00:00') < 2 THEN cast(date_trunc('week', TIMESTAMP '2021-12-01 03:00:00') AS date) - 8 + 2
ELSE cast(date_trunc('week', TIMESTAMP '2021-12-01 03:00:00') AS date) - 1 + 2
END, ' - ',
CASE
WHEN extract(ISODOW FROM TIMESTAMP '2021-12-01 03:00:00') < 2 THEN cast(date_trunc('week', TIMESTAMP '2021-12-01 03:00:00') AS date) - 8 + 2 + 6
ELSE cast(date_trunc('week', TIMESTAMP '2021-12-01 03:00:00') AS date) - 1 + 2 + 6
END);
=> Result:
2021-11-30 - 2021-12-06
Note: You can change the day_of_week_index following the above mapping to determine the week start day (Monday, Tuesday, ..., Sunday)