Non repeating monthly SQL - mysql

I have a query in which I would like to return the number of users who have logged in for the month without repeating the record in the next month.
If a user has logged in April and May, it only shows one record for April. This is what I have so far.
SELECT DISTINCT (a.userid), EXTRACT(MONTH FROM a.loginTime) as month
FROM login_audit a LEFT JOIN user u on u.userid = a.userid
WHERE a.loginTime <= '2012-12-31 11:59:59'
AND a.loginTime >= '2012-01-01 00:00:00'
GROUP BY month
So far the records are returning
userid month
1 1
2 1
1 2
3 2
In this scenario, user 1 is coming up for both January and Februray. I would like it to ommit that record. Either that or have it accumulated. Like so:
Either
userid month
1 1
2 1
3 2
Or
userid month
1 1
2 1
1 2
2 2
3 2
I hope this made sense. Please ask me anything if you'd like any further clarifications. Thanks a lot!

Don't see where you need table user...
For first "wanted scenario" :
SELECT
a.userid,
MIN(EXTRACT(MONTH FROM a.loginTime)) as month
FROM login_audit a
WHERE a.loginTime <= '2012-12-31 11:59:59' AND a.loginTime >= '2012-01-01 00:00:00'
GROUP BY a.userid

I would use this approach.
SELECT DISTINCT (a.userid), EXTRACT(MONTH FROM a.loginTime) as month
FROM login_audit a
WHERE a.loginTime <= '2012-12-31 11:59:59'
AND a.loginTime >= '2012-01-01 00:00:00'
and not exists
(select userid
from login_audit
where login_audit.user_id = a.user_id
and carry on with date range for the following month
)

Related

how to get pending months from due entries using mysql

I have the entries of monthly dues like,
Table name : month_dues,
Columns:
customer_id,
due_date,
due_amount
These table have lot of due entries.
customer_id due_date due_amount
--------------------------------------
1 2018-12-01 100
1 2019-01-01 100
1 2019-02-01 100
1 2019-10-01 100
so, how to select pending due months from these record?
in my table customer 1 not paid dues for these months,
2019-03,2019-04,2019-05,2019-06,2019-07,2019-08, 2019-09
customer pay the due every month so
For select paid dues from table using,
SELECT customer_id, due_date, due_amount FROM month_dues where customer_id='1' where due_date>='2019-01-01' and due_date<='2019-10-18';
How to get pending due month and year using this table?
Which means, find month and year not in this record.
IF you are searching between the two dates
YOu can use this
select * from month_dues
where due_date between '2012-03-11 00:00:00' and '2012-05-11
23:59:00' && customer_id='1'
order by month_dues desc;
If you want to search the date(due_date) lower than today
SELECT * FROM month_dues WHERE due_date < CURDATE();
And you are refeering to the record that is not belong to the query you can find some NOT IN query
Like
`SELECT * FROM month_dues NOT IN ( select * from month_dues
where due_date between '2012-03-11 00:00:00' and '2012-05-11
23:59:00' && customer_id='1'
order by month_dues desc;
)`
So basically you need to validate your table against some kind of calendar, here is a simple solution that only works for the current year, maybe you can use it as a start or someone else could improve it
SELECT m.MONTH
FROM (SELECT 1 AS MONTH
UNION SELECT 2 AS MONTH
UNION SELECT 3 AS MONTH
UNION SELECT 4 AS MONTH
UNION SELECT 5 AS MONTH
UNION SELECT 6 AS MONTH
UNION SELECT 7 AS MONTH
UNION SELECT 8 AS MONTH
UNION SELECT 9 AS MONTH
UNION SELECT 10 AS MONTH
UNION SELECT 11 AS MONTH
UNION SELECT 12 AS MONTH) as m
WHERE m.MONTH NOT IN (SELECT MONTH(due_date)
FROM due_months
WHERE customer_id = 1
AND YEAR(due_date) = YEAR(CURDATE()))
AND m.MONTH < MONTH(CURDATE()) -- needs to be improved as well

MySQL Get Orders From Last 12 Weeks Monday to Sunday

