I used to know how to do this but a lack of practice made me lose it.
I am trying to update usernames from a table by comparing matching email in another.
basically the first table has username empty, while the other has username and emails filled.
here is my wrong query :
UPDATE users SET username = (SELECT Username FROM clients WHERE email in mail)
email is from my clients table, mail is from my users table
I would suggest update with using JOIN with UPDATE, something like this should work
UPDATE users
INNER JOIN
#your relationship / for example
clients ON (users.id = clients.user_id)
SET
users.username = clients.email
WHERE
users.username IS NULL
Just make sure ON clause is correct relation that you have between users and clients and it should update all records in users username column with email from clients
You have not provided enough information to get a clear answer.
If you don't set a WHERE clause in your UPDATE statement, you will update all records with the same value, which is probably not what you want
If you want to update the users table with some info on matching records in the client table, then you need to join both tables on your matching field. Something like this :
UPDATE users U, clients C
SET u.username = c.username
WHERE U.email=C.email
AND C.email IN (...)
In this example I assumed that the email address was the matching field between the 2 tables (you should adapt this), and that you provide a list of target email addresses (you can remove this)
Related
So, I’ve got two tables. Users contains basic user information and user_address contains user address’. Pretty straight forward.
I have a search form that allows for users to be looked up. One search field searches multiple columns using LIKE.
It allows for users to be pulled by their...
company name (listed under users table)
Name (listed under user address table)
Email address (user address table)
Phone 1 (user address table)
Phone 2 (user address table)
The form triggers an Ajax which passes the search value to the search page via $_POST.
$value is then assigned from the $_POST and is filtered and then passed to the mysql query.
On a normal case scenario where both the user exists and addresses exist for the user, the query below works perfectly.
The problem is, that sometimes when a “user” is added to the database, an address isn’t entered right away. During this instance, when trying to search for a user, the user isn’t found.
I need it to find the users whether an address is entered or not. I have tried JOIN, LEFT JOIN, RIGHT JOIN, INNER JOIN, etc. Nothing seems to be working. And for some reason, left join SLOWS down the query and when the query is triggered, the page gets bogged down.
"SELECT u.id,u.company,a.name as address_name
FROM Users as u
JOIN User_Address as a ON a.user_id = u.id
WHERE a.name LIKE '%$value%' OR u.company LIKE '%$value%' OR a.email LIKE '%$value%' OR a.phone_1 LIKE '%$value%' OR a.phone_2 LIKE '%$value%' GROUP BY u.id”
Again the problem with the search is when a user exists in the User table, but no address exists for that user in the User Address table.
Your query is a bit tricky, because if I understand correctly, you want to have both the user and the address, even if the match is just in the user. That's why I would pull the matching into a subquery. This will also massively help with performance.
SELECT Users.id, Users.company, User_Address.name AS address_name
FROM (
SELECT id AS user_id FROM Users WHERE u.company LIKE '%$value%'
UNION
SELECT user_id
FROM User_Address
WHERE a.name LIKE '%$value%'
OR a.email LIKE '%$value%'
OR a.phone_1 LIKE '%$value%'
OR a.phone_2 LIKE '%$value%'
) AS matches
JOIN Users ON Users.user_id = matches.user_id
LEFT JOIN User_Address ON User_Address.user_id = Users.id
GROUP BY u.id
By the way, the LIKE '%$value%' looks like you're using string interpolation to build your query. This can be unsafe. Make sure your values are properly escaped and you understand the dangers and alternatives (like using a parameter binding library).
I'm currently having a problem with a legacy app I just inherited on my new job. I have a SQL query that's way too long to respond and I need to find a way to fasten it.
This query acts on 3 tables:
SESSION contains all users visits
CONTACT contains all the messages people have been sending through a form and contains a "session_id" field that links back to the SESSION id field
ACCOUNT contains users accounts (people who registered on the website) and whose "id" field is linked back in SESSION (through a "SESSION.account_id" field). ACCOUNT and CONTACT are no linked in any way, besides the SESSION table (legacy app...).
I can't change this structure unfortunately.
My query tries to recover ALL the interesting sessions to serve to the administrator. I need to find all sessions that links back to an account OR a contact form.
Currently, the query is structured like that :
SELECT s.id
/* a few fields from ACCOUNT and CONTACT tables */
FROM session s
LEFT JOIN account act ON act.id = s.account_id
LEFT JOIN contact c on c.session_id = s.id
WHERE s.programme_id = :program_id
AND (
c.id IS NOT NULL
OR
act.id IS NOT NULL
)
Problem is, the SESSION table is growing pretty fast (as you can expect) and with 400k records it slows things down for some programs ( :programme_id in the query).
I tried to use an UNION query with two INNER JOIN query, one between SESSION and ACCOUNT and the other one between SESSION and CONTACT, but it doesn't give me the same number of records and I don't really understand why.
Can somebody help me to find a better way to make this query ?
Thanks a lot in advance.
I think you just need indexes. For this query:
SELECT s.id
/* a few fields from ACCOUNT and CONTACT tables */
FROM session s LEFT JOIN
account act
ON act.id = s.account_id LEFT JOIN
contact c
ON c.session_id = s.id
WHERE s.programme_id = :program_id AND
(c.id IS NOT NULL OR act.id IS NOT NULL);
You want indexes on session(programme_id, account_id, id), account(id) and contact(session_id).
It is important that programme_id be the first column in the index on session.
#Gordon already suggested you add an index, which is generally the easy and effective solution, so I'm going to answer a different part of your question.
I tried to use an UNION query with two INNER JOIN query, one between
SESSION and ACCOUNT and the other one between SESSION and CONTACT, but
it doesn't give me the same number of records and I don't really
understand why.
That part is rather simple: the JOIN returns a result set that contains the rows of both tables joined together. So in the first case you would end up with a result that looks like
session.id, session.column2, session.column3, ..., account.id, account.column2, account.column3, ....
and a second where
session.id, session.column2, session.column3, ..., contact.id, contact.column2, contact.column3, ....
Then an UNION will faill unless the contact and account tables have the same number of columns with correspoding types, which is unlikely. Otherwise, the database will be unable to perform a UNION. From the docs (emphasis mine):
The column names from the first SELECT statement are used as the column names for the results returned. Selected columns listed in corresponding positions of each SELECT statement should have the same data type. (For example, the first column selected by the first statement should have the same type as the first column selected by the other statements.)
Just perform both INNER JOINs seperately and compare the results if you're unsure.
If you want to stick to an UNION solution, make sure to perform a SELECT only on corresponding columns : doing SELECT s.id would be trivial but it should work, for instance.
I have a users table and an edits table (showing who performed changes on their own or someone else's profile).
In the edits table, the editor and editee are listed using their userid, which is the unique id in the users table.
I would like to create the query:
Select users.username (the editee), users.username (the editor) from users
inner join edits on users.id = edits.editee_id
How would I create a subquery to pull the editor's name?
Thanks
You need to join the users table twice.
SELECT whatever,
editor.username AS editor_username,
editee.username AS editee_username
FROM edits
JOIN users AS editor ON edits.editor_id = editor.id
JOIN users AS editee ON edits.editee_id = editee.id
See what's going on? You use the users table twice, and give it a different alias in each use.
I have two tables that I'm joining, Users and Addresses.
The Users table has a unique (but not primary) key called userID.
The Addresses table has a primary key called userID.
I'm trying to left-join the tables so that I get all the info from the Users table regardless if it has a match in the Addresses table, so I used
select * from users u left join addresses a on a.userID = u.userID
This works, but it only shows userID's if there is a match. How do I get the userID regardless if there's a match or not?
Edit: The following image shows what my current query (left join) returns:
Now it's clear what the problem is.
There's nothing "wrong" with the query, except that it is returning multiple expressions (columns) with the same alias. And one of them is overriding the other. (Not in terms of the resultset being returned, all the columns and rows are there; the issue is with how your PHP script is processing the resultset. If you are referencing the values from the row by "association" (using the column name), only one of the column values gets referenced.
So, one way to fix that, is to qualify the columns in the query:
SELECT u.userID
, u.blah
, a.userID AS a_userID
, a.blah AS a_blah
FROM users u
LEFT
JOIN addresses a
ON ...
such that all column aliases are unique. Then all of those column names will be available by "association" in your PHP.
Using the query you provided should give a result in the u.userID column regardless of if it had a corresponding address. The a.userID column would only have data in the rows that were joined with an address.
You could change to:
select u.*, a.address from users u left join addresses a on a.userID = u.userID
Which would select only the relevant parts of the address and keep the whole u.
I have two tables, user and ban. User table has two columns id and type. Ban table also has two columns userID and bannedUserID. I want to delete records in ban table where bannedUserID has type of 'Admin'.
I've come up with such query but I am not sure if it is correct or not.
DELETE FROM ban WHERE ban.bannedUserID IN (SELECT id FROM user WHERE type = 'Admin')
Is it correct? Do I have to add/remove anything?
If you're not sure whether the DELETE is correct, you can test it by converting to an equivalent SELECT:
SELECT b.bannedUserID
FROM ban b JOIN user u ON b.bannedUserID = u.id
WHERE u.type = 'Admin';
Are the id's returned by that query the ones you want to DELETE?
Then try it in a transaction (if you use a storage engine that supports transactions, i.e. not MyISAM), so you can roll back if necessary:
START TRANSACTION;
DELETE b
FROM ban b JOIN user u ON b.bannedUserID = u.id
WHERE u.type = 'Admin';
/* do some SELECT to see if the correct rows have been deleted and no others */
/* but if anything appears wrong, and ban is an InnoDB table, you can... */
ROLLBACK;
Note that I'm using MySQL's multi-table DELETE syntax. It should work identically to your subquery approach, but in some cases it can be more flexible.