Select rows with HAVING after a given date - mysql

Having a structure like so:
+----+------------+--------+-----------+
| id | date | userid | status |
+----+------------+--------+-----------+
| 1 | 2013-06-05 | 1 | validated |
| 2 | 2013-06-05 | 2 | validated |
| 3 | 2013-06-06 | 2 | pending |
| 4 | 2013-06-07 | 1 | validated |
| 5 | 2013-06-08 | 1 | validated |
| 6 | 2013-06-08 | 1 | validated |
| 7 | 2013-06-09 | 1 | validated |
+----+------------+--------+-----------+
If I want to select users with 5 validated statuses, I can do:
SELECT userid, COUNT(status) as valid
FROM table1
WHERE status="validated"
GROUP BY userid
HAVING valid=5
Now I want to up the complexity of this query, I want to select users that have 5 validated rows starting from a given date:
SELECT userid, COUNT(status) as valid
FROM ladder_offers_actions
WHERE status="validated"
AND date > "2013-06-06"
GROUP BY userid
HAVING valid=5
This will of course return 0 users with the example given above, this is because it's only looking at validated entries after 2013-06-06 (4).
I want to select users that only have 5 validated entries after a given date... example:
User 1 has 4 validated rows before 2013-06-06 and 1 validated row after 2013-06-06 - this user should be included in the select
User 2 has 3 validated rows before 2013-06-06 and 2 validated row after 2013-06-06 - this user should be included in the select
User 3 has 5 validated rows before 2013-06-06 - this user should not be included in the select.
User 4 has 5 validated rows after 2013-06-06 - this user should be included in the select.
Hopefully this is clear enough, essentially I only want users that that have 5 validated rows after a certain date, but include the rows before that date if the user didn't yet have 5 validated rows.

If I understand correctly what you are asking, how about using a subquery? Something like:
SELECT * from (
SELECT userid, COUNT(status) as valid, MAX(date) as lastdate
FROM ladder_offers_actions
WHERE status="validated"
GROUP BY userid
HAVING valid=5
) x WHERE x.lastdate > '2013-06-06'

Well to simplify your problem, you want to select someone if she has 5 validate and she has any validate after a certain date.
Then you can use:
SELECT userid, COUNT(status) as valid
FROM ladder_offers_actions
WHERE status="validated"
and userid in
(SELECT t2.userid
FROM ladder_offers_actions t2
WHERE t2.date > "2013-06-06")
GROUP BY userid
HAVING valid=5

Related

Sum of Counted records that calculated using "group by" with condition and "group by"