I have a table that stores each order made by a user, recording the date it was made , the amount and the user id. I am trying to create a query that returns the weekly transactions from Monday to Sunday for the last 12 weeks for a particular user. I am using the following query:
SELECT COUNT(*) AS Orders,
SUM(amount) AS Total,
DATE_FORMAT(transaction_date,'%m/%Y') AS Week
FROM shop_orders
WHERE user_id = 123
AND transaction_date >= now()-interval 3 month
GROUP BY YEAR(transaction_date), WEEKOFYEAR(transaction_date)
ORDER BY DATE_FORMAT(transaction_date,'%m/%Y') ASC
This produces the following result:
This however does not return the weeks where the user has made 0 orders, does not sum the orders from Monday to Sunday and does not return the weeks ordered from 1 to 12. Is there a way to achieve these things?
One way to accomplish this is with an self outer join (in this case, I use a right outer join, but of course a left outer join would work as well).
To start your weeks on Monday, subtract the result of WEEKDAY from your column transaction_date with DATE_SUB, as proposed in the most upvoted answer here.
SELECT
COALESCE(t1.Orders, 0) AS `Orders`,
COALESCE(t1.Total, 0) AS `Total`,
t2.Week AS `Week`
FROM
(
SELECT
COUNT(*) AS `Orders`,
SUM(amount) AS `Total`,
DATE(DATE_SUB(transaction_date, INTERVAL(WEEKDAY(transaction_date)) DAY)) AS `Week`
FROM
shop_orders
WHERE 1=1
AND user_id = 123
AND transaction_date >= NOW() - INTERVAL 12 WEEK
GROUP BY
3
) t1 RIGHT JOIN (
SELECT
DATE(DATE_SUB(transaction_date, INTERVAL(WEEKDAY(transaction_date)) DAY)) AS `Week`
FROM
shop_orders
WHERE
transaction_date >= NOW() - INTERVAL 12 WEEK
GROUP BY
1
ORDER BY
1
) t2 USING (Week)
To return the weeks with no Orders you have to create a table with all the weeks.
For the order order by the same fields in the group by

mysql query on case when or data between specified date

for each relationship manager display all the customer and their total orders,who ordered more than 5 times in the last week or more than 10 times in the last 14 days,there are two tables
1.orders[date,rel. manager],
2.customer[cid,cname].
I am trying like this, thanks.
select o.RelationshipManager,c.Name,count(*) total_orders
case
when o.OrderedDate >curdate() -interval 7 day then count(*)
else
o.OrderedDate >curdate() -interval 14 day then count(*)
end
from customer c
join orders o on c.customerid=o.customerid;
SELECT o.RelationshipManager, c.Name
, COUNT(*) total_orders
, COUNT(CASE WHEN o.OrderedDate > curdate() - INTERVAL 7 DAY THEN 1 ELSE NULL END) AS oneWeekCount
, COUNT(CASE WHEN o.OrderedDate > curdate() - INTERVAL 14 DAY THEN 1 ELSE NULL END) AS twoWeekCount
FROM customer AS c
JOIN orders AS o ON c.customerid=o.customerid
-- WHERE o.OrderedDate > curdate() - INTERVAL 14 DAY
GROUP BY o.RelationshipManager, c.Name
HAVING oneWeekCount > 5 OR twoWeekCount > 10
;
COUNT only counts non-null values, the WHERE is optional but changes the results (it should reduce the number of records inspected, but makes total_orders the same as twoWeekCount); the HAVING filters the results after the aggregation/counting has been performed.
In my experience, it is very rare for an aggregate function to be appropriate inside a conditional; I'm not even 100% sure there is an appropriate scenario for such use.

Count number of entries in time interval 1 that appear in time interval 2 - SQL

