Date subtraction - sql

I'd like to select all the users in our database that put their accounts on hold the day they created them. Users can only go on hold for 1 month, so the logic would be selecting users where....
day(hold_until - 1 month) = day(signup)
How can I achieve this in SQL?

Try:
SELECT *
FROM TheTable
WHERE date(singup) = date(hold_until - INTERVAL '6 months')

It depends on the RDBMS You're using, but assuming this is PostgreSQL, you can try this:
...where
day(hold_until - interval '1 month') = day(signup)

Assuming you have timestamp columns:
... WHERE (hold_until - interval '1 month')::date = singnup::date

Related

PostgreSQL generate_series with WHERE clause

I'm having an issue generating a series of dates and then returning the COUNT of rows matching that each date in the series.
SELECT generate_series(current_date - interval '30 days', current_date, '1 day':: interval) AS i, COUNT(*)
FROM download
WHERE product_uuid = 'someUUID'
AND created_at = i
GROUP BY created_at::date
ORDER BY created_at::date ASC
I want the output to be the number of rows that match the current date in the series.
05-05-2018, 35
05-06-2018, 23
05-07-2018, 0
05-08-2018, 10
...
The schema has the following columns: id, product_uuid, created_at. Any help would be greatly appreciated. I can add more detail if needed.
Put the table generating function in the from and use a join:
SELECT g.dte, COUNT(d.product_uuid)
FROM generate_series(current_date - interval '30 days', current_date, '1 day':: interval
) gs(dte) left join
download d
on d.product_uuid = 'someUUID' AND
d.created_at::date = g.dte
GROUP BY g.dte
ORDER BY g.dte;

How to get min value of all cities of yesterday?

How to get min value(temp) of all cities of yesterday.
I want:
Indore:min value:yesterday date
Bhopal:min value:yesterday date
Mumbai:min value:yesterday date
In Postgres, you can do:
select name, min(temp)
from t
where write_date < current_date and
write_date >= current_date - interval '1 day'
group by name;
You can also write the where clause as:
where date_trunc('day', write_date) = current_date - interval '1 day'
However, using the function date_trunc() prevents the use of the index for the where clause.
select name, min(temp) from table
where date(write_date) BETWEEN TRUNC(SYSDATE - 1)
AND TRUNC(SYSDATE) - 1/86400
group by name
this will do your job

How to get date: one month away from a specific date?

I know that I can get the date from today such as
select CURRENT_DATE - INTERVAL '1 months';
But what if I need the first date specified. Something like
select '2017-05-08 00:00:00' - INTERVAL '1 months'?
I tried different things and can't get it to work.
You could use:
select '2017-05-08 00:00:00'::DATE - '1 month'::INTERVAL
/\
|
cast as date
DBFiddle Demo
'2017-05-08 00:00:00' is a string literal. You need to convert it to a date, e.g., by using to_date:
SELECT TO_DATE('2017-05-08','yyyy-mm-dd') - INTERVAL '1 months'

SQL Aggregation Join and Subquery Optimisation