I'm sorry for fuzzy title of this question.
I have 2 Tables in my database and want to count records of first_table using "group by" on a foreign key id that exists in a column of second_table (which stores ids like array "1,2,3,4,5").
id | name | fk_id
1 | john | 1
2 | mike | 1
3 | jane | 2
4 | tailor | 1
5 | jane | 3
6 | tailor | 5
7 | jane | 4
8 | tailor | 5
9 | jane | 5
10 | tailor | 5
id | name | fk_ids | s_fk_id
1 | xxx | 1,5,6 | 1
2 | yyy | 2,3 | 1
3 | zzz | 9 | 1
4 | www | 7,8 | 1
Now i wrote the following query but it not working properly and displays wrong numbers.
I WANT TO:
1-Count records in first_table group by "fk_id"
2-Sum the counted records which exists in "fk_ids"
3-Display the sum result (sum of related counts) grouped by id.
symbol ' ' means ``.
select sum(if(FIND_IN_SET('fk_id', 'fk_ids')>0,'count',0) 'sum', 'count', 'from'.'fk_id', 'second_table'.* FROM 'second_table'
LEFT JOIN
(
SELECT 'fk_id', count(*) 'count'
FROM 'first_table'
group BY 'fk_id'
) AS 'from'
ON FIND_IN_SET('fk_id', 'fk_ids')>0
WHERE 'second_table'.'s_fk_id'=1
GROUP BY 'id'
ORDER by 'count' DESC
This table has many data and we have no plan to change the structure.
Edit:
Desired output:
id | name | sum
1 | xxx | 7 (3+4+0)
2 | yyy | 2 (1+1)
3 | zzz | 0 (0)
4 | www | 0 (0+0)
After two holidays i came back to work and found out that the "FIND_IN_SET" function is not working properly with space contained string.
And the problem is that i was ignored the spaces too, (same as this question)
Finnaly this query worked:
select sum(`count`) `sum`, `count`, `from`.`fk_id`, `second_table`.* FROM `second_table`
LEFT JOIN
(
SELECT `fk_id`, count(*) `count`
FROM `first_table`
group BY `fk_id`
) AS `from`
ON FIND_IN_SET(`fk_id`, replace(`fk_ids`,' ',''))>0
WHERE `second_table`.`s_fk_id`=1
GROUP BY `id`
ORDER by `count` DESC
And the magic is replace(fk_ids,' ','')

How to count users with where condition previous row

please help me i have no idea for this...
I have table like this (create_at YYYY-MM-DD). ID is auto increment
-----------------------------------------------------------------
| ID | id_user | activity | create_at |
-----------------------------------------------------------------
| 1 | 10 | A | 2017-10-11 |
| 2 | 52 | A | 2017-10-11 |
| 3 | 41 | A | 2017-10-12 |
| 4 | 52 | A | 2017-10-12 |
| 5 | 41 | B | 2017-10-12 |
| 6 | 52 | B | 2017-10-13 |
| 7 | 10 | B | 2017-10-14 |
-----------------------------------------------------------------
How to get count (mysql) user who doing activity "B" after activity "A" in sameday create_at.. In this case, the result is 1 (IDUser 41).. How can i do this in mysql? thankyou
We could use a semi-join or a correlated subquery.
we start like this, users that are doing activity B
SELECT t.id_user
FROM table_like_this t
WHERE t.activity = 'B'
we can match those rows to users that are doing activity A on the "same day" with JOIN operation back to the same table...
SELECT t.id_user
FROM table_like_this t
JOIN table_like_this r
ON r.id_user = t.id_user
AND r.create_at = t.create_at
AND r.activity = 'A'
WHERE t.activity = 'B'
As far as whether activity B is occurring "after" activity A, I don't see any information in the table that can tell us that (we can't tell what time each activity A and B occurred, and can't determine which one was "after" the other.)
For testing, we can include other columns in the SELECT list, to verify which rows from t and r are being returned, if the matching is being done properly.
Once we are satisfied, we can replace the SELECT list, to get a count of distinct id_user
SELECT COUNT(DISTINCT t.id_user)
FROM ...
Note that this will collapse occurrences of id_user that performed activity A and B on several different days so that the id_user will be counted only once.
If we want to count the number of days for each id_user, and include each of those days in the count, the query would need to be changed.

count amount of days user enter into db

I have a table of items similar to this:
id | desc | created | user
-----------------------------
1 | a... | 2015-05-23 | 1
2 | b... | 2015-05-23 | 1
3 | c... | 2015-06-23 | 1
4 | d... | 2015-07-23 | 2
5 | e... | 2015-07-23 | 1
I want to count the amount of days where the user submitted to the db. MY desired result from the above example would be:
User 1: 3
User 2: 1
Please try below query, I hope it helps.
select user, count(distinct date(created)) from table_name group by user;
SQLFiddle
SELECT COUNT(DISTINCT created) from items WHERE user=':user_id'
This is assuming your 'created' column only receives distinct daily values, if not, you would have to use trim functions.
select user,count(DISTINCT created) from tableName group by user;
Here is an explanation how COUNT(DISTINCT ) works.

MySQL - Selecting a weeks worth of data from week beginning date

Trying to do a select but can't seem to master the art of this particular one.
This is what I have tried:
select user_id,date,monday_am_task from users,week,timesheet_submission where user_id='1' and date='2015-04-06';
However it says it is too ambiguous. This is basically what I want to do. If the user_id=1 and the date is in between 2015-04-06 then show the data. By between and the date I mean this, I have setup a week table, this includes the week_number, week_id and date. Date is referred to as the week commencing date. So with my select statement I am trying to select the date that will pull all the data for that week, if that makes sense?
Week Table:
mysql> select * from week;
+---------+------+------------+
| week_id | week | date |
+---------+------+------------+
| 1 | 1 | 2014-12-29 |
| 2 | 2 | 2015-01-05 |
| 3 | 3 | 2015-01-12 |
| 4 | 4 | 2015-01-19 |
| 5 | 5 | 2015-01-26 |
| 6 | 6 | 2015-02-02 |
| 7 | 7 | 2015-02-09 | etc...
Users:
mysql> select user_id, username, level from users;
+---------+----------+-------+
| user_id | username | level |
+---------+----------+-------+
| 1 | tom | 1 |
| 2 | owain | 2 |
+---------+----------+-------+
2 rows in set (0.00 sec)
mysql> select user_id, date, timesheet_id, monday_am_task from timesheet_submission;
+---------+---------------------+--------------+----------------+
| user_id | date | timesheet_id | monday_am_task |
+---------+---------------------+--------------+----------------+
| 1 | 2015-04-10 12:44:54 | 34 | 5 |
+---------+---------------------+--------------+----------------+
1 row in set (0.00 sec)
This error happens when a column name exists in one or more of the selected tables. In this case, it appears to be user_id because it is in both users and timesheet_submission.
In addition, while it is all personal preference, many people prefer to use the JOIN syntax instead of listing multiple tables in the FROM clause. The second option creates a Cartesian product, which is what you are experiencing, and unless you set the proper conditions to relate a table, you can get very odd results like the ones you have now.
In short, the join syntax may look like this:
SELECT [columns]
FROM table1 t1
JOIN table2 t2 ON t2.relatedColumn = t1.relatedColumn;
For your tables, you can join users to timesheet_submission, and timesheet_submission to week, although that one is tricky because there is no direct link. To break my answer down a bit, I would start by getting all timesheet submissions for user_id 1 with a join like this:
SELECT u.user_id, ts.date, ts.monday_am_task
FROM users u
JOIN timesheet_submission ts ON ts.user_id = u.user_id AND u.user_id = 1;
Don't forget to use the table alias in select, or you'll get the ambiguity error again. As far as the date, if I were writing this query I would just include the condition that the timesheet date is between your given date, and six days later [since between is inclusive, if you go seven days later you will get the next date as well]. Try this:
SELECT u.user_id, ts.date, ts.monday_am_task
FROM users u
JOIN timesheet_submission ts ON ts.user_id = u.user_id AND u.user_id = 1
WHERE ts.date BETWEEN '2015-04-06' AND DATE_ADD('2015-04-06', INTERVAL 6 DAY);
Here is more on JOINS and on the DATE_ADD function.

Retrieving the most recent entry per user

If I have a table with the following structure and data:
id | user_id | created_at
-------------------------
1 | 7 | 0091942
2 | 3 | 0000014
3 | 6 | 0000890
4 | 6 | 0029249
5 | 7 | 0000049
6 | 3 | 0005440
7 | 9 | 0010108
What query would I use to get the following results (explanation to follow):
id | user_id | created_at
-------------------------
1 | 7 | 0091942
6 | 3 | 0005440
4 | 6 | 0029249
7 | 9 | 0010108
As you can see:
Only one row per user_id is returned.
The row with the highest created_at is the one returned.
Is there a way to accomplish this without using subqueries? Is there a name in relational algebra parlance that this procedure goes by?
The query is known as a groupwise maximum, which (in MySQL, at least) can be implemented with a subquery. For example:
SELECT my_table.* FROM my_table NATURAL JOIN (
SELECT user_id, MAX(created_at) created_at
FROM my_table
GROUP BY user_id
) t
See it on sqlfiddle.
You can just get the max and group by the user_id:
select id,user_id,max(created_at)
from supportContacts
group by user_id
order by id;
Here is what it outputs:
ID USER_ID MAX(CREATED_AT)
1 7 91942
2 3 5440
3 6 29249
7 9 10108
See the working demo here
Note that the example on the fiddle uses the created_at field as int, just use your format it should make no difference.
EDIT: I will leave this answer as a referece but note that his query will produce undesired results as Gordon stated, please do not use this in production.