PostgreSQL Select every fifteen day of month - sql

Hello i have some record:
date Money
1/6/2014 100
12/6/2014 2200
13/6/2014 500
1/3/2014 100
2/5/2014 2200
30/5/2014 500
30/6/2014 100
23/6/2014 2200
31/6/2014 500
Well, i have one param, its date for example i need all record of 30 of july but i need the sum of record if very easy that
select sum(money) from info where date <= param
group by month
But now i need all record group by day of month but i need every fifteen for every month to lower the parameter in my result i need for example
param = 30/6/2014
The result I hope to get:
15/6/2014 sum(money)
15/5/2014 sum(money)
15/4/2014 sum(money)
I need the record for every fifteen of month

The question is how to arrange it to days up to the 15th are in one month and days from the 16th onward are in the next month. You can do this by subtracting 15 days. This puts all days from 1-15 in the previous month. Then, add a month. Here is an approach in Postgres:
select to_char(date - 15 * interval '1 day' + interval '1 month', 'YYYY-MM') as mon,
sum(money)
from info
where date <= param
group by to_char(date - 15 * interval '1 day' + interval '1 month', 'YYYY-MM')
order by 1;
EDIT:
If you want month-to-the-15th, then you can do:
select to_char(date, 'YYYY-MM') as mon,
sum(money)
from info
where extract(day from date) <= param
group by to_char(date, 'YYYY-MM')
order by 1;
Or, if it is only for one month:
select sum(money)
from info
where to_char(date, 'YYYY-MM') = to_char(param, 'YYYY-MM') and
date <= param;

Related

postgresql show month start date and end date based on given dates

I need to pull out first date and last date of the month from the given from_date and to_date as input, For Example:-
I have my psql output table as the following:
Year
Term
Start Date
End Date
2022
Odd
01-02-2022
30-04-2022
2022
Even
01-07-2022
30-09-2022
I need the output as the following:-
Year
Term
Start Date
End Date
2022
Odd
01-02-2022
28-02-2022
2022
Odd
01-03-2022
31-03-2022
2022
Odd
01-04-2022
30-04-2022
2022
Even
01-07-2022
30-07-2022
2022
Even
01-08-2022
31-08-2022
2022
Even
01-09-2022
30-09-2022
I need the ouput in Postgresql, Pls help
Thanks
Your issue boils down to given a period with start and end dates, determine the first and last dates for each month in that period. In Postgres given a date you can determine the first (with date_trunc function) and last of the a month with the expressions:
-- for a given date
date_trunc('month', given_date) -- returns first day of month
date_trunc('month', given_date + interval '1 month' - interval '1 day') -- returns last day of month
Use the first expression above, with generate_series with dates, to create the first of each month in the period. The use the second expression to generate the end of each month. (see demo)
with range_dates (year, term, gsom) as
( select year
, term
, generate_series( date_trunc('month', od.start_date)::date
, date_trunc('month', od.end_date )::date
, interval '1 month'
)::date
from output_data od
)
select year
, term
, gsom start_date
, (gsom + interval '1 month' - interval '1 day')::date end_date
from range_dates
order by term desc, start_date;

Get data of last Month day by day in oracle sql

I want to get data from last month day by day, I can get the last 30 days but I just want the month as it may be less or more than 30 days,
this is the query for getting the last 30 days
SELECT Trunc(timestamp),
Count(*)
FROM table1
WHERE Trunc(timestamp) > Trunc(sysdate - 30)
GROUP BY Trunc(timestamp)
ORDER BY 1;
Also, I am using it in a shell script if I can make a variable in the script and put it the query
To get data from the start of the current month until today:
SELECT TRUNC(timestamp) AS day,
COUNT(*)
FROM table1
WHERE timestamp >= TRUNC(SYSDATE, 'MM')
AND timestamp < TRUNC(SYSDATE) + INTERVAL '1' DAY
GROUP BY TRUNC(timestamp)
ORDER BY day
To get data from the same day last month until today:
SELECT TRUNC(timestamp) AS day,
COUNT(*)
FROM table1
WHERE timestamp >= ADD_MONTHS(TRUNC(SYSDATE), -1)
AND timestamp < TRUNC(SYSDATE) + INTERVAL '1' DAY
GROUP BY TRUNC(timestamp)
ORDER BY day
db<>fiddle here

Statistic of sales per day in the last 30 day

I have a quest that is about doing a statistic of the sales per day in the last 30 day...i've found a way to only show the last month:
SELECT *
FROM purchase
WHERE date >= date('01-05-2021', current_date - interval '1 month')
and date < date('01-05-2021', current_date)
the columns in purchase are just id, value, date, cashier and store id what do you think is the best way to do this?
i have this and i don't know way it is not working...i'm new in postgresql so please don't be offended by this
Group by date and use sum to find the total.
select date,sum(value)
from purchase
where date between current_date - interval '1 month' and current_date - 1
group by date

Select data with a rolling date criteria

