Updating a row based on number of existing records - php

I'm trying to update a number of rows in a user table based on a value occurring more than once. In this case it's user email - as the user can sign up to multiple websites hosted in this application.
UPDATE users SET email = REPLACE(email,'#', CONCAT('+',user_id,'#'))
WHERE user_id IN (
SELECT user_id FROM users HAVING COUNT('email') > 1
);
This query gives me the following error;
ERROR 1093 (HY000): You can't specify target table 'customer_entity' for update in FROM clause
I've tried a number of variations but none of these seem to work.

MySQL does not support this syntax. Instead, you can self-join an aggregate query:
UPDATE users u
INNER JOIN (SELECT user_id FROM users GROUP BY user_id HAVING count(email) > 1) u1
ON u1.user_id = u.user_id
SET u.email = REPLACE(e.email,'#', CONCAT('+', u.user_id, '#'))

The two links I cited have lots of great suggestions, and GMB's suggestion sounds promising, too.
Q: Have you really looked at each of these (multiple different!) alternatives, and tried them out yourself, with your dataset? What happened?
SUGGESTION (taking GMB's example):
Verify the select works (returns one or more rows):
SELECT user_id FROM users GROUP BY user_id HAVING count(email) > 1)
Combine the "update" with the "join" (different syntax):
UPDATE users u1
SET u1.email = REPLACE(e.email,'#', CONCAT('+', u1.user_id, '#'))
INNER JOIN users u2
ON u1.user_id = u2.user_id
GROUP BY u2.user_id HAVING count(u2.email) > 1;
Please let us know the results.

Related

MYSQL Query - Get the users that are not equal to the users I am following

