UPDATE with a JOIN & GROUP - mysql

I want to update all user records with the number of emails associated to that user. So I have
| userid | name | emailcount |
and
| userid | emaildata
I am trying to make a single UPDATE query which which will fill the emailcount with the number of emails that user has.
I have tried using a single UPDATE but can't make it work; do I need to use a subquery somehow to do this?

As Elliot suggests, you can drop the column emailcount and generate the value dynamically with a query like this:
select userid, name, coalesce(ec.count, 0) as emailcount
from User u
left outer join (
select userid, count(*) as count
from Email
group by userid
) ec on u.userid = ec.userid

If you want to do this action I suggest this query, but it is not tested on MySQL, I don't have the access at this moment. I hope that it is correct if not please others can correct me
UPDATE user SET emailcount = (SELECT count(*) FROM emaildata WHERE emaildata.userid user.userid)

Related

How to get data from database with condition on another table where something exist or not

I have a table for users like this
id | name | password | email
1 saeid ***** asd#asd.com
I have another table called appointments
id | created_by | due_date | notification_send
1 1 ***** 0
I want to get all users from users table where they have at least created one appointment in the appointments table (denoted by created_by field in the appointments table).
I have tried the code below but it fails:
SELECT * FROM users LEFT JOIN appointments a ON persons.id = a.created_by
But obviously it does not work.
One way is to use the exists predicate:
SELECT * FROM users u
WHERE EXISTS (SELECT 1 FROM appointments a WHERE a.created_by = u.id)
Alternatively you could use an inner join, but the exists query corresponds better to your question in my opinion (that is if you only need data from the users table).
The left join says to get all rows from users regardless if they have matching rows in appointments which is not what you want.
You are searching for a match between the table and so I would suggest doing a INNER JOIN rather like below
SELECT * FROM users u
JOIN appointments a ON u.id = a.created_by
Also check your ON clause once I think either this is a typo or a big mistake. You are selecting from users table then why persons.id??
ON persons.id = a.created_by
Try something like this:
http://sqlfiddle.com/#!9/5eba3/2
select * from users c where (select count(*) from appointments where created_by = c.id) > 0;

SQL SELECT name by id

I need help with a sql query.
I have these 2 tables:
player_locations:
ID | playerid | location <- unqiue key
---|-----------------------
1 | 1 | DOWNTOWN
and users:
ID | playername | [..]
----|--------------------
1 | example1 | ...
I need a select to get the users.playername from the player_locations.playerid. I have the unique location to get the player_locations.playerid.
Pseudo query:
SELECT playername
FROM users
WHERE id = player_locations.playerid
AND player_locations.location = "DOWNTOWN";
The output should be example1.
This is just a simple INNER JOIN. The general syntax for a JOIN is:
SELECT stuff
FROM table1
JOIN table2 ON table1.relatedColumn = table2.relatedColumn
In your case, you can relate the two tables using the id column from users and playerid column from player_locations. You can also include your 'DOWNTOWN' requirement in the JOIN statement. Try this:
SELECT u.playername
FROM users u
JOIN player_locations pl ON pl.playerid = u.id AND pl.location = 'DOWNTOWN';
EDIT
While I personally prefer the above syntax, I would like you to be aware of another way to write this which is similar to what you have now.
You can also select from multiple tables by using a comma in your FROM clause to separate them. Then, in your WHERE clause you can insert your conditions:
SELECT u.playername
FROM users u, player_locations pl
WHERE u.id = pl.playerid AND pl.location = 'DOWNTOWN';
Here is the solution.
SELECT
playername
FROM users
WHERE id = (SELECT id FROM player_locations WHERE location='DOWNTOWN')
I have a idea, try this:
SELECT playername
FROM users
WHERE id IN (SELECT DISTINCT playerid FROM player_location WHERE location LIKE "DOWNTOWN");

sql, keep only max value and delete others

