SQL - Syncing Denormalize Table - mysql

I have a USERS table and a LOGS table. The LOGS table was normalized, storing only a user_id until recently, when I decided to denormalized it for performance reasons. After this change, I have username and user_role columns as part of LOGS table as well.
Now I need to update existing records of the LOGS table to fill out username and user_role columns, based on the value of user_id column, so that data becomes consistent. How can go about achieving this? I'm looking for possibly an SQL script that I can run on the database server.
Asim

Use something like this. You can just join the users table
UPDATE LOGS l
INNER JOIN users u ON u.id=l.user_id
SET l.username=u.name,
l.user_role=u.role
WHERE ... if necessary
UPDATE:
UPDATE LOGS l
INNER JOIN (select l.id as log_id, u.*
from logs l join users u ON u.id=l.user_id
order by l.id
limit 10) sub ON sub.id=l.id
SET l.username=sub.name,
l.user_role=sub.role

Related

Subquery in mysql to use one column for two different results

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.

2-step SQL Query..something seems wrong

I'm writing what is a pretty simple 2-step SQL Query.
I have one table called Users and another called ProfileCharacteristics.
**Users Table:**
UserId [PK]
UserName
**ProfileCharacteristics Table:**
UserId [FK]
.....(other data)
I'm trying to get access to (other data), but I only have the UserName available. So what I'm presently doing is running one SQL Query that matches the UserName to the UserId and stores the UserId value.
Then, I'm pulling all values that match to UserId in ProfileCharacteristics in a separate query. I have a gut feeling that I could combine these two queries into one, but I'm not sure how.
Any pointers?
EDIT: The start of a JOIN?
SELECT * FROM ProfileCharacteristics
INNER JOIN Users
ON ....
What you're looking for is an INNER JOIN:
SELECT pc.*
FROM ProfileCharacteristics pc
JOIN Users u ON pc.UserId = u.UserId
WHERE U.UserName = 'someuser'
A Visual Explanation of SQL Joins

Cross referencing tables in a mySQL query?

I have two tables. One is a table of users with a unique id field, and the other is a table of data, with a column that holds the user id of whoever generated that piece of data.
I want to do something like SELECT data,genned_by FROM datatable; but I want to replace the results for genned_by with SELECT username FROM users WHERE id = genned_by
So that the results from the query changes the userid into a username that corresponds with the other table.
I did some research and figured INNER JOIN might be what I'm looking for, but I'm left very unsure of how to use it after reading it. Help?
Try to use
SELECT d.data, u.username FROM database d INNER JOIN user u ON u.id=d.genned_by
Hope it helps you
SELECT datatable.data,users.username
FROM datatable, users
WHERE users.id = datatable.genned_by

Convert many to many to one to one (mysql)

We changed database schema and moved a relationship between users/accounts from a 1-1 to a many to many using a join table accounts_users.
So we have
accounts,
users,
accounts_users (user_id and account_id)
Our data is still 1-1, and we have decided to move back. So I need sql to move back:
To Migrate I used:
INSERT INTO accounts_users (account_id,user_id) SELECT id AS account_id, user_id AS user_id FROM accounts
To move back I have tried:
UPDATE
accounts
SET
user_id = ru.user_id
FROM
accounts r, accounts_users ru
ON
r.id = ru.account_id
Update accounts
Set r.user_id = ru.user_id
FROM accounts r, accounts_users ru
WHERE r.id = ru.account_id
SELECT accounts_users.user_id
INTO accounts
FROM accounts_users
INNER JOIN accounts
ON accounts.id = accounts_users.account_id
All of these give a sql error of some sort. Im guessing its because my sql is ambiguous, and I need some sort of select first or min or something like that.
** To be clear, Im sure still have the 1-1 relationship in the data, but I cant figure out the sql to bring the data from the existing tables back into the original tables. What im looking for is some working sql that will take the data from accounts_users and put the user_id into the account table. Thanks, Joel
You could try...
UPDATE accounts
SET user_id = (SELECT user_id
FROM accounts_users
WHERE accounts_users.accounts_id = accounts.accounts_id);
That'll get pretty tedious if you have a lot of columns in accounts_users that have to go back in accounts, though, and won't work if there is any problems with the ids (hence my previous answer). How many columns are there?
If your mapping is 1-1 then just select the first result (you know there is only one)

Serious MySQL Performance Issue (Joins, Temporary Table, Filesort....)

I've got a users table and a votes table. The votes table stores votes toward other users. And for better or worse, a single row in the votes table, stores the votes in both directions between the two users.
Now, the problem is when I wanna list for example all people someone has voted on.
I'm no MySQL expert, but from what I've figured out, thanks to the OR condition in the join statement, it needs to look through the whole users table (currently +44,000 rows), and it creates a temporary table to do so.
Currently, the bellow query takes about two minutes, yes, two minutes to complete. If I remove the OR condition, and everything after it in the join statement, it runs in less than half a second, as it only needs to look through about 17 of the 44,000 user rows (explain ftw!).
The bellow example, the user ID is 9834, and I'm trying to fetch his/her own no votes, and join the info from user who was voted on to the result.
Is there a better, and faster way to do this query? Or should I restructure the tables? I seriously hope it can be fixed by modifying the query, cause there's already a lot of users (+44,000), and votes (+130,000) in the tables, which I'd have to migrate.
thanks :)
SELECT *, votes.id as vote_id
FROM `votes`
LEFT JOIN users ON (
(
votes.user_id_1 = 9834
AND
users.uid = votes.user_id_2
)
OR
(
votes.user_id_2 = 9834
AND
users.uid = votes.user_id_1
)
)
WHERE (
(
votes.user_id_1 = 9834
AND
votes.vote_1 = 0
)
OR
(
votes.user_id_2 = 9834
AND
votes.vote_2 = 0
)
)
ORDER BY votes.updated_at DESC
LIMIT 0, 10
Instead of the OR, you could do a UNION of 2 queries. I have known instances where this is an order of magnitude faster in at least one other DBMS, and I'm guessing MySQL's query optimizer may share the same "feature".
SELECT whatever
FROM votes v
INNER JOIN
users u
ON v.user_id_1 = u.uid
WHERE v.user_id_2 = 9834
AND v.votes_2 = 0
UNION
SELECT whatever
FROM votes v
INNER JOIN
users u
ON v.user_id_2 = u.uid
WHERE v.user_id_1 = 9834
AND v.votes_1 = 0
ORDER BY updated_at DESC
You've answered your own question: yes, you should redesign the table, as it's not working for you. It's too slow, and requires overly complicated queries. Fortunately, migrating the data is just a matter of doing essentially the query you're asking about here, but for all user instead of just one. (That is, a sum or count over the unions the first answering suggested.)