I am trying to get the users I am not following and that isn't equal to me.
So far I have got this query:
SELECT DISTINCT
u.id,
u.username,
u.profileImage,
u.fullname,
u.coverImage,
u.bio,
a.uuid,
a.type
FROM USERS u
JOIN Activity a
WHERE NOT u.id = 145
AND a.id = 145
AND type = 'follow'
145 is the current user.
I store following's in the Activity table, So I Don't want to get the users that are equal to the IdOtherUser in the row where id = 145.
When I follow someone it would be like this:
Id = 145(me)
IdOtherUser = 86(other person I follow, who I don't want to get from USERS table.)
type = 'follow'(type of action)
I am successfully getting all the users that aren't equal to me(145) but cannot seem to get the users that are equal to the people I follow!
Any ideas are much appreciated.
Thanks in advance
fiddle
I want to get the users that is not equal to 123(current user, and the people he is following user(145))
There are various ways to accomplish the expected outcome. They are all based on using a subquery to determine if a user is followed by a given user. You can have this subquery as a derived table (in the from clause), or in a not in() or not exists() operator. I'll show you an example for the not exists() operator because it does not have to pull data from the users table, it merely checks if you have a record corresponding to the where criteria
select *
from users u1
where u1.id<>145 --not me
and not exists (select 1
from activity a
where a.id=145 --users I follow
and a.IdOtherUser=u1.id
and a.type='follow')

Inner, outer or full join on three tables in MySQL database on linux with apache

I want to have some help creating my query to get information from three different tables sharing information in common.
My first table is:
auctions
id title description user_id(who posted it)
My second table is:
bids
id user_id bid auction_id owner_id
My third table is:
users
id username X XX XXX XXXX
...and my SQL is as follows however it's not returning any results:
SELECT auction_bids.user_id AS applicant, auction_bids.*, auctions.title FROM auction_bids, auctions
WHERE auctions.user_id=".$_SESSION['userid']."
INNER JOIN users ON auction_bids.user_id = users.id
WHERE auction_bids.owner_id = ".$_SESSION['userid']."
What I need is to capture the auction's title, username who bidded on the auction and the bid. the auction has to have a bid and posted by the user who owns the $_SESSION['userid'].
Any help is appreciated.
You have two different 'where' statements, which may just need combining;
SELECT auction_bids.user_id AS applicant, auction_bids.*, auctions.title FROM auction_bids, auctions
INNER JOIN users ON auction_bids.user_id = users.id
WHERE auction_bids.owner_id = ".$_SESSION['userid']." AND auctions.user_id=".$_SESSION['userid']."
However, I'm not sure this is really what you want, as it will return only records where the specific user both 'owns' the item AND has bidded on it (both based on the userid session), rather than displaying all records from different people who have bidded on an item 'owned' by the user.
Something like: ?
SELECT auction_bids.user_id AS applicant, auction_bids.*, auctions.title FROM auction_bids, auctions
INNER JOIN users ON auction_bids.user_id = users.id,
WHERE auction.owner_id = ".$_SESSION['userid']."
Hope this points you in the right direction!
you have 2 where clauses, that is incorrect. I have revised your query based on your requirements.
SELECT auction_bids.user_id AS applicant, auction_bids.*, auctions.title
FROM auction_bids, auctions
INNER JOIN users ON auction_bids.owner_id = users.id
WHERE auction_bids.owner_id = ".$_SESSION['userid']."
AND auctions.user_id=auctions_bids.owner_id

SQL Joins across multiple tables

I am building an online survey system for which I wish to produce statistics. I want query based on the gender of the user. I have the following tables:
survey_question_options
survey_answer
users
I have constructed the following query so that it brings back a null response where there are no answers to the question:
SELECT COUNT(sa.option_id) AS answer , so.option_label
FROM survey_answer sa
RIGHT JOIN survey_question_options so
ON sa.option_id = so.option_id AND
sa.record_date>='2011-09-01' AND
sa.record_date<='2012-08-01'
LEFT JOIN users u
ON (sa.uid = u.uid AND u.gender='F')
WHERE so.question_id=24
GROUP BY so.option_label
ORDER BY so.option_id ASC
My query returns the following results set:
0 Red
1 Yellow
0 Blue
0 Green
However, the gender condition in the LEFT JOIN appears to be ignored in the query. When I change the gender to 'M' the same result is returned. However, the expected result would be 0 for everything.
I am not sure where I am going wrong. Please help.
Thanks in advance.
Well, you are doing a COUNT on a column from the main table, so the gender condition on the LEFT JOIN won't affect the result. You should do the COUNT on a column from the users table. I'm not sure if this is what you want, but you should try:
SELECT COUNT(u.uid) AS answer , so.option_label
FROM survey_answer sa
RIGHT JOIN survey_question_options so
ON sa.option_id = so.option_id AND
sa.record_date>='2011-09-01' AND
sa.record_date<='2012-08-01'
LEFT JOIN users u
ON (sa.uid = u.uid AND u.gender='M')
WHERE so.question_id=24
GROUP BY so.option_label
ORDER BY so.option_id ASC
The left join to the users table is evaluated after the join to the answer table - so although the user record is not returned if the user is the wrong gender, the answer record will be returned (regardless of the user's gender). Try:
SELECT COUNT(sa.option_id) AS answer , so.option_label
FROM (select a.option_id
from survey_answer a
JOIN users u ON a.uid = u.uid AND u.gender='F'
where a.record_date>='2011-09-01' AND
a.record_date<='2012-08-01') sa
RIGHT JOIN survey_question_options so
ON sa.option_id = so.option_id
WHERE so.question_id=24
GROUP BY so.option_label
ORDER BY so.option_id ASC
You're putting your condition in the wrong block. Since you're performing a LEFT JOIN, (which is a left-bound outer join) everything in the left table (the main table) is selected, together with the data from the joined table, where applicable. What you want is to add the data from all users and then restrict the full output of the query. What you've actually done is add the user data from only the female users and then displayed all data.
Sounds technical, but all you have to do is move the AND u.gender='F' into the main WHERE clause instead the ON clause. That will cause SQL to only select the rows for female users after the JOIN has taken place.

How to omit select results based on IDs from another table in mySQL?

My goal is that I want to get a list of user names in the database from my "users" table, but omit every user whose ID is also in the "projects_users" table where project_id = 1.
In another words, if these are the tables:
table: users
user_id user_name
1 dave
2 matt
3 james
table: projects_users
user_id project_id
1 2
2 2
3 1
This query would return "dave" and "matt" (since "james" is in the users table, but is also associated with project #1, thus he is omitted).
I understand that I should probably be using some form of join, but my current query is not doing it:
SELECT user_name
FROM users
JOIN projects_users ON (
users.user_id != (projects_users.user_id WHERE projects_users.user_id == 1)
)
This result does not work at all, and earlier experiments kept returning multiple copies of every name. Does anyone know of a way to do this without having to turn to a more manual PHP solution?
Final answer, worked perfectly. Maybe it isn't as optimised as some of the other solutions, but it's the only one that gave me valid results every time. For some reason, the other solutions sometimes popped out an unexpected name, or no name at all when they should have. Regardless, this sure beats doing it the long way with PHP.
SELECT user_id, user_name FROM users WHERE user_id NOT IN (SELECT user_id FROM projects_users WHERE project_id = 1)
Thanks everyone for your contributions. I appreciate all of your help and input.
Original answer
Utilize the power of a LEFT JOIN.
SELECT u.*
FROM users u
LEFT JOIN project_users pu ON u.user_id = pu.user_id
WHERE pu.project_id IS NULL OR pu.project_id <> 1;
Unlike JOIN (which is a shortcut for INNER JOIN), LEFT JOIN selects all rows from main table and their matching rows from joined table, BUT if the matching row is not found, a fake one is returned with all fields set to NULL.
Edit
When I re-read the question, it appeared to me that I got it wrong. If you want to filter out only users that are associated with a certain project, then this is a query to use.
SELECT DISTINCT u.user_id, u.user_name
FROM project_users pu
LEFT JOIN users u ON u.user_id = pu.user_id
WHERE pu.project_id <> 1;
try this:
SELECT DISTINCT
users.user_id,
user_name
FROM
projects_users
RIGHT JOIN
users
ON
users.user_id = projects_users.user_id
WHERE
projects_users.project_id <> 1
OR
projects_users.project_id IS NULL
Try the following:
select u.*
from users u
where exists (select null
from projects_users pu1
where u.user_id = pu1.user_id)
and not exists (select null
from projects_users pu2
where u.user_id = pu2.user_id and pu2.project_id = 1)
Alternatively:
select u.*
from users u
join projects_users pu on u.user_id = pu.user_id
group by u.user_id
having max(case when pu.project_id = 1 then 1 else 0 end) = 0

SELECT statement inside another SELECT statement

I have two tables called messages and users. In the messages table, there's a field which is a foreign key to the users table that is basically the users ID. I am trying to retrieve results from the messages table using a SELECT query, but I want the users username rather than their user ID. This SQL is wrong but I think it gets across the idea of what I'm trying to do:
SELECT (SELECT username FROM `users` WHERE u_id=?), message, sent FROM `messages` WHERE r_id=? AND sent > ?
Basically, I want to use the users ID stored in the messages table to get the users username to be returned AND get results from the messages table in one query.
I think JOINs are the tool for this, but I have very little bar no SQL experience.
Thanks.
You want to JOIN the two tables together, using the common u_id column.
SELECT u.username, m.message, m.sent
FROM messages m
INNER JOIN users u
ON m.u_id = u.u_id
WHERE m.r_id = ?
AND m.sent > ?
This is the case for an inner join:
select
u.username,
m.message,
m.sent
from
messages m
inner join users u on
m.u_id = u.u_id
where
m.r_id = ?
and u.u_id = ?
and m.sent > ?
What you're doing here is taking the messages table and saying, "Okay, grab me everything in the users table where the u_id column from messages equals the u_id column from users.
The where clause then filters your results down based on the parameters you want to pass it.
You can join tables ad nauseum, so you don't have to do just one, for future reference.
If you'd like to read more about joins and the different types, I highly encourage you to read Atwood's post on it here.
You can join two tables like this too:
SELECT
u.username,
m.message,
m.sent
FROM
messages m,
users u
WHERE
m.r_id=? AND
m.sent > ? AND
m.u_id = u.u_id
m.u_id is user id in messages table
You can refactor the query slightly like this:
select
u.username,
m.message,
m.sent
from
(
select u_id,message,sent
from messages
where r_id = ?
and sent > ?
) m
inner join
(
select u_id,username
from users
where u_id = ?
) u using (u_id);
You need to make sure you have a compound index on r_id and sent
ALTER TABLE messages ADD INDEX (r_id,sent);
Your query needs only slight correction and then it's equivalent to a LEFT JOIN (or INNER JOIN, exactly as #Joe Stefanelli's answer if messages.u_id is never NULL):
SELECT
(SELECT username FROM `users` WHERE u_id = messages.u_id) AS username
, message
, sent
FROM messages
WHERE r_id = ?
AND sent > ?

Categories