The below query returns a distinct count of 'members' for a given month and brand (see image below).
select to_char(transaction_date, 'YYYY-MM') as month, brand,
count(distinct UNIQUE_MEM_ID) as distinct_count
from source.table
group by to_char(transaction_date, 'YYYY-MM'), brand;
The data is collected with a 15 day lag after the month closes (meaning September 2016 MONTHLY data won't be 100% until October 15). I am only concerned with monthly data.
The query I would like to build: Until the 15th of this month (October), last month's data (September) should reflect August's data. The current partial month (October) should default to the prior month and thus also to the above logic.
After the 15th of this month, last month's data (September) is now 100% and thus September should reflect September (and October will reflect September until November 15th, and so on).
The current partial month will always = the prior month. The complexity of the query is how to calc prior month.
This query will be ran on a rolling basis so needs to be dynamic.
To be clear, I am trying to build a query where distinct_count for the prior month (until end of current month + 15 days) should reflect (current month - 2) value (for each respective brand). After 15 days of the close of the month, prior month = (current month - 1).
Partial current month defaults to prior month's data. The 15 day value should be variable/modifiable.
First, simplify the query to:
select to_char(transaction_date, 'YYYY-MM') as month, brand,
count(distinct members) as distinct_count
from source.table
group by members, to_char(transaction_date, 'YYYY-MM'), brand;
Then, you are going to have a problem. The problem is that one row (say from Aug 20th) needs to go into two groups. A simple group by won't handle this. So, let's use union all. I think the result is something like this:
select date_trunc('month', transaction_date) as month, brand,
count(distinct members) as distinct_count
from source.table
where (date_trunc('month', transaction_date) < date_trunc('month' current_date) - interval '1 month') or
(day(current_date) > 15 and date_trunc('month', transaction_date) = date_trunc('month' current_date) - interval '1 month')
group by date_trunc('month', transaction_date), brand
union all
select date_trunc('month' current_date) - interval '1 month' as month, brand,
count(distinct members) as distinct_count
from source.table
where (day(current_date) < 15 and date_trunc('month', transaction_date) = date_trunc('month' current_date) - interval '1 month')
group by brand;
Since you already have a working query, I concentrate on the subselect. The condition you can use here is CASE, especially "Searched CASE"
case
when extract(day from current_date) < 15 then
extract(month from current_date - interval '2 months')
else
extract(month from current_date - interval '1 month')
end case
This may be used as part of a where clause, for example.
Here is some sudo code to get the begin date and the end date for your interval.
Begin date:
date DATE_TRUNC('month', CURRENT_DATE - integer 15) - interval '1 month'
This will return the current month only after the 15th day, from there you can subtract a full month to get your starting point.
End Date:
To calculate this, grab the begin date, plus a month, minus a day.
If the source table is partitioned by transaction_date, this syntax (not masking transaction_date with expression) enables partitions eliminatation.
select to_char(transaction_date, 'YYYY-MM') as month
,count (distinct members) as distinct_count
,brand as brand
FROM source.table
where transaction_date between date_trunc('month', current_date) - case when extract (day from current_date) >= 15 then 1 else 2 end * interval '1' month
and date_trunc('month', current_date) - case when extract (day from current_date) >= 15 then 0 else 1 end * interval '1' month - interval '1' day
group by to_char(transaction_date, 'YYYY-MM')
,brand
;

Generate series of week intervals for given month

In a Postgres 9.1 database, I am trying to generate a series of weeks for a given month but with some constraints. I need all weeks to start on Monday and get cut when they start or end in another month.
Example:
For February, 2013 I want to generate a series like this:
start
------------------------
2013-02-01 00:00:00+00
2013-02-04 00:00:00+00
2013-02-11 00:00:00+00
2013-02-18 00:00:00+00
2013-02-25 00:00:00+00
The query that I have now looks like this:
SELECT GREATEST(date_trunc('week', dates.d),
date_trunc('month',dates.d)) as start
FROM generate_series(to_timestamp(1359676800),to_timestamp(1362095999), '1 week') as dates(d)
This query gets me the first 4 weeks but it's missing the week from the 25th. Is it possible to get the last week?
SELECT generate_series(date_trunc('week', date '2013-02-01' + interval '6 days')
, date_trunc('week', date '2013-02-01' + interval '1 month - 1 day')
, interval '1 week')::date AS day
UNION SELECT date '2013-02-01'
ORDER BY 1;
This variant does not need a subselect, GREATEST or GROUP BY and only generates the required rows. Simpler, faster. It's cheaper to UNION one row.
Add 6 days to the first day of the month before date_trunc('week', ...) to compute the first Monday of the month.
Add 1 month and subtract 1 day before date_trunc('week', ...) to get the last Monday of the month.
This can conveniently be stuffed into a single interval expression: '1 month - 1 day'
UNION (not UNION ALL) the first day of the month to add it unless it's already included as Monday.
Note that date + interval results in timestamp, which is the optimum here. Detailed explanation:
Generating time series between two dates in PostgreSQL
Automation
You can provide the start of the date series in a CTE:
WITH t(d) AS (SELECT date '2013-02-01') -- enter 1st of month once
SELECT generate_series(date_trunc('week', d + interval '6 days')
, date_trunc('week', d + interval '1 month - 1 day')
, interval '1 week')::date AS day
FROM t
UNION SELECT d FROM t
ORDER BY 1;
Or wrap it into a simple SQL function for convenience with repeated calls:
CREATE OR REPLACE FUNCTION f_week_starts_this_month(date)
RETURNS SETOF date AS
$func$
SELECT generate_series(date_trunc('week', $1 + interval '6 days')
, date_trunc('week', $1 + interval '1 month - 1 day')
, interval '1 week')::date AS day
UNION
SELECT $1
ORDER BY 1
$func$ LANGUAGE sql IMMUTABLE;
Call:
SELECT * FROM f_week_starts_this_month('2013-02-01');
You would pass the date for the first day of the month, but it works for any date. You the first day and all Mondays for the following month.
select
greatest(date_trunc('week', dates.d), date_trunc('month',dates.d)) as start
from generate_series('2013-02-01'::date, '2013-02-28', '1 day') as dates(d)
group by 1
order by 1