Why is this adding all rows? Insert only when exists? - mysql

I'm trying to insert a row into mentions when a username exists in the users table.
INSERT INTO mentions (user_id)
SELECT USER_ID
FROM users
WHERE EXISTS (
SELECT USER_ID FROM users
WHERE USERNAME LIKE 'mike'
);
However, the above query is adding ALL user_ids into the mentions table -- all 1 million of them. What am I overlooking here?
Users table schema
USER_ID | USER_NAME | USER_STATUS
1 | mike | active
2 | brian | active
mentions table schema
MENTION_ID | COMMENT_ID | USER_ID
I have a comment "#mike have you talked to #john lately?" and I'm parsing for the mentions. If mike is found in the user's table, I want to insert it into the mentions table along with the comment_id.

exists needs to have a correlation to the outer select so something like this
INSERT INTO mentions (user_id)
SELECT u.user_id
FROM users u
WHERE EXISTS
( SELECT 1 FROM mentions m
WHERE u.user_id = m.user_id
AND m.username = 'mike'
);
you can also use IN
INSERT INTO mentions (user_id)
SELECT u.user_id
FROM users u
WHERE u.user_id IN
( SELECT m.user_id FROM mentions m
WHERE m.username = 'mike'
);
NOTE:
I removed the LIKE 'mike' and just changed it to = 'mike'... LIKE is used when you need to match partial strings... you can easily do it with = if you are looking for the whole string.
if you want to find a partial string then you should include wildcards like so LIKE "%mike%"
EDIT:
with your most recent edit you are trying to do a subquery when you dont need one.
INSERT INTO mentions (comment_id, user_id)
VALUES
(your_comment_id,(SELECT u.user_id FROM users uWHERE u.username = 'mike'));
However, it seems like you should have some sort of dependency between the tables.. can you post the table schemas?

Are you sure USERNAME is in the table mentions?
Maybe you just need:
INSERT INTO mentions (user_id)
SELECT USER_ID
FROM users
WHERE USERNAME LIKE 'mike'

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;

MYSQL/PHP table design for friends table/query to select friends

For a social network site, I have a table with the ids of the inviter and the invitee and the status of the invitation ie accepted or not. According to what I've read, this seems to be best practice for a friends table.
Table friends
id | inviterid |inviteeid |status
however, for a given userid, I want to display all the "friends" the person has including their names. I can get a list of records of relationships with a simple query
Select * from friends WHERE inviterid = '33' or inviteeid = '33'"
But, this does not translate easily into a list of friends, since the friends could be either inviters or invitees so the field will be different depending on who invited whom.
Is there a better table design for a friends table? Alternatively, is there a sql syntax that would select friends who can be either inviters and invitees. Ultimately, I need to do a join to another table that has the users names.
You have a user table with below colums
userId|name|...
and your friend table
id | inviterid |inviteeid |status
if you want to find friends of a user that this user invited themes you can use below query!
select id, status from friend_tbl inner join user_tbl on user_tbl.id=friend_tbl.inviterid;
or if you want to get friend of this user that themes invitee his/her you can use below query:
select id, status from friend_tbl inner join user_tbl on user_tbl.id=friend_tbl.inviteeid;
I hope these can help you and i can understand your purpose!
Use union to get two kinds of friendS together, then you can join the results with username table.
Select inviterid as friend_id, status from friends where inviteeid = 33
Union
Select inviteeid as friend_id, status from friends where inviterid =33
I personally would just prefer to have two tables for this case, friend table and invite table
Friend Table
id | userid | friendid
So for selecting friends would be just
SELECT friendid FROM friend_table WHERE userid = 33
Invite Table
id | inviterid | inviteeid | status
For changing the status of invite table once the user approves, and insert new row to friend table
UPDATE invite_table SET status = 'accepted' WHERE inviterid = 33
INSERT INTO friend_table (`userid`, `friendid`) VALUES (33, $friendid)

MySQL: How to LEFT JOIN WHERE IS NULL (user1 blocks user2 OR upside down)?

I have a table user and in addition INNER JOIN it with table cities and a few others already. Now I also have the following table:
blocked_user
--------------------------------------------------------
id | user1_id | user2_id | timestamp
How can I use LEFT JOIN WHERE IS NULL, so both user combinations (user1 blocked user2 or user2 blocked user1) are excluded from the search results?
user
--------------------------------------------------------
id | username | ...
Thank you very much in advance for you help!
I'm guessing that you have a current user (the user who is performing the request) and you want to hide all users they have blocked or all users who have blocked them. I'm also assuming that user1_id is the user who did the blocking, and user2_id is the user they blocked. You should edit your question to make those points more clear.
If that's right, here's what I would do:
SELECT id, username
FROM user
LEFT JOIN (
SELECT DISTINCT user2_id AS blockee_id
FROM blocked_user
WHERE user1_id = :current_user_id
) this_user_blocked
ON user.id = this_user_blocked.blockee_id
LEFT JOIN (
SELECT DISTINCT user1_id AS blocker_id
FROM blocked_user
WHERE user2_id = :current_user_id
) blocked_this_user
ON user.id = blocked_this_user.blocker_id
WHERE this_user_blocked.blockee_id IS NULL
AND blocked_this_user.blocker_id IS NULL
I think it makes sense to use two separate LEFT JOIN ... WHERE ... IS NULL constructs because you are really checking for two different situations.
In this case I guess the keyword NOT EXISTS would be adecuate, semantically at least.
SELECT * FROM user u
WHERE NOT EXISTS (
SELECT * FROM blocked_user b
WHERE
b.user1_id = u.id
OR b.user2_id = u.id
)
There's also indeed the option of using:
SELECT * FROM user u LEFT JOIN blocked_user b ON b.user1_id = u.id
OR b.user2_id = u.id
WHERE b.id IS NULL
But regarding to the performances I don't know which one is more efficient.
rgds.

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)

Counting records from table that appear is one but not other: MYSQL

I have a two simple tables
users
+----+--------+-----------+
| id | gender | birthdate |
+----+--------+-----------+
userpreference
+----+------------------+-----------------+
| id | preference value | preference type |
+----+------------------+-----------------+
Question:
I want to query all people who have not listed a specific preference value such as 'shopping'.This includes all people who have not listed any preference types as well so that column could be null, however since userpreference's column 'id' references users as a foreign key, I also want to include in my count all people who don't show up in the second table (user preference)?
Total # of people who do not have preference value 'shopping' as their preference value:
Here is what i have tried:
SELECT
(
SELECT COUNT(DISTINCT userpreference.id) FROM userpreference
WHERE preferencevalue != 'shopping')
+
(
SELECT COUNT(users.id)
FROM users
WHERE users.id NOT IN
(SELECT userpreference.Id
FROM userpreference )
)
AS'Total'
Select Count(*)
From Users
Where Not Exists (
Select 1
From UserPreference As UP1
Where UP1.id = Users.id
And UP1.PreferenceValue = 'Shopping'
)
Try a RIGHT JOIN, that will include all people who dont show up in the second table
SELECT *
FROM Users
RIGHT JOIN Userpreference ON ( users.userID = Users.userID)
WHERE preference_value = 'shopping'
Try this:
SELECT COUNT(DISTINT U.id) FROM users U NATURAL LEFT JOIN userpreference UP
WHERE UP.preferencevalue IS NULL OR UP.preferenceValue != 'shopping';
The LEFT JOIN should bring in all the users records whether or not they have a UP record.