how do I calculate days of week in this current date?
if I use
select
date_trunc(salesdate, month)mt,
count(distinct case when extract(dayofweek from salesdate) in (6,7,1) then salesdate end) weekend,
count(distinct case when extract(dayofweek from salesdate) not in (6,7,1) then salesdate end) weekday
from `my_table` group by 1
salesdate is the date I got from November-now.
and the answer I got
since this month is not completed yet. the numbers of weekend and weekday is depend on the current date
what I expected is will be
mt weekend weekday
2023-01-01 13 18
2022-12-01 14 17
Can you try this:
with my_table as (
select *
from unnest(generate_date_array('2022-11-01', current_date(), interval 1 day))salesdate
)
select mt
,count(distinct case when extract(dayofweek from salesdate) in (6,7,1) then salesdate end) weekend
,count(distinct case when extract(dayofweek from salesdate) not in (6,7,1) then salesdate end) weekday
from (
select
date_trunc(salesdate, month)mt,
LAST_DAY(salesdate, MONTH)ld
from my_table
group by mt,ld
),
unnest(generate_date_array(mt, ld, interval 1 day))salesdate
group by mt
Query results:
Related
Select date_trunc('week',dateTime) Date_week, Max(Ranking) Runing_Total_ID
from (select datetime, id , dense_rank () over (order by datetime) as Ranking
from Table1)
group by 1
This query is working for me to give me the running total of total IDs by week. But the week starts on Monday in Postgres by default. Is there any way to change the week start to SUNDAY?
Shift the timestamp back and forth:
Add a day before feeding the timestamp to date_trunc(), then subtract again:
SELECT date_trunc('week', datetime + interval '1 day') - interval '1 day' AS date_week
, max(ranking) AS runing_total_id
FROM (
SELECT datetime, dense_rank() OVER (ORDER BY datetime) AS ranking
FROM table1
) sub
GROUP BY 1;
See:
PostgreSQL custom week number - first week containing Feb 1st
I want to be able to generate groups of row by days, weeks, month or depending on the interval I set
Following this solution, it works when granularity is by month. But trying the interval of 1 week, no records are being returned.
This is the rows on my table
This is the current query I have for per month interval, which works perfectly.
SELECT *
FROM (
SELECT day::date
FROM generate_series(timestamp '2018-09-01'
, timestamp '2018-12-01'
, interval '1 month') day
) d
LEFT JOIN (
SELECT date_trunc('month', created_date)::date AS day
, SUM(escrow_amount) AS profit, sum(total_amount) as revenue
FROM (
select distinct on (order_id) order_id, escrow_amount, total_amount, create_time from order_item
WHERE created_date >= date '2018-09-01'
AND created_date <= date '2018-12-01'
-- AND ... more conditions
) t2 GROUP BY 1
) t USING (day)
ORDER BY day;
Result from this query
And this is the per week interval query. I will reduce the range to two months for brevity.
SELECT *
FROM (
SELECT day::date
FROM generate_series(timestamp '2018-09-01'
, timestamp '2018-11-01'
, interval '1 week') day
) d
LEFT JOIN (
SELECT date_trunc('week', created_date)::date AS day
, SUM(escrow_amount) AS profit, sum(total_amount) as revenue
FROM (
select distinct on (order_id) order_id, escrow_amount, total_amount, create_time from order_item
WHERE created_date >= date '2018-09-01'
AND created_date <= date '2018-11-01'
-- AND ... more conditions
) t2 GROUP BY 1
) t USING (day)
ORDER BY day;
Take note that I have records from October, but the result here doesn't show anything for October dates.
Any idea what I am missing here?
Results from your first query are not truncated to the begin of the week.
date_trunc('2018-09-01'::date, 'week')::date
is equal to
'2018-08-27'::date
so your join using day is not working
'2018-09-01'::date <> '2018-08-27'::date
Your query should look more like that:
SELECT *
FROM (
SELECT day::date
FROM generate_series(date_trunc('week',timestamp '2018-09-01') --series begin trunc
, timestamp '2018-11-01'
, interval '1 week') day
) d
LEFT JOIN (
SELECT date_trunc('week', created_date::date)::date AS day
, SUM(escrow_amount) AS profit, sum(total_amount) as revenue
FROM (
select distinct on (order_id) order_id, escrow_amount, total_amount, create_time from order_item
WHERE created_date::date >= date '2018-09-01'
AND created_date::date <= date '2018-11-01'
-- AND ... more conditions
) t2 GROUP BY 1
) t USING (day)
WHERE day >= '2018-09-01' --to skip days from begining of the week to the begining of the series before trunc
ORDER BY day;
There is one table:
ID DATE
1 2017-09-16 20:12:48
2 2017-09-16 20:38:54
3 2017-09-16 23:58:01
4 2017-09-17 00:24:48
5 2017-09-17 00:26:42
..
The result I need is the last 7-days of data with hourly aggregated count of rows:
COUNT DATE
2 2017-09-16 21:00:00
0 2017-09-16 22:00:00
0 2017-09-16 23:00:00
1 2017-09-17 00:00:00
2 2017-09-17 01:00:00
..
I tried different stuff with EXTRACT, DISTINCT and also used the generate_series function (most stuff from similar stackoverflow questions)
This try was the best one currently:
SELECT
date_trunc('hour', demotime) as date,
COUNT(demotime) as count
FROM demo
GROUP BY date
How to generate hourly series for 7 days and fill-in the count of rows?
SQL DEMO
SELECT dd, count("demotime")
FROM generate_series
( current_date - interval '7 days'
, current_date
, '1 hour'::interval) dd
LEFT JOIN Table1
ON dd = date_trunc('hour', demotime)
GROUP BY dd;
To work from now and now - 7 days:
SELECT dd, count("demotime")
FROM generate_series
( date_trunc('hour', NOW()) - interval '7 days'
, date_trunc('hour', NOW())
, '1 hour'::interval) dd
LEFT JOIN Table1
ON dd = date_trunc('hour', demotime)
GROUP BY dd;
I have a table with the date columns (start_date, end_date) and I want to calculate the difference between these dates and grouped by the month.
I am able to get the datediff in days, but I do not know how to group this in month, any suggestions?
Table:
id Start_date End_date days
1234 2014-06-03 2014-07-05 32
12345 2014-02-02 2014-05-10 97
Expected results:
month diff_days
2 26
3 30
4 31
5 10
6 27
7 5
I think your expected output numbers are off a little. You might want to double-check.
I use a calendar table myself, but this query uses a CTE and date arithmetic. Avoiding the hard-coded date '2014-01-01' and the interval for 365 days is straightforward, but it makes the query harder to read, so I just used those values directly.
with your_data as (
select date '2014-06-03' as start_date, date '2014-07-05' as end_date union all
select '2014-02-02', '2014-05-10'
), calendar as (
select date '2014-01-01' + (n || ' days')::interval calendar_date
from generate_series(0, 365) n
)
select extract (month from calendar_date) calendar_month, count(*) from calendar
inner join your_data on calendar.calendar_date between start_date and end_date
group by calendar_month
order by calendar_month;
calendar_month count
--
2 27
3 31
4 30
5 10
6 28
7 5
As a rule of thumb, you should never group by the month alone--doing that risks grouping data from different years. This is a safer version that includes the year, and which also restricts output to a single calendar year.
with your_data as (
select date '2014-06-03' as start_date, date '2014-07-05' as end_date union all
select '2014-02-02', '2014-05-10'
), calendar as (
select date '2014-01-01' + (n || ' days')::interval calendar_date
from generate_series(0, 700) n
)
select extract (year from calendar_date) calendar_year, extract (month from calendar_date) calendar_month, count(*) from calendar
inner join your_data on calendar.calendar_date between start_date and end_date
where calendar_date between '2014-01-01' and '2014-12-31'
group by calendar_year, calendar_month
order by calendar_year, calendar_month;
SQL Fiddle
with min_max as (
select min(start_date) as start_date, max(end_date) as end_date
from t
), g as (
select daterange(d::date, (d + interval '1 month')::date, '[)') as r
from generate_series(
(select date_trunc('month', start_date) from min_max),
(select end_date from min_max),
'1 month'
) g(d)
)
select *
from (
select
to_char(lower(r), 'YYYY Mon') as "Month",
sum(upper(r) - lower(r)) as days
from (
select t.r * g.r as r
from
(
select daterange(start_date, end_date, '[]') as r
from t
) t
inner join
g on t.r && g.r
) s
group by 1
) s
order by to_timestamp("Month", 'YYYY Mon')
;
Month | days
----------+------
2014 Feb | 27
2014 Mar | 31
2014 Apr | 30
2014 May | 10
2014 Jun | 28
2014 Jul | 5
Range data types
Range functions and operators
I would like to get the count of ordered items from monday to sunday but adding saturday and sunday orders to fridays, so the query results would only display Orderdates (Monday to Friday)
I have this sql already that shows orders for every single day of the week:
select DATENAME(weekday,orderdate) Day,CONVERT(VARCHAR(10), orderdate, 103) orderdate,
COUNT(orderdate) Orders
from Orders_tb
where orderDate >= '2012-03-01 00:00:00.000'
and orderDate <= '2012-03-31 00:00:00.000'
group by datepart(day,orderDate),orderdate,DATENAME(weekday,orderdate)
Thanks for your input!
EDIT after clarification.
Use case to change weekend days to friday. Derived table is employed to avoid the need to replicate the same expression everywhere orderdate is needed.
select DATENAME(weekday,orderdate_trimmed) Day,
CONVERT(VARCHAR(10), orderdate_trimmed, 103) orderdate,
COUNT(orderdate_trimmed) Orders
from
(
select *,
order_date -
case DATENAME(weekday,orderdate)
when 'Saturday' then 1
when 'Sunday' then 2
else 0
end
orderdate_trimmed
from Orders_tb
) a
where orderDate >= '2012-03-01 00:00:00.000'
and orderDate <= '2012-03-31 00:00:00.000'
group by orderdate_trimmed
You might count matching days only by use of case statement:
select COUNT(orderdate) TotalOrders,
COUNT(CASE WHEN DATENAME(weekday,orderdate) = 'Monday' then 1 end) Monday,
COUNT(CASE WHEN DATENAME(weekday,orderdate) = 'Tuesday' then 1 end) Tuesday,
COUNT(CASE WHEN DATENAME(weekday,orderdate) = 'Wednesday' then 1 end) Wednesday,
COUNT(CASE WHEN DATENAME(weekday,orderdate) = 'Thursday' then 1 end) Thursday,
COUNT(CASE WHEN DATENAME(weekday,orderdate) = 'Friday'
OR DATENAME(weekday,orderdate) = 'Saturday'
OR DATENAME(weekday,orderdate) = 'Sunday'
THEN 1 end) Friday
from Orders_tb
where orderDate >= '2012-03-01 00:00:00.000'
and orderDate <= '2012-03-31 00:00:00.000'
A warning about dates: as a date can contain time portion it would be wiser to compare like this:
where orderDate >= '2012-03-01 00:00:00.000'
and orderDate < '2012-04-01 00:00:00.000'