MySQL date range SELECT + JOIN query using column with CURRENT_TIMESTAMP - sql

I am using this query:
SELECT p.id, count(clicks.ip)
FROM `p`
LEFT JOIN c clicks ON p.id = clicks.pid
WHERE clicks.ip = '111.222.333.444'
To select clicks from table "c", that has "pid" = "p.id". The query seems to work fine, but now I want to use that query with date ranges. The "c" table has a column "time" that uses MySQL CURRENT_TIMESTAMP data type (YYYY-MM-DD HH:MM:SS). How can I use my query with date range using that column?
I want to be able to select count(clicks.ip) from a specific day, and also group the results by hour (but this is for a different query).

Use:
SELECT p.id,
COUNT(clicks.ip)
FROM `p`
LEFT JOIN c clicks ON clicks.pid = p.id
AND clicks.ip = '111.222.333.444'
AND clicks.time BETWEEN DATE_SUB(NOW(), INTERVAL 1 DAY)
AND NOW()
I provided an example that will count clicks that occurred between this time yesterday (DATE_SUB(NOW(), INTERVAL 1 DAY)) and today (NOW()). Mind that BETWEEN is inclusive.

Related

Compare counts of two tables joined on week - SQL

I'm a newbie in SQL. I have two tables. I want to count the number of occurrences of one thing each week in the first, and of another thing each week in the second, and then compare them.
I already have the codes for counting in two separate graphs bu can't seem to be able to join them.
My first count :
select
date_part('week',Table2.date at time zone 'utc' at time zone 'Europe/Paris') as week,
count(Table2.issue_solved) as count2
from Table2
where date is not null
group by week
order by week asc
My second count
select
date_part('week',Table1.activity_date at time zone 'utc' at time zone 'Europe/Paris') as week,
count(distinct Table1.activity_id) as count1
from Table1
left join X
on Y1 = Y2
left join W
on A1 = A2
and B1 = B2
where activity_dimensions.type in ('Training')
and acquisition_opportunity_dimensions.product_family = 'EHR'
and activity_dimensions.country = 'fr'
and activity_date::date >= date_trunc('[aggregation]', [daterange_start])
and activity_date::date <= [daterange_end]
and activity_date::date <= current_date
group by week
order by count_training_meetings desc
I tried to join the first code into the second with a join on week, but I can't seem to make this work.
Any idea?
Not sure if periscope allows full join, but if you have some weeks in your first data set (query) which don't appear in the second one, and vice versa, you should use this operator in order to retrieve everything.
coalesce is intend to get the first value it recognices as not null.
In standard sql, it should be something like this
select
coalesce(q1.week, q2.week) as week,
count1,
count2
from
(
select
date_part('week',Table2.date at time zone 'utc' at time zone 'Europe/Paris') as week,
count(Table2.issue_solved) as count2
from Table2
where date is not null
group by week
) q1
full join
(
select
date_part('week',Table1.activity_date at time zone 'utc' at time zone 'Europe/Paris') as week,
count(distinct Table1.activity_id) as count1
from Table1
left join X
on Y1 = Y2
left join W
on A1 = A2
and B1 = B2
where activity_dimensions.type in ('Training')
and acquisition_opportunity_dimensions.product_family = 'EHR'
and activity_dimensions.country = 'fr'
and activity_date::date >= date_trunc('[aggregation]', [daterange_start])
and activity_date::date <= [daterange_end]
and activity_date::date <= current_date
group by week
) q2
on q1.week = q2.week
As I told you in previous comments, maybe it could be wrong to mix weeks from different years if they are present on your data, but this is just a suggestion

Redshift - Adding dates (month interval) between two dates

Using Amazon Redshift.
Also have a dates table with all calendar dates that can be utilized.
Question: How can I take a start timestamp (created_at) and end timestamp (ended_at) and add a column that adds 1 month to the start timestamp until the end timestamp.
I have a table with:
user_id,
plan_id,
created_at,
ended_at, (can be null)
So if I had a created_at timestamp of 2019-07-11, I would have a column with additional rows for 2019-08-11, 2019-09-11, 2019-10-11, etc. The goal is to associate the monthly amounts paid by a user to the dates when starting with only a start and end date.
EDIT:
I used the below query which works when an ended_at timestamp is present, however, when it is null, I need to have the next month populated until an ended_at timestamp is present.
select
ps.network_id,
ps.user_id,
ps.plan_id,
ps.created_at,
extract('day' from ps.created_at) as extract_day,
d.calendar_date,
ps.archived_at as ended_at,
ps.application_fee_percent,
pp.amount,
pp.interval,
pp.name
from payments_subscriptions ps
left outer join dates d on extract('day' from date_trunc('day',d.calendar_date)) = extract('day' from ps.created_at) AND date_trunc('day',d.calendar_date) >= date_trunc('day',ps.created_at) AND date_trunc('day',d.calendar_date) < date_trunc('day',ps.archived_at)
left outer join payments_plans pp on ps.plan_id = pp.id
where ps.network_id = '1318990'
and ps.user_id = '2343404'
order by 3,6 desc
output from above query - subscription with null ended_at needs to continue until ended_at is present
Use dateadd function for increasing time/date in timestamp
https://docs.aws.amazon.com/redshift/latest/dg/r_DATEADD_function.html
For increasing one month use this:
DATEADD(month, 1, CURRENT_TIMESTAMP)
For anyone looking for a potential solution, I ended up joining my dates table in this fashion:
LEFT OUTER JOIN dates d ON extract('day' FROM date_trunc('day',d.calendar_date)) = extract('day' FROM payments_subscriptions.created_at)
AND date_trunc('day',d.calendar_date) >= date_trunc('day',payments_subscriptions.created_at)
AND date_trunc('day',d.calendar_date) < date_trunc('day',getdate())
and this where clause:
WHERE (calendar_date < date_trunc('day',payments_subscriptions.archived_at) OR payments_subscriptions.archived_at is null)

Postgres: Return zero as default for rows where there is no matach

I am trying to get all the paid contracts from my contracts table and group them by month. I can get the data but for months where there is no new paid contract I want to get a zero instead of missing month. I have tried coalesce and generate_series but I cannot seem to get the missing row.
Here is my query:
with months as (
select generate_series(
'2019-01-01', current_date, interval '1 month'
) as series )
select date(months.series) as day, SUM(contracts.price) from months
left JOIN contracts on date(date_trunc('month', contracts.to)) = months.series
where contracts.tier='paid' and contracts.trial=false and (contracts.to is not NULL) group by day;
I want the results to look like:
|Contract Value| Month|
| 20 | 01-2020|
| 10 | 02-2020|
| 0 | 03-2020|
I can get the rows where there is a contract but cannot get the zero row.
Postgres Version 10.9
I think that you want:
with months as (
select generate_series('2019-01-01', current_date, interval '1 month' ) as series
)
select m.series as day, coalesce(sum(c.price), 0) sum_price
from months m
left join contracts c
on c.to >= m.series
and c.to < m.series + interval '1' month
and co.tier = 'paid'
and not c.trial
group by m.series;
That is:
you want the condition on the left joined table in the on clause of the join rather than in the where clause, otherwise they become mandatory, and evict rows where the left join came back empty
the filter on the date can be optimized to avoid using date functions; this makes the query SARGeable, ie the database may take advantage of an index on the date column
table aliases make the query easier to read and write
You need to move conditions to the on clause:
with months as (
select generate_series( '2019-01-01'::date, current_date, interval '1 month') as series
)
select dm.series as day, coalesce(sum(c.price), 0)
from months m left join
contracts c
on c.to >= m.series and
c.to < m.series + interval '1 month' and
c.tier = 'paid' and
c.trial = false
group by day;
Note some changes to the query:
The conditions on c that were in the where clause are in the on clause.
The date comparison uses simple data comparisons, rather than truncating to the month. This helps the optimizer and makes it easier to use an index.
Table aliases make the query easier to write and to read.
There is no need to convert day to a date. It already is.
to is a bad choice for a column name because it is reserved. However, I did not change it.

Postgres Query to get details before 2 months

I want to get the details of customers who has not visited for last two months by using postgresql. Below is my Query. I am getting all the data before 2months, but also wants to know whether the customer visits in between two months. If so, the result of query must not show that customer.
select usr.name,usr.mobile,ihv.create_date,ihv.partner_id from
invoice_header_view ihv join user_store_mapper usm on ihv.partner_id =
usm. partner_id join public.user usr on usr.user_id = usm.user_id
where usm.store_id = '123' and cast(ihv.create_date as date) =
cast(now() as date) - interval '2 month' and (cast(ihv.create_date as
date) between cast(ihv.create_date as date) and cast(now() as
date) - interval '2 months')
One of ways to solve it is NOT EXISTS. You can create a corelated subquery which will check if there are any newer rows in invoice_header_view.
Another way is to use GROUP BY, like
SELECT
usr.name, usr.mobile, ihv.partner_id,
max(ihv.create_date) AS max_create_date,
count(*) AS invoice_header_count
FROM invoice_header_view ihv
JOIN user_store_mapper usm ON ihv.partner_id = usm.partner_id
JOIN public.user usr ON usr.user_id = usm.user_id
WHERE
usm.store_id = '123'
AND ihv.create_date >= now() - interval '2 months'
GROUP BY
1,2,3
HAVING
max(ihv.create_date) <= now() - interval '2 months';
If you want customers whose most recent date is more than two months ago, then you can use:
SELECT u.name, u.mobile
FROM invoice_header_view ihv JOIN
user_store_mapper usm
ON ihv.partner_id = usm.partner_id JOIN
public.user u
ON u.user_id = usm.user_id
WHERE usm.store_id = 123 -- I'm guessing this really a number
GROUP BY u.name, u.mobile
HAVING max(ihv.create_date) <= curdate() - interval '2 months';

How to calculate an SQL MAX() for any N-second duration within a certain timeframe

I need to answer a question like this:
For each user, what is the most items that user viewed in any 60 second
time frame between START_TIMESTAMP and END_TIMESTAMP?
The 60 second time frame is a sliding window. It's not just a matter of "items viewed" counts for each whole minute. Also, 60 seconds was just an example, it should work for any number of seconds.
My data is stored like this:
-- Timestamped log of users viewing items
CREATE TABLE user_item_views (
user_id integer,
item_id integer,
timestamp timestamp
);
Doing it for each whole minute is easy enough, just format timestamp to something like YYYY-MM-DD hh:mm and do a count grouped by that formatted timestamp and the user_id.
Doing it for a sliding window, I have no idea how to approach.
If this would be easier outside of SQL, I am open to exporting the data to another format, or using another language.
Desired output is something like:
User ID Max items viewed in N seconds, between START and END.
... ...
... ...
... ...
How can I do this?
Here's how I would do it (beware, untested code, this ist just to outline the idea).
You need a helper table with as many rows as there are seconds between START_TIMESTAMP and END_TIMESTAMP. Create that as a temp table before you begin your query.
For the sake of the sample, let's call it every_second. I'm assuming your minimum time resolution is one second.
Then do:
SELECT
s.timestamp,
v.user_id,
(
SELECT COUNT(*) FROM user_item_views
WHERE timestamp BETWEEN s.timestamp AND ADDTIME(s.timestamp, '00:00:59')
AND user_id = v.user_id
) item_count
FROM
every_second s
LEFT JOIN user_item_views v ON v.timestamp = s.timestamp
GROUP BY
s.timestamp,
v.user_id
Store that in another temporary table and select the desired maxima from it (this is necessary because of the "select max from group" problem).
In MySQL (assuming that timestamp is unique):
SELECT
user_id
, MAX(max_count) AS max_count
FROM
( SELECT
a.user_id
, COUNT(*) AS max_count
FROM
user_item_views AS a
JOIN
user_item_views AS b
ON a.user_id = b.user_id
AND a.timestamp <= b.timestamp
AND b.timestamp < a.timestamp + INTERVAL 60 SECOND
GROUP BY
a.user_id
, a.timestamp
) AS grp
GROUP BY
user_id