I have this sort of table :
-id | name | memo
-1 | Gotham | s1ep1
-2 | Gotham | s1ep3
-3 | Gotham | s1ep5
I would like to keep the entry with the max(memo) and delete others, so just keep the third one (ep5).
I can retrieve the result of all max(memo) group by name like this :
SELECT id,max(memo) FROM `reminder` group by name
But I don't find the proper way to delete others, even looking at similar topics.
I expected something like "delete every entries that are not in my selection".
delete from reminder where not exists (SELECT id,max(memo) FROM `reminder` group by name)
But it doesn't work, "You can't specify target table 'reminder' for update in FROM clause". I must do it badly. Thanks for help.
You can do this with a join:
delete r
from reminder r left join
(select name, max(memo) as maxmemo
from reminder
group by name
) rn
on r.name = rn.name and r.memo = rn.maxmemo
where rn.name is null;
As an aside. More typically, one wants to keep the row with the highest id. The structure is the same, just the columns are different:
delete r
from reminder r left join
(select name, max(id) as maxid
from reminder
group by name
) rn
on r.name = rn.name and r.id = rn.maxid
where rn.name is null;

SQL Update with results of SELECT

I have an extensive SQL SELECT That performs a calculation of TotalNetWorth for a number of Users. The result is the TotalNetworth and User. This can contain multiple records. Example:
-------------------------
|TotalNetWorth | UserId |
-------------------------
| 24.45 | 1 |
| 45.34 | 3 |
-------------------------
What I want to do is update the NetWorth column in my Users table with the TotalNetWorth value, and UserId = Users.Id as the key. What's the best way to go about this?
You can use a JOIN on an aliased subquery.
UPDATE
Users
FROM
Users u
INNER JOIN
(SELECT WhatEver FROM YourQueryThatCalcsNetWorth) nw
ON
nw.UserID = u.UserId
Something like that
UPDATE u
FROM Users u
JOIN tableTotalNetWorth t ON t.UserID = u.UserId
CREATE TEMPORARY TABLE TempNetWorth AS (SELECT * FROM [your query])
UPDATE Users u, TempNetWorth t
SET u.NetWorth = t.TotalNetWorth
WHERE u.UserID = t.UserId
do your select first and then update immediately with cte help
WITH cte_query AS (
SELECT TotalNetWorth = <calculate_total>
FROM [Users])
UPDATE cte_query
SET TotalNetWorth = TotalNetWorth;
You could do an INSERT .... SELECT .... ON DUPLICATE KEY UPDATE ...., as explained here.
You may have to use your extensive SELECT query to pull data into a temporary table first, say "temp" and then try using this query:
Update Users set NetWorth = (select TotalNetWorth from temp where Users.Id = temp.UserId)

SQL query to find number of users who are in two specific groups

I have table in MySQL database with two integer columns for example:
userid | groupid
10 | 300
11 | 300
11 | 301
12 | 302
Given two groupids, I am looking for the best and quickest way to find userids which are in both groups. My table contains 23M rows and I need to that for each distinct pair of groupids. Currently both columns are indexed however it takes so long to get the result even for a single pair of groups and I have 1000 distinct groupids. The query I am running now is:
select count(t2.userid)
from usergroup t1, usergroup t2
where t1.groupid = 27 and t2.groupid = 714 and t1.userid = t2.userid
Is there a way to do it fast?
Why the join?
select
u.userid
from
usergroup u
where
u.groupid in (27, 714)
group by
u.userid
having
count(u.userid) > 1
Assuming a combination of userid and groupid is unique, which I figure it should be in a table like this.
It looks correct method for me, but it could be faster by creating prepared statements.
See the below post for example.
How can I prevent SQL injection in PHP?
I think this might be what you are looking for...
select
u1.userID
from
usergroup u1
join usergroup u2
on u2.groupid = 714
AND u1.userid = u2.userid
where
u1.groupid = 27
So, the primary WHERE clause is just give me a list of users within group ID = 27... so this will be optimized exclusively on the GROUP ID. THEN, by doing a self-join to the user groups table matched by the same user ID AND group ID = the 714, it will only return the record if such IS found. I could have a compound index on BOTH Group AND User such as
KEY GroupUser (groupid, userid)
so this way the index will be optimized for BOTH query components...
At MOST, it will go through the first u1 instance one time for everyone in the group 27... No counts or having involved...