MySQL select user who less performed an action - mysql

I have the following table structures:
ACTIONS
+ userid + action +
+----------+----------+
USERS
+ id + name +
+----------+----------+
+ 1 + james +
+----------+----------+
+ 2 + john +
+----------+----------+
A data example:
ACTIONS
+ userid + action +
+----------+----------+
+ null + action1 +
+----------+----------+
+ 1 + action2 +
+----------+----------+
+ 1 + action3 +
+----------+----------+
+ 2 + action4 +
+----------+----------+
I need a SELECT query that will return the user who performed less actions.
If all fields are null (the first launch) or all equal (all users performed the same action), it can return 1 user (rand, asc, desc, it's the same).
///////////////////
EDIT
Based on the Richard Hamilton's reply, this query only works with users already in ACTIONS table. If one or more user_id are NULL or users are not in ACTIONS, doesn't select from USERS table
SELECT id FROM users
INNER JOIN actions ON users.id = actions.user_id
GROUP BY user_id
ORDER BY COUNT(user_id)
LIMIT 1;

You'll want to use GROUP BY. We can then ORDER BY the number of actions they performed.
To find the one with the lowest number, just use LIMIT 1
SELECT user_id FROM users
INNER JOIN data ON users.id = data.users_id
GROUP BY action
ORDER BY COUNT(action)
LIMIT 1;

Related

Update columns of a table which data contains from another table mysql

I am about to update records which contain data from another table. From the given example table data below, I want to update the NULL values of company_name and domain of log table:
User Table
id | email_address
1 test#gmail.com
2 test#yahoo.com
Log table
id | user_id | company_name | domain
1 1 NULL | NULL
2 1 NULL | NULL
3 2 Yahoo | yahoo.com
4 1 Google Inc | gmail.com
Company_domain table
id | company | domain
1 | Google Inc | google.com,gmail.com,gmail.com.us
2 | Yahoo | yahoo.com,yahoomail.com
The company_name should be based on the domain of user email address. From the example log table above, the company_name of id #3 is Yahoo since the user_id=2 which is test#yahoo.com. This should also reflect on log.domain
My sql query below does not match with the company.
UPDATE user_log AS log INNER JOIN user AS u ON u.id=log.user_id
SET log.domain = (
select (SUBSTR(u.email_address, INSTR(u.email_address, '#') + 1))
),
log.company_name = (
SELECT company FROM company_domain
WHERE find_in_set(
(
SELECT (SUBSTR(log.domain, INSTR(log.domain, '#') + 1))
),
domain
)
);
Does anybody know?
I got this sql query working on my local. I notice that the domain should come from the email address since the domain from log table is null.
UPDATE user_log ul
INNER JOIN user u ON u.id = ul.user_id
SET
ul.domain = (
SELECT (SUBSTR(u.email_address, INSTR(u.email_address, '#') + 1))
),
ul.company_name = (
SELECT company FROM company_domain
WHERE FIND_IN_SET(
(
SELECT (SUBSTR(u.email_address, INSTR(u.email_address, '#') + 1))
),
domain
) LIMIT 1
);

How to order the table data with double condition order in mysql

I have table like this :
+-------------+------------+
+ my_id + name +
+-------------+------------+
+ 1 + Adam +
+-------------+------------+
+ 2 + Udin +
+-------------+------------+
+ 3 + Asep +
+-------------+------------+
+ 4 + Jarwo +
+-------------+------------+
+ 5 + Bambang +
+-------------+------------+
And then I wanna show just my data have a newest id and limit my data until 3 row, like this :
+-------------+------------+
+ my_id + name +
+-------------+------------+
+ 5 + Bambang +
+-------------+------------+
+ 4 + Jarwo +
+-------------+------------+
+ 3 + Asep +
+-------------+------------+
For the problem is I wanna order again my data into ascending by name field, and when I insert a query for order by after sorting my id by descending is not working and my data is not sorting by name, for my query code like this :
SELECT tables.my_id, tables.name
FROM tables
ORDER BY tables.my_id DESC, tables.name ASC
LIMIT 3
And for the result still same with my code when I sorting my id by descending, and my expectation like this :
+-------------+------------+
+ my_id + name +
+-------------+------------+
+ 3 + Asep +
+-------------+------------+
+ 5 + Bambang +
+-------------+------------+
+ 4 + Jarwo +
+-------------+------------+
so what's wrong with my code? Thanks before
The alias "tables" is not defined
tables.my_id + 0; Does nothing
What I understand ID is unique; So second sort will not work
SELECT * FROM (
SELECT my_id, tables.name
FROM occupants
ORDER BY my_id DESC
LIMIT 3
) t
ORDER BY t.name ASC

Translation Inner Join in JQL

I have a problem with INNER JOIN in my JQL. What I want to do is to retrieve all Users that have rate one User Z with a mean of >= 2. Users have to answer 3 questions that will determine the final rate of this User Z. There is 2 tables, User and Score.
Table User Table Score
Id_user Id_score Id_rated Id_rater Id_question Score
1 1 1 3 1 1
2 2 1 3 2 0
3 3 1 3 3 1
4 1 2 1 0
5 1 2 2 0
6 1 2 3 0
I want as a result only User 2 for example.
This is the error when I translare my query to JQL :
[32, 184] The join association path is not a valid expression.
My query works well in MySQL Workbench
SELECT *
FROM User
INNER JOIN (
SELECT ID_RATER, (AVG(Score.score)*5) as AvgScore
FROM Score
WHERE ID_RATED=1751
AND (
SELECT (AVG(Score.score) * 3)
FROM Score)
GROUP BY ID_RATER
) TabAvg
ON TabAvg.AvgScore >= 2
AND USER.ID=TabAvg.ID_RATER
Translating to JQL :
String sql =
"SELECT U "
+ "FROM User U "
+ "INNER JOIN "
+ "("
+ "SELECT S.id_rater, (AVG(S.Score) * 3) AS AvgScore "
+ "FROM Score S "
+ "WHERE S.id_rated= :id_rated"
+ "AND "
+ "("
+ "SELECT (AVG(S2.score) * 3) "
+ "FROM Score S2"
+ ") "
+ "GROUP BY S.id_rater"
+ ") TabAvg "
+ "ON TabAvg.AvgScore >= 2 "
+ "AND U.id_user = TabAvg.id_rater";
Well, I still don't know what the problem with
EntityManager.createQuery(sql)
but to bypass this, I used
EntityManager.createNativeQuery(sql)
by just copy/paste my working sql into my code.

Find two table where one table has redundant value

user_list
+---------------------+
+ user_id + name +
+---------------------+
+ 001 + Anna +
+---------------------+
+ 004 + David +
+----------------------
...
job_list
+---------------------+
+ user_id + job +
+---------------------+
+ 001 + Norse +
+---------------------+
+ 002 + Doctor +
+---------------------+
+ 003 + Sales +
+----------------------
+ 004 + Driver +
+----------------------
...
I want to find the records which job_list exists but user_list doesn't exists
For example, some user may deleted for some reason
but their record still stay in the database, so I want to find them and remove
In this case, the returning result should be 002 and 003
SELECT * FROM `user_list` ul, `job_list` jl WHERE jl.user_id NOT LIKE ul.user_id;
I tried the SQL command above but not work, please help
SELECT * FROM job_list AS jl
LEFT JOIN user_list AS ul ON ul.user_id = jl.user_id
WHERE ul.user_id IS NULL
should do the job
Try this
SELECT *
FROM `job_list` jl
WHERE NOT EXISTS (SELECT 1 FROM user_list ul WHERE ul.user_id=jl.user_Id)
If you dont care abaut know what records remove and you just whant to remove them something like this should do the trick: (warning: subquery´s are extremly inefficient)
delete from job_list where user_id not in ( select user_id from user_list)
if you whant to know the records before remove them you shuld join the tables:
SELECT * FROM job_list
LEFT JOIN user_list
ON user_list .user_id = job_list.user_id
WHERE user_list.user_id = NULL
SELECT user_id FROM job_list MINUS SELECT user_id FROM user_list;

slow count query - explain shows temp and filesort

have following query which runs slow,
It produces a list of ACTION records with "action.typeid=1"
and also counts if an ACTION record with "typeid=2" exists.
It is this count which is slowing things - it uses temporary and filesort!!!
can you help me find out how to improve.
EXPLAIN
SELECT
action.actionid
FROM
ACTION
INNER JOIN EVENT
ON action.eventid = event.eventid
LEFT JOIN
(SELECT
COUNT(1),
action.eventid
FROM
ACTION
WHERE (action.typeid = '2')
GROUP BY action.eventid) AS act
ON act.eventid = event.eventid
WHERE actiondate2 BETWEEN 20130601
AND 20131031
AND event.siteid = 1
AND action.typeid = 1
The following indexes exist
CREATE INDEX idx_cusid ON `event` (cusid);
CREATE INDEX idx_actiontypeid ON `action` (typeid);
CREATE INDEX idx_actioneventid ON `action` (eventid);
CREATE INDEX idx_actiondate ON `action` (actiondate2);
CREATE INDEX idx_eventsiteid ON `event` (siteid);
Sir, the requirements in the question are still unclear to me.
I am going to explain my confusion using examples.
Please take a look at a simple demo: http://sqlfiddle.com/#!2/19f52c/6
This demo contains a simplified (for a sake of clarity) database structure and queries.
The query from the question (the first query in the demo) returns the following results:
SELECT action.actionid
FROM ACTION
INNER JOIN EVENT
ON action.eventid = event.eventid
LEFT JOIN
(SELECT
COUNT(1),
action.eventid
FROM
ACTION
WHERE (action.typeid = '2')
GROUP BY action.eventid) AS act
ON act.eventid = event.eventid
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
event.siteid = 1
AND action.typeid = 1
;
+ ------------- +
| actionid |
+ ------------- +
| 1 |
| 3 |
| 5 |
+ ------------- +
Hovever, in the above query the subquery with alias ACT is simply ... useless.
The query executes this subquery (consuming time and server resources), then ... ignores its results, just throws them away.
The above query is equivalent to the below query (the second query in the demo) - it returns identical results as the query from the question, but without using the subquery (saving time and resources, therefore will perform much better):
SELECT action.actionid
FROM
ACTION
INNER JOIN EVENT
ON action.eventid = event.eventid
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
event.siteid = 1
AND action.typeid = 1
;
+ ------------- +
| actionid |
+ ------------- +
| 1 |
| 3 |
| 5 |
+ ------------- +
If your intent is to optimize the query show in your question - then please simply use the query shown above, this is the answer to your question.
However, looking at your comments about expected results, it appears that the query in the question is probably wrong - it doesn't give expected results.
Well, but it's still unclear what the query should give ? There are many possibilities, I'll show some of them below.
If you need to list all action.actionid with typeid = 1, but only such records, for which it exists any record with the same eventid and typeid = 2 ... then use the below query (the 3rd query in the demo):
SELECT a.actionid
FROM
ACTION a
INNER JOIN EVENT e
ON a.eventid = e.eventid
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
EXISTS ( SELECT 1 FROM action a1
WHERE a1.eventid = a.eventid
AND a1.typeid = 2
)
AND e.siteid = 1
AND a.typeid = 1
;
+ ------------- +
| actionid |
+ ------------- +
| 1 |
| 3 |
+ ------------- +
This query uses the EXISTS operator, instead of COUNT() - if we want an information that same record exist, we don't need to count all of them! The count must read all of records, the EXISTS stops reading the table if it finds the first record that meets conditions - therefore EXISTS is usually faster than COUNT().
If you need to list all action.actionid with typeid = 1,and also display an information that some corresponding records exist with typeid = 2 - then use the below query (the fourth query in the demo):
SELECT
a.actionid ,
CASE WHEN EXISTS ( SELECT 1 FROM action a1
WHERE a1.eventid = a.eventid
AND a1.typeid = 2
)
THEN 'typeid=2 EXISTS'
ELSE 'typeid=2 DOESN''T EXIST'
END typeid2_exist
FROM
ACTION a
INNER JOIN EVENT e
ON a.eventid = e.eventid
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
e.siteid = 1
AND a.typeid = 1
;
+ ------------- + ---------------------- +
| actionid | typeid2_exist |
+ ------------- + ---------------------- +
| 1 | typeid=2 EXISTS |
| 3 | typeid=2 EXISTS |
| 5 | typeid=2 DOESN'T EXIST |
+ ------------- + ---------------------- +
But if you really need to count corresponding records with typeid = 2 - then this query can help (the fifth query in the demo):
SELECT
a.actionid ,
( SELECT count(*) FROM action a1
WHERE a1.eventid = a.eventid
AND a1.typeid = 2
) typeid2_count
FROM
ACTION a
INNER JOIN EVENT e
ON a.eventid = e.eventid
WHERE -- actiondate2 BETWEEN 20130601 AND 20131031 AND
e.siteid = 1
AND a.typeid = 1
;
+ ------------- + ------------------ +
| actionid | typeid2_count |
+ ------------- + ------------------ +
| 1 | 1 |
| 3 | 1 |
| 5 | 0 |
+ ------------- + ------------------ +
If none of queries shown above meet your requirements, please show (basing on sample data in the demo) the results that the query should return - this helps someone in this forum to build a proper query that meets all your requirements.
Then, when we recognize the right query that meet all expectations, we can start to optimize it's performance.