SQL Query, cannot find the right query - php

I'm hosting a platform where users get SQL logs, I want to make some kind of highscore for it so there like a top 10 of users who got the most logs.
All registered users get their own 'ID', in the logs the user 'ID' is displayed as: 'id'. So in users 'ID' is in capitals and in 'logs' it is without capitals.
I would like to have some kind of query like this:
SELECT username,ID FROM users ORDER BY COUNT (id) FROM logs LIMIT 10;
But this does not work so maybe someone of you have a solution?

Try this, you'll need to join the table and use the group function, really useful for what you're trying to achieve:
SELECT users.username, users.id
FROM users
LEFT JOIN logs on users.id = logs.id
GROUP BY users.id
ORDER BY COUNT (logs.id)
LIMIT 10;
Or try with aliases:
SELECT users.username as u, users.id as i
FROM users
LEFT JOIN logs on users.id = logs.id
GROUP BY i
ORDER BY COUNT (logs.id)
LIMIT 10;
Try this to achieve the log count:
SELECT users.username, users.id, COUNT(logs.id) as quantity
FROM users
LEFT JOIN logs on users.id = logs.id
GROUP BY users.id
ORDER BY COUNT(logs.id)
LIMIT 10;

Simple Inner Join should work
SELECT U.username,U.ID
FROM users U
INNER JOIN logs L
on U.id = L.id
Group by U.username,U.ID
ORDER BY COUNT (id) FROM LIMIT 10

SELECT User.username, User.ID, Count(Log.id) LogCount
FROM users User
LEFT JOIN logs Log
ON User.ID = Log.id
GROUP BY User.ID, User.username
ORDER BY LogCount DESC
LIMIT 10

Related

EXISTS query optimization on mysql query

I have a big data problem with MySQL.
I have:
a users table with 59033 rows, and
a user_notes table with 8753 rows.
But when I search which users have user note in some dates.
My query like this :
SELECT u.*, rep.name as rep_name FROM users as u
LEFT JOIN users as rep on rep.id = u.add_user
LEFT JOIN authorization on authorization.id = u.authorization
LEFT JOIN user_situation_list on user_situation_list.user_situation_id = u.user_situation
WHERE
EXISTS(
select * from user_notes
where user_notes.note_user_id = u.id AND user_notes.create_date
BETWEEN "2017-10-20" AND "2017-10-22"
)
ORDER BY u.lp_modify_date DESC, u.id DESC
Turn it around -- find the ids first; deal with the joins later.
SELECT u.*,
( SELECT rep.name
FROM users AS rep
WHERE rep.id = u.add_user ) AS rep_name
FROM (
SELECT DISTINCT note_user_id
FROM user_notes
WHERE create_date >= "2017-10-20"
AND create_date < "2017-10-20" + INTERVAL 3 DAY
) AS un
JOIN users AS u ON u.id = un.note_user_id
ORDER BY lp_modify_date DESC, id DESC
Notes
No GROUP BY needed;
2 tables seem to be unused; I removed them;
I changed the date range;
User notes needs INDEX(create_date, note_user_id);
Notice how I turned a LEFT JOIN into a subquery in the SELECT list.
If there can be multiple rep_names, then the original query is "wrong" in that the GROUP BY will pick a random name. My Answer can be 'fixed' by changing rep.name to one of these:
MAX(rep.name) -- deliver only one; arbitrarily the max
GROUP_CONCAT(rep.name) -- deliver a commalist of names
Rewriting your query to use a JOIN rather than an EXISTS check in the where should speed it up. If you then group the results by the user.id it should give you the same result:
SELECT u.*, rep.name as rep_name FROM users as u
LEFT JOIN users as rep on rep.id = u.add_user
LEFT JOIN authorization on authorization.id = u.authorization
LEFT JOIN user_situation_list on user_situation_list.user_situation_id = u.user_situation
JOIN user_notes AS un
ON un.note_user_id
AND un.create_date BETWEEN "2017-10-20" AND "2017-10-22"
GROUP BY u.id
ORDER BY u.lp_modify_date DESC, u.id DESC