I am trying to get aggregate values by time periods of two relations (buys and uses) and join them so that I can get the results in one report and also draw a ratio on them. I am using PostgreSQL. The end report required is: dateTime, u.sum, b.sum, b.sum/u.sum
The following query works but scales very poorly with larger table sizes.
SELECT b2.datetime AS dateTime, b2.sum AS BUY_VOLUME, u1.sum AS USE_VOLUME,
CASE u1.sum
WHEN 0 THEN 0
ELSE (b2.sum / u1.sum)
END AS buyToUseRatio
FROM(
SELECT SUM(b.total / 100.0) AS sum, date_trunc('week', (b.datetime + INTERVAL '1 day')) - INTERVAL '1 day' as datetime
FROM buys AS b
WHERE
datetime > date_trunc('month', CURRENT_DATE) - INTERVAL '1 year'
GROUP BY datetime) AS b2
INNER JOIN (SELECT SUM(u.amount) / 100.00 AS sum, date_trunc('week', (u.datetime + INTERVAL '1 day')) - INTERVAL '1 day' AS datetime
FROM uses AS u
WHERE
datetime > date_trunc('month', CURRENT_DATE) - INTERVAL '1 year'
GROUP BY datetime) AS u1 ON b2.datetime = u1.datetime
ORDER BY b2.datetime ASC;
I was wondering if anyone could help me by providing an alternative query that would get the end result required and is faster to execute.
I appreciate any help on this :-) My junior level SQL is a little rusty and I can't think of another way of doing this without creating indexes. Thanks in advance.
At least, these indexes can help your query:
create index idx_buys_datetime on buys(datetime);
create index idx_uses_datetime on uses(datetime);
Your query seems fine. However, you could use full join (instead of inner) to have all rows, where at least one of your tables have data. You could even use generate_series() to always have 1 year of results, even when there is no data in either of your tables, but I'm not sure if that's what you need. Also, some other things can be written more easily; your query could look like this:
select dt, buy_volume, use_volume, buy_volume / nullif(use_volume, 0.0) buy_to_use_ratio
from (select sum(total / 100.0) buy_volume, date_trunc('week', (datetime + interval '1 day')) - interval '1 day' dt
from buys
where datetime > date_trunc('month', current_timestamp - interval '1 year')
group by 2) b
full join (select sum(amount) / 100.0 use_volume, date_trunc('week', (datetime + interval '1 day')) - interval '1 day' dt
from uses
where datetime > date_trunc('month', current_timestamp - interval '1 year')
group by 2) u using (dt)
order by 1
http://rextester.com/YVASV92568
So the answer depends on how large your tables are, but if it was me, I would create one or two new "summary" tables based on your query and make sure to keep them updated (run a batch job once a day to update them or once an hour with all the data that has changed recently).
Then, I would be able to query those tables and do so, much faster.
If however, your tables are very small, then just keep going the way you are and play around with indexes till you get some timing which is acceptable.

How do I determine the last day of the previous month using PostgreSQL?

I need to query a PostgreSQL database to determine records that fall within today's date and the last day of the previous month. In other words, I'd like to retrieve everything that falls between December 31, 2011 and today. This query will be re-used each month, so next month, the query will be based upon the current date and January 31, 2012.
I've seen this option, but I'd prefer to avoid using a function (if possible).
Both solutions include the last day of the previous month and also include all of "today".
For a date column:
SELECT *
FROM tbl
WHERE my_date BETWEEN date_trunc('month', now())::date - 1
AND now()::date
You can subtract plain integer values from a date (but not from a timestamp) to subtract days. This is the simplest and fastest way.
For a timestamp column:
SELECT *
FROM tbl
WHERE my_timestamp >= date_trunc('month', now()) - interval '1 day'
AND my_timestamp < date_trunc('day' , now()) + interval '1 day'
I use the < operator for the second condition to get precise results (read: "before tomorrow").
I do not cast to date in the second query. Instead I add an interval '1 day', to avoid casting back and forth.
Have a look at date / time types and functions in the manual.
For getting date of previous/last month:
SELECT (date_trunc('month', now())::date - 1) as last_month_date
Result: 2012-11-30
For getting number of days of previous/last month:
SELECT DATE_PART('days', date_trunc('month', now())::date - 1) last_month_days
Result: 30
Try this:
SELECT ...
WHERE date_field between (date_trunc('MONTH', now()) - INTERVAL '1 day')::date
and now()::date
...
Try
select current_date - cast((date_part('day', current_date) + 1) as int)
take from http://wiki.postgresql.org/wiki/Date_LastDay, and modified to return just the days in a month
CREATE OR REPLACE FUNCTION calc_days_in_month(date)
RETURNS double precision AS
$$
SELECT EXTRACT(DAY FROM (date_trunc('MONTH', $1) + INTERVAL '1 MONTH - 1 day')::date);
$$ LANGUAGE 'sql' IMMUTABLE STRICT;
select calc_days_in_month('1999-05-01')
returns 31
Reference is taken from this blog:
You can use below function:
CREATE OR REPLACE FUNCTION fn_GetLastDayOfMonth(DATE)
RETURNS DATE AS
$$
SELECT (date_trunc('MONTH', $1) + INTERVAL '1 MONTH - 1 day')::DATE;
$$ LANGUAGE 'sql'
IMMUTABLE STRICT;
Sample executions:
SELECT *FROM fn_GetLastDayOfMonth(NOW()::DATE);