I am new here and tried to look up the answer to my question but couldn't find anything on it. I am currently learning how to work with SQL queries and am wondering how I can count the amount of unique values that appear in two time intervals?
I have two columns; one is the timestamp while the other is a customer id. What I want to do is to check, for example, the amount of customers that appear in time interval A, let's say January 2014 - February 2014. I then want to see how many of these also appear in another time interval that i specify, for example February 2014-April 2014. If the total sample were 2 people who both bought something in january while only one of them bought something else before the end of April, the count would be 1.
I am a total beginner and tried the query below but it obviously won't return what I want because each entry only having one timestamp makes it not possible to be in two intervals.
SELECT
count(customer_id)
FROM db.table
WHERE time >= date('2014-01-01 00:00:00')
AND time < date('2014-02-01 00:00:00')
AND time >= date('2014-02-01 00:00:00')
AND time < date('2014-05-01 00:00:00')
;
Try this.
select count(distinct t.customer_id) from Table t
INNER JOIN Table t1 on t1.customer_id = t.customer_id
and t1.time >= '2014-01-01 00:00:00' and t1.time<'2014-02-01 00:00:00'
where t.time >='2014-02-01 00:00:00' and t.time<'2014-05-01 00:00:00'
Here's one method of doing this with conditional grouping in an inner-select.
Select Case
When GroupBy = 1 Then 'January - February 2014'
When GroupBy = 2 Then 'February - April 2014'
End As Period,
Count (Customer_Id) As Total
From
(
SELECT Customer_Id,
Case
When Time Between '2014-01-01' And '2014-02-01' Then 1
When Time Between '2014-02-01' And '2014-04-01' Then 2
Else -1
End As GroupBy
From db.Table
) D
Where GroupBy <> -1
Group By GroupBy
Edit: Sorry, misread the question. This will show you those that overlap those two time ranges:
Select Count(Customer_Id)
From db.Table t1
Where Exists
(
Select Customer_Id
From db.Table t2
Where t1.customer_id = t2.customer_id
And t2.Time Between '2014-02-01' And '2014-04-01'
)
And t1.Time Between '2014-01-01' And '2014-02-01'

Return a zero for a day with no results

I have a query which returns the total of users who registered for each day. Problem is if a day had no one register it doesn't return any value, it just skips it. I would rather it returned zero
this is my query so far
SELECT count(*) total FROM users WHERE created_at < NOW() AND created_at >
DATE_SUB(NOW(), INTERVAL 7 DAY) AND owner_id = ? GROUP BY DAY(created_at)
ORDER BY created_at DESC
Edit
i grouped the data so i would get a count for each day- As for the date range, i wanted the total users registered for the previous seven days
A variation on the theme "build your on 7 day calendar inline":
SELECT D, count(created_at) AS total FROM
(SELECT DATE_SUB(NOW(), INTERVAL D DAY) AS D
FROM
(SELECT 0 as D
UNION SELECT 1
UNION SELECT 2
UNION SELECT 3
UNION SELECT 4
UNION SELECT 5
UNION SELECT 6
) AS D
) AS D
LEFT JOIN users ON date(created_at) = date(D)
WHERE owner_id = ? or owner_id is null
GROUP BY D
ORDER BY D DESC
I don't have your table structure at hand, so that would need adjustment probably. In the same order of idea, you will see I use NOW() as a reference date. But that's easily adjustable. Anyway that's the spirit...
See for a live demo http://sqlfiddle.com/#!2/ab5cf/11
If you had a table that held all of your days you could do a left join from there to your users table.
SELECT SUM(CASE WHEN U.Id IS NOT NULL THEN 1 ELSE 0 END)
FROM DimDate D
LEFT JOIN Users U ON CONVERT(DATE,U.Created_at) = D.DateValue
WHERE YourCriteria
GROUP BY YourGroupBy
The tricky bit is that you group by the date field in your data, which might have 'holes' in it, and thus miss records for that date.
A way to solve it is by filling a table with all dates for the past 10 and next 100 years or so, and to (outer)join that to your data. Then you will have one record for each day (or week or whatever) for sure.
I had to do this only for MS SqlServer, so how to fill a date table (or perhaps you can do it dynamically) is for someone else to answer.
A bit long winded, but I think this will work...
SELECT count(users.created_at) total FROM
(SELECT DATE_SUB(CURDATE(),INTERVAL 6 DAY) as cdate UNION ALL
SELECT DATE_SUB(CURDATE(),INTERVAL 5 DAY) UNION ALL
SELECT DATE_SUB(CURDATE(),INTERVAL 4 DAY) UNION ALL
SELECT DATE_SUB(CURDATE(),INTERVAL 3 DAY) UNION ALL
SELECT DATE_SUB(CURDATE(),INTERVAL 2 DAY) UNION ALL
SELECT DATE_SUB(CURDATE(),INTERVAL 1 DAY) UNION ALL
SELECT CURDATE()) t1 left join users
ON date(created_at)=t1.cdate
WHERE owner_id = ? or owner_id is null
GROUP BY t1.cdate
ORDER BY t1.cdate DESC
It differs from your query slightly in that it works on dates rather than date times which your query is doing. From your description I have assumed you mean to use whole days and therefore have used dates.