I have a table, described like so:
Table1
id (int),
link (varchar512),
text (varchar80),
status (varchar10),
created (timestamp),
updated (timestamp),
user (varchar)
What I need to do is get the total count of rows per user between two timestamps.
So, for example, let's say I want to get the total number of rows for users in the database. That is just a simple
SELECT user, COUNT(*) FROM table_name GROUP BY user;
If I want to get all the rows, for say October, I can do:
SELECT * FROM table_name WHERE created > "2016-10-01 00:00:00" and created < "2016-11-31 23:59:59"
My problem, is I cannot combine the two. I try, and I get syntax errors. I think that I need to run the where query, and then do a count based on that, but I'm not sure how do to that.
Hope this helps.
SELECT user, count(*)
FROM table_name
WHERE created > "2016-10-01 00:00:00" and created < "2016-11-31 23:59:59"
GROUP BY user;
SELECT user, COUNT(*)
FROM table_name
WHERE created >= '2016-10-01'
and created < '2016-12-01'
GROUP BY user;
BTW there is no date 2016-11-31 since November has only 30 days.
Related
I have rows of user data. I store the createDate, which is the timestamp in milliseconds when the user registered. I want to get the total number of registrations per month. When I try to do that, I don't get any rows returned. Here's the query I'm using
SELECT COUNT(*) FROM users WHERE YEAR(createDate) = 2023 GROUP BY MONTH(createDate)
createDate is BIGINT and is the date in milliseconds
I guess your createDate column is defined as TIMESTAMP(3), to get millisecond resolution. LAST_DAY() comes in handy here.
Try this:
SELECT COUNT(*), LAST_DAY(createDate) month_ending
FROM users
WHERE createDate >= '2023-01-01'
AND createDate < '2024-01-01'
GROUP BY LAST_DAY(createDate)
The date range test I use for getting the dates in a single year is sargable. That is, it can be accelerated by an index on createDate, where YEAR(createDate) cannot be.
This approach generates a useful result set if you run it on a multi-year date range.
But, if your result set is empty (has no rows), the result set from this query will be too. That might mean:
your table has no dates in that range, or
your createDate data type is something other than TIMESTAMP or DATETIME. (You didn't show us the table definition.)
It sounds like you need to convert to/from unix time:
SELECT COUNT(*), LAST_DAY(FROM_UNIXTIME(createDate/1000)) month_ending
FROM users
WHERE createDate >= UNIX_TIMESTAMP('2023-01-01') * 1000
AND createDate < UNIX_TIMESTAMP('2024-01-01') * 1000
GROUP BY month_ending
I have a table with every login by all users.
I want to run a query that will pull the number of times each user logs in but limit it to 4 if the user logged in more than 4 times on a day.
And then do a sum to get the total number of logins.
Further to this I want to pull back the time frame for the total number of logins. So I specify the total number of logins as 100 then the query must pull back the earliest date, going back from today and counting the number of logins (limited at 4 if above 4) per user.
My query so far to get the list of totals limited to 4 per user:
SELECT (case when (count(l.user_id) > 4) then 4 else count(l.user_id) end) as cappedcount
FROM `logins` l
where l.store_id = 908
and l.login_dt > '2018-04-17 00:00:00' and l.login_dt < '2018-04-18 23:59:59'
group by l.user_id order by cappedcount desc
I'm specifying the date range at the moment but don't want to do that in the final query.
If I understand correctly, you only want to look at the last four logins per user and day and ignore their earlier logins. From this set you want the last 100 logins.
So the first task is to get the four last logins per user and day, which would usually be solved with window functions, but MySQL doesn't feature them. So count in a subquery instead (which may take long):
select *
from logins
where
(
select count(*)
from logins later
where later.user_id = logins.user_id
and date(later.login_dt) = date(logins.login_dt)
and later.login_dt > logins.login_dt
) < 4
order by login_dt desc
limit 100;
I suggest to provide the following index for this query:
create index idx_logins on logins (user_id, login_dt);
What is the version of MySQL you user? Because as far as I know with clause is only supported in recent versions of MySQL.
I believe the answer to your first request is something like :
select sum(cntx) from (
select user_id, date(login_time), least(count(*), 4) cntx
from logins
where login_time between '2018-04-10 00:00:00' and '2018-04-17 00:00:00'
group by user_id, date(login_time)
) x
as you can view it in sqlfiddle.com.
For your second question, I have following answer, I believe it's not the best solution, but it works on MySQL 5.6. In next MySQL version (MySQL 8) you can use with clause which provides better solution for this question. I use views in the solution to skip duplicate queries:
create view xlogins as
select user_id, date(login_time) xdt, least(count(*), 4) xcnt
from logins
group by user_id, date(login_time);
create view xxlogins as
select distinct xdt, (select sum(x2.xcnt)
from xlogins x2
where x2.xdt >= x1.xdt) sumx
from xlogins x1;
select min(x1.xdt)
from xxlogins x1
join xxlogins x2 on x1.xdt < x2.xd
where x1.sumx >= 100
and x2.sumx <= 100
Find the solution in this sqlfiddle.com, I've just changed the 100 to 10.
I need a way to show the rows ordered by date ( ascending ) but with the date from now. I am using this query:
SELECT * FROM status
ORDER BY YEAR(datestart), MONTH(datestart), DAY(datestart) ASC
but it still shows the rows older than today.
This is the database structure:
id, status, datestart
database:
0,blabla,2015-02-12 16:15:12
1,blabla,2017-02-12 16:15:12
2,blabla,2016-08-11 19:13:22
4,blabla,2016-01-27 11:12:02
5,blabla,2016-07-21 18:12:02
6,blabla,2018-03-22 13:35:22
8,blabla,2016-08-15 17:12:32
expected results:
5,blabla,2016-07-21 18:12:02
2,blabla,2016-08-11 19:13:22
8,blabla,2016-08-15 17:12:32
1,blabla,2017-02-12 16:15:12
5,blabla,2018-03-22 13:35:22
You can simply add a WHERE clause:
SELECT * FROM status WHERE datestart > now()
ORDER BY YEAR(datestart), MONTH(datestart), DAY(datestart) ASC
I have a login_log table:
And I'm trying to build a query grouped "unique" logins baseed on login_email, login_success, login_email, account_type_id, login_lock, login_ip
So so far I have
SELECT count(*) count, MAX(login_date) date, login_ip, login_email, account_type_id, login_lock, login_success
FROM `login_log`
GROUP BY login_email, login_success, login_email, account_type_id, login_lock, login_ip
ORDER BY date DESC
Which gets me:
But take row 5 and 6 for example. On 6 the user failed the login 3 times before a successful one on row 5. Row 5's count should read 1 but it's grouping successful logins previous to the failed attempts.
What I want is one row with the successful login, a row with the failed login, then a row with a successful login, ordered by date.
How can I group the date query so that they don't "jump" each other?
The problem with your query is that you don't group by Date in the Group By section. As a result, your Count(*) increments unnecessarily.
Adding:
Group By Date
will work but might not give you the correct interval. Adding the MySQL Date() function would allow you to split it up by day, so you would add:
Group By Date(Date)
You also might want to change your alias Date to a non reserved MySQL keyword, like LogDate or something similar.
More on the MySQL Date/Time functions:
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html
I'm not sure if this is even within the scope of MySQL to be honest or if some php is necessary here to parse the data. But if it is... some kind of stored procedure is likely necessary.
I have a table that stores rows with a timestamp and an amount.
My query is dynamic and will be searching based on a user-provided date range. I would like to retrieve the SUM() of the amounts for each day in a table that are between the date range. including a 0 if there are no entries for a given day
Something to the effect of...
SELECT
CASE
WHEN //there are entries present at a given date
THEN SUM(amount)
ELSE 0
END AS amountTotal,
//somehow select the day
FROM thisTableName T
WHERE T.timeStamp BETWEEN '$start' AND '$end'
GROUP BY //however I select the day
This is a two parter...
is there a way to select a section of a returned column? Like some kind of regex within mysql?
Is there a way to return the 0's for dates with no rows?
select * from thisTableName group by date(created_at);
In your case, it would be more like
SELECT id, count(id) as amountTotal
FROM thisTableName
WHERE timeStamp BETWEEN '$start' AND '$end'
GROUP BY DATE(timeStamp);
Your question is a duplicate so far: link.