MySql : left join users table with transactions table return several rows

I have 2 tables : users and paypal_transactions
For each user, we have an id (named user_id in paypal_transactions table)
A user may have several paypal_transactions. Relation one to many
I need to grab the latest transaction id (ordered by date_dt DESC) when I do my query
My current query :
SELECT `Transaction`.*, `User`.*, `Tipster`.`username`
FROM `pronostics_framework`.`users` AS `User`
LEFT JOIN `pronostics_framework`.`users` AS `Tipster` ON (`User`.`tipster_id` = `Tipster`.`id`)
LEFT JOIN `pronostics_framework`.`paypal_transactions` AS `Transaction` ON (`User`.`id` = `Transaction`.`user_id`)
ORDER BY `User`.`id` DESC
LIMIT 500
Currently with one transaction per user, it works fine. BTW with many transactions I still get the 1st entry from paypal_transactions table (the oldest, but I want the latest from now).
I did many tries, without success.
Thanks for your help !
Here you go:
SELECT `Transaction`.*, `User`.*, `Tipster`.`username`
FROM `pronostics_framework`.`users` AS `User`
LEFT JOIN `pronostics_framework`.`users` AS `Tipster` ON (`User`.`tipster_id` = `Tipster`.`id`)
LEFT JOIN (SELECT user_id, MAX(date_dt) AS max_date
FROM `pronostics_framework`.paypal_transactions
GROUP BY user_id) AS max_trans
ON User.id = max_trans.user_id
LEFT JOIN `pronostics_framework`.`paypal_transactions` AS `Transaction`
ON (max_trans.user_id = `Transaction`.`user_id` AND max_trans.max_date = Transation.date_dt)
ORDER BY `User`.`id` DESC
LIMIT 500
Another way, based on the first query in the first answer at Retrieving the last record in each group:
SELECT `Transaction`.*, `User`.*, `Tipster`.`username`
FROM `pronostics_framework`.`users` AS `User`
LEFT JOIN `pronostics_framework`.`users` AS `Tipster` ON (`User`.`tipster_id` = `Tipster`.`id`)
LEFT JOIN `pronostics_framework`.`paypal_transactions` AS `Transaction` ON Transaction.user_id = User.id
LEFT JOIN `pronostics_framework`.paypal_transactions AS Transactions1
ON Transactions1.user_id = Transactions.user_id AND Transactions1.user_id > Transactions.user_id
WHERE Transactions1.user_id IS NULL
ORDER BY `User`.`id` DESC
LIMIT 500

return a total count of counts in prepared statement

The following statement gets row counts for user_ids from various tables/conditions where the users are within specific computers of a specific account. It works as expected. An example output would be something like this :
Array
(
[0] => Array
(
[computer_name] => COMPUTER_1
[username] => Steve
[t1count] => 13
[t2count] =>
[t3count] => 23
[t4count] => 64
)
... and so on for each
the statement :
$stmt = $db->prepare("
SELECT c.computer_name, users.username, t1count, t2count, t3count, t4count
FROM
( SELECT account_id, computer_id, computer_name
FROM computers
WHERE account_id = ".$_SESSION['user']['account_id']."
ORDER BY computer_id ASC LIMIT 0, ".$_SESSION['user']['licenses']."
) as c
LEFT JOIN users
on users.computer_id = c.computer_id
LEFT JOIN
(SELECT user_id, COUNT(user_id) as t1count
FROM t1
WHERE t1.title LIKE 'started'
GROUP BY user_id) as t_t1
on t_t1.user_id = users.user_id
LEFT JOIN
(SELECT user_id, COUNT(user_id) as t2count
FROM t2
GROUP BY user_id) as t_t2
on t_t2.user_id = users.user_id
LEFT JOIN
(SELECT user_id, COUNT(user_id) as t3count
FROM t1
WHERE t1.title LIKE 'blocked'
GROUP BY user_id) as t_t3
on t_t3.user_id = users.user_id
LEFT JOIN
(SELECT user_id, COUNT(user_id) as t4count
FROM t1
WHERE t1.title LIKE 'closed'
GROUP BY user_id) as t_t4
on t_t4.user_id = users.user_id
... and so on for each
WHERE c.account_id = ?
");
I want to also return a totalsum = t1count + t2count + t3count + t4count in this statement as well, but can't seem to get anything working. In this situation I cannot do outside processing (adding the values that are returned)... it needs to be in the statement. I am also open to any suggestions in what I already have if there are better options.
What are you trying to do with these values? SUM(t1count,t2count,t3count,t4count) AS totalsum should work to get a count of counts.
Your query is a bit hard to read. You have implicit and explicit JOINs. You are grouping numerous times and pulling columns when you can generally do this all in one shot. If you share an SQLFiddle, I will be able to clean this up, but in short:
SELECT
c.computer_name,
users.username,
count(t_t1.user_id) AS t1count,
count(t_t2.user_id) AS t2count,
count(t_t3.user_id) AS t3count,
count(t_t4.user_id) AS t4count,
(count(t_t1.user_id)+count(t_t2.user_id)+count(t_t3.user_id)+count(t_t4.user_id)) AS totalsum FROM users
LEFT JOIN computers AS c ON users.computer_id=c.computer_id AND c.account_id=?
LEFT JOIN t1 AS t_t1 ON t_t1.user_id = users.user_id AND t_t1.title LIKE "started"
LEFT JOIN t2 AS t_t2 ON t_t2.user_id = users.user_id
LEFT JOIN t1 AS t_t3 ON t_t3.user_id = users.user_id AND t_t3.title LIKE 'blocked'
LEFT JOIN t1 AS t_t4 ON t_t4.user_id = users.user_id AND t_t4.title LIKE 'closed'
WHERE c.account_id = ?
AND t_t1.title LIKE started
GROUP BY users.user_id;
This may need tweaking, as I stated, but it is a lot cleaner and easier to read and should accomplish something very similar.
Alternately, if you can't get the query to run the way you want it to when you change it to entirely explicit joins, rather than using SUM, try adding the values together like I did in the example above. It should prevent them from aggregating in the same way.
EDIT
After viewing your SQLFiddle, I have doctored up a solution which does away with nested queries. The positive is that it is cleaner. The negative is that it requires you to specify the users using an IN clause.
SELECT computers.account_id,computers.computer_id,computers.computer_name,users.user_id,users.username,count(distinct t_count1.log_id) AS count1,count(distinct t_count2.log_id) AS count2,count(distinct t_count3.log_id) AS count3, count(distinct t_count4.event_id) AS count4,
(count(distinct t_count1.log_id) + count(distinct t_count2.log_id) + count(distinct t_count3.log_id) + count(distinct t_count4.event_id)) AS totalcount
FROM users
INNER JOIN computers ON computers.computer_id=users.computer_id
LEFT JOIN logs AS t_count1 ON t_count1.type LIKE 'type1' AND t_count1.user_id=users.user_id
LEFT JOIN logs AS t_count2 ON t_count2.type LIKE 'type2' AND t_count2.user_id=users.user_id
LEFT JOIN logs AS t_count3 ON t_count3.type LIKE 'type3' AND t_count3.user_id=users.user_id
LEFT JOIN events AS t_count4 ON t_count4.user_id = users.user_id
WHERE computers.account_id=1 AND computers.computer_id in (1,2)
GROUP BY users.user_id
ORDER BY users.user_id ASC,computers.computer_id ASC;
If you choose to keep your current query structure for any reason, adapting it like so should make it work for you:
select *,ifnull(count1,0)+ifnull(count2,0)+ifnull(count3,0)+ifnull(count4,0) AS totalcount from
( select account_id, computer_id, computer_name
from computers
order by computer_id asc limit 0, 2
) as c
left join users
on users.computer_id = c.computer_id
left join
(select user_id, count(user_id) as count1
from logs
where logs.type like 'type1'
group by user_id) as t_count1
on t_count1.user_id = users.user_id
left join
(select user_id, ifnull(count(user_id),0) as count2
from logs
where logs.type like 'type2'
group by user_id) as t_count2
on t_count2.user_id = users.user_id
left join
(select user_id, count(user_id) as count3
from logs
where logs.type like 'type3'
group by user_id) as t_count3
on t_count3.user_id = users.user_id
left join
(select user_id, count(user_id) as count4
from events
group by user_id) as t_count4
on t_count4.user_id = users.user_id
where c.account_id = 1;
My advice would be to follow along each query to understand what you are asking SQL to do. To actually add all values together, you should be counting the number of records that are returned. Counting values of your primary keys helps you to count records. Also, using your other example, ifnull in the second example make sure that null values are not going to interfere with adding. "If a value is null make it 0 instead."

Using LEFT JOIN with 2 different query GROUP BY

My first SQL query is:
SELECT username,COUNT(username) as total_active_users FROM users WHERE active = '1' GROUP BY referrer // $act_user
To count the active users for each referrer
The second sql query is:
SELECT COUNT(orders) as total_user_orders FROM users_orders GROUP BY $act_user['username'] // the username from the first query.
To count total number of orders for each user which i got from the first query
What I'm trying to do it using LEFT JOIN to only count active users who have 1 order at least
The problem is: I have 2 different GROUP BY the first one is "referrer" and the second is "username"
I'm trying to do something like :
SELECT u.username, COUNT(u.username) as total_active_users, COUNT(b.orders) as
total_user_orders FROM users u LEFT JOIN users_orders b on u.username = b.username
WHERE u.active = '1' AND total_user_orders >= '1' GROUP BY (u.referrer for u) and (b.username for b)
Any idea please?
You can do this instead:
SELECT
a.username,
COUNT(u.username) as total_active_users,
COUNT(b.orders) as total_user_orders
FROM
(
SELECT username FROM users_orders WHERE total_user_orders >= '1'
UNION ALL
SELECT username FROM users WHERE u.active = '1'
) AS a
LEFT JOIN users AS u ON a.username = u.username
LEFT JOIN users_orders AS b on u.username = b.username
GROUP BY a.username;
Assuming that user names are unique and that for a user to have at least one order means the same as for them to have at least one row in the users_orders table, you could do the following:
SELECT
u.referrer,
COUNT(DISTINCT u.username) AS usercount
FROM users u
INNER JOIN users_orders uo ON u.username = uo.username
WHERE u.active = 1
;
The join between users and users_orders acts as a filter (in addition to that on the active status). It may produce duplicate user names but COUNT(DISTINCT) will count unique entries only.

How to get all posts from each user?

I have the table users with information about every user. Then the table posts with information about articles and finally the table user_posts, which contains following columns:
user_id
post_id
...
I am trying to get the chart of users with the highest count of posts. I made this query:
SELECT u.id as uid, u.name as uname,
count(up.id) as up_count
FROM users as u JOIN user_posts as up ON up.user_id = u.id ORDER BY vcount DESC LIMIT 25
This query returns me only one user and the total count of all rows in the table user_posts.
What am I doing wrong? I need to get the list of 25 users sorted by the count of articles that published each user.
Thank you in advance
Your query needs to have GROUP BY clause because you have used COUNT() function.
SELECT u.id as uid,
u.name as uname,
count(up.id) as up_count
FROM users as u
LEFT JOIN user_posts as up
ON up.user_id = u.id
GROUP BY u.id, u.name
ORDER BY up_count DESC LIMIT 25
You must have grouped them by ID otherwise you'll single total count result for all records. One more thing, use LEFT JOIN so even users with no post still will be visible in you result with the score of 0.
SELECT
u.id as uid, u.name as uname, count(up.id) as up_count
FROM users as u
JOIN user_posts as up ON up.user_id = u.id
GROUP BY
u.id, u.name
ORDER BY
vcount
DESC LIMIT 25

Categories