I'm know this can be written as a single SQL statement, but I just don't know how to do it. I have two separate queries. Ont that pulls all orders from a specific period of last year
SELECT * FROM `order` WHERE date_added BETWEEN '2014-10-01' AND '2014-11-01';
and one that pulls from the last month
SELECT * FROM `order` WHERE date_added BETWEEN DATE_SUB( now(), INTERVAL 1 MONTH) AND Now() ORDER BY date_added ASC
What I want to do is now join the two so that I only get the customer_id of orders that were placed inside of the date range last year (query 1), but haven't placed an order in the last month (query 2).
I know there is a way to set this up as a join, but my knowledge on sql join's is not very limited. Thanks for any help.
http://sqlfiddle.com/#!9/35ed0/1
SELECT * FROM `order`
WHERE date_added BETWEEN '2014-10-01' AND '2014-11-01'
AND customer_id NOT IN (
SELECT DISTINCT customer_id FROM `order`
WHERE date_added BETWEEN DATE_SUB( now(), INTERVAL 1 MONTH) AND Now())
UPDATE If you need only 1 records per customer_id, here is an example . It is not very best from performance perspective. But it returns only last (according to the date_added column) order per customer.
SELECT t.*,
if(#fltr=customer_id, 0, 1) fltr,
#fltr:=customer_id
FROM (SELECT *
FROM `order`
WHERE date_added BETWEEN '2014-10-01' AND '2014-11-01'
AND customer_id NOT IN (
SELECT DISTINCT customer_id FROM `order`
WHERE date_added BETWEEN DATE_SUB( now(), INTERVAL 1 MONTH) AND Now())
ORDER BY customer_id, date_added DESC
) t
HAVING (fltr=1);
I usually use a correlated not exists predicate for this as I feel that it corresponds well with the intent of the question:
SELECT *
FROM `order` o1
WHERE date_added BETWEEN '2014-10-01' AND '2014-11-01'
AND NOT EXISTS (
SELECT 1
FROM `order` o2
WHERE date_added BETWEEN DATE_SUB(NOW(), INTERVAL 1 MONTH) AND NOW()
AND o1.customer_id = o2.customer_id
);
I like to approach these questions using group by and having. You are looking for customer ids, so:
select o.customer_id
from orders o
group by o.customer_id
having sum(date_added BETWEEN '2014-10-01' AND '2014-11-01') > 0 and
sum(date_added BETWEEN DATE_SUB( now(), INTERVAL 1 MONTH) AND Now()) = 0;
Related
SELECT COUNT(order_id) AS xAxis,
WEEK(created_at) AS yAxis
FROM orders WHERE created_at >= startDate
AND created_at <= endDate GROUP BY WEEK(created_at);
Try just using MIN and MAX:
SELECT
COUNT(order_id) AS xAxis,
WEEK(created_at) AS yAxis,
MIN(created_at) AS week_start,
MAX(created_at) AS week_end
FROM orders
WHERE
created_at BETWEEN startDate AND endDate
GROUP BY
WEEK(created_at);
The reasoning here is simple: the start of each week group of records should be the smallest date and vice-versa for the max.
Should your data not cover every day in the range, then you can join to a calendar table to bring in the missing dates. The updated query would now look something like:
SELECT
COUNT(o.order_id) AS xAxis,
WEEK(t.dt) AS yAxis,
MIN(t.dt) AS week_start,
MAX(t.dt) AS week_end
FROM
(
SELECT '2020-01-01' AS dt UNION ALL
SELECT '2020-01-02' UNION ALL
...
SELECT '2020-12-31'
) t
LEFT JOIN orders o
ON t.dt = o.created_at
WHERE
o.created_at BETWEEN startDate AND endDate
GROUP BY
WEEK(t.dt);
See here for more information on generating date tables in MySQL.
I have a mySQL table, which holds:
CustomerId and OrderDate
There can me multiple rows for one CustomerId
Now, I try to get the CustomerId's where only the last OrderDate is older than a year.
I try the following:
SELECT *
FROM order
WHERE OrderDate <=DATE_SUB(now(), Interval 1 Year)
GROUP BY CustomerId
ORDER BY OrderDate DESCC;
The problem here is, that I get all the rows, which are older then 1 year.
But as I said above, I try to get only the latest order, which is older than 1 year.
THX for any advise
Order the rows and limit to the last. Also, you had DESCC instead of DESC.
SELECT *
FROM order
WHERE OrderDate <=DATE_SUB(now(), Interval 1 Year)
GROUP BY CustomerId
ORDER BY OrderDate DESC
LIMIT 1;
You might also try this query:
SELECT
`CustomerId`,
`CustomerName`, // Add other fields you want returned.
MAX(`OrderDate`)
FROM `order`
WHERE `OrderDate` <= DATE_SUB(now(), Interval 1 Year)
GROUP BY `CustomerId`
ORDER BY MAX(`OrderDate`) DESC;
Also, this will return all of the related columns in the last order for each customer:
SELECT *
FROM `order` a
JOIN (
SELECT
`CustomerId`,
MAX(`OrderDate`) as `maxdate`
FROM `order`
WHERE `OrderDate` <= DATE_SUB(now(), Interval 1 Year)
GROUP BY `CustomerId`) b
ON a.`CustomerId` = b.`CustomerId` AND
a.`OrderDate` = b.`maxdate`
ORDER BY `maxdate` DESC;
Try this subquery:
select customer_id
from customer table
where order_id in(Select order_id from (select order_id from order_table (year(now())-year(order_date)) = 1 order by order_date desc limit 1))
if it doesn't work please post your table structure.
THX for all your tips.
At the end, I found my working solution:
SELECT
*
FROM order a1
INNER JOIN (SELECT
order.Id
FROM (SELECT
*
FROM (SELECT
*
FROM order
WHERE OrderDate <= DATE_SUB(NOW(), INTERVAL 1 year)
ORDER BY OrderDate DESC) AS Sub
GROUP BY Sub.CustomerId) AS a2) AS a3
ON a1.id = a3.id;
I'm trying to do a query that fetches data per the last hour and the two last hours. It's just a hits counter.
So I would like to get the resultset as follows:
id, page_url, last_hour_hits, two_last_hours_hits
The table is very simple:
id (autonumber)
page_url
time_stamp
I tried the query below:
SELECT
page_url,
COUNT(page_url) AS last_hour_hits
FROM stats
WHERE time_stamp > '2015-08-01 00:00:00'
GROUP BY page_url
('2015-08-01 00:00:00' is calculated for the last hour)
It works fine, but I have now idea how to add the 'two_last_hours' counter.
Thank you in advance.
With MySQL you can use the fact that boolean expression returns 1 for true and simplify the query to this:
SELECT
page_url
,sum(time_stamp > (now() - interval 1 hour)) as last_hour_hits
,sum(time_stamp > (now() - interval 2 hour)) as two_last_hours_hits
FROM stats
GROUP BY page_url;
This uses now() to get the current time and subtracts the interval as needed.
Just put your WHERE clause with two hours before ('2015-07-31 23:00:00') and a CASE WHEN to count for the last hour ('2015-08-01 00:00:00') :
SELECT
page_url,
COUNT(DISTINCT CASE WHEN time_stamp > '2015-08-01 00:00:00' THEN id ELSE NULL END) as last_hour_hits
COUNT(*) AS two_last_hours_hits
FROM stats
WHERE time_stamp > '2015-07-31 23:00:00'
GROUP BY page_url;
you can use join between two result sets- one for the one hour and the other for the two hours:
SELECT stats.page_url, last_hour_hits, last_two_hours_hits from
stats inner join (
SELECT page_url, COUNT(page_url) AS last_hour_hits
FROM stats WHERE time_stamp > '2015-08-01 00:00:00'
GROUP BY page_url ) as last_hour
on stats.page_url = last_hour.page_url
inner join (
SELECT page_url, COUNT(page_url) AS last_two_hours_hits
FROM stats WHERE time_stamp > '2015-07-31 23:00:00'
GROUP BY page_url ) as last_two_hours
on stats.page_url = last_two_hours.page_url
I am looking to get the first and last record for a given user_id in a time period, for example, 24 hours.
I am aware this could be done using two queries, doing something like this and then switching the ORDER BY ASC/DESC.
SELECT id, user_id, date, other_columns
FROM table
WHERE user_id = 1 AND date > DATE_SUB(CURDATE(), INTERVAL 24 HOUR)
ORDER BY date DESC
LIMIT 1
However, I am wondering if it would be possible to do this using one query.
This is something that you could consider:
SELECT t.id, t.user_id, t.date, t.other_columns
FROM table t
WHERE user_id = 1
AND date = (
SELECT MIN(date)
FROM table
WHERE user_id = t.user_id
AND date > DATE_SUB(CURDATE(), INTERVAL 24 HOUR))
UNION ALL
SELECT id, user_id, date, other_columns
FROM table
WHERE user_id = 1
AND date = (
SELECT MAX(date)
FROM table
WHERE user_id = t.user_id
AND date > DATE_SUB(CURDATE(), INTERVAL 24 HOUR))
I'm trying to collect the number of distinct visits in my cp yesterday, then count them.
SELECT
DISTINCT `user_id` as user,
`site_id` as site,
`ts` as time
FROM
`cp_visits`
WHERE
ts >= DATE_SUB(NOW(), INTERVAL 1 DAY)
For some reason this is pulling multiple results with the same site id....how do i only pull and count the distinct site_id cp logins?
Select
Count(Distinct user_id) As countUsers
, Count(site_id) As countVisits
, site_id As site
From cp_visits
Where ts >= DATE_SUB(NOW(), INTERVAL 1 DAY)
Group By site_id
Overall
SELECT
COUNT(DISTINCT `site_id`) as distinct_sites
FROM `cp_visits`
WHERE ts >= DATE_SUB(NOW(), INTERVAL 1 DAY)
Or per site
SELECT
`site_id` as site,
COUNT(DISTINCT `user_id`) as distinct_users_per_site
FROM `cp_visits`
WHERE ts >= DATE_SUB(NOW(), INTERVAL 1 DAY)
GROUP BY `site_id`
Having the time column in the result doesn't make sense - since you are aggregating the rows, showing one particular time is irrelevant, unless it is the min or max you are after.
You need to use a group by clause.
SELECT site_id, MAX(ts) as TIME, count(*) group by site_id