Two identical mysql tables, one is empty, how to populate it? - mysql

I have one table full of data (around 20,000 values)
table_1
ID | name | e-mail (only as an example, it could be just normal TEXT)
1 |alfaa | e-mail alfaa 1
2 |alfaa | e-mail alfaa 2
3 |beta | e-mail beta
4 |celta | e-mail celta
...
and other identical table with the "e-mail" column empty, and some names that are also contained in table_1, alltough with a different ID
table_2 (around 5,000 values)
ID | name | e-mail
1 |beta |
2 |alfaa |
3 |celta |
...
My question is, how can I populate the empty e-mail column of table_2 with values from e-mail column of table_1 WHERE table_2.name = table_1.name ?
The IDs are different AND table_1 contains some cases of several e-mails for the same name.
(well, I think I also could to manage it to work without several e-mails for the same name)

This is what I've got:
UPDATE table_2, table_1
SET table_2.email = table_1.email
WHERE table_1.name = table_2.name;
See this sqlfiddle

Let's talk about Database Normalization.
You have found a problem in the way your database schema is designed, mainly, you're store a lot of data in multiple places. This can easily lead to tables drifting out of sync from each other, wasted storage space, and costly lookups.
Let me show you what I'm talking about.
Case 1. Synchronizing tables.
Let's say you do populate your table_1, table_2 correctly. You get something like this:
table_1 table_2
ID_1 | name | email ID_2 | name | email
1 | bob | bob#cat.com 1 | adam | adam#dog.com
2 | adam | adam#dog.com 2 | bob | bob#cat.com
3 | bob | bob#dog.com 3 | bob | bob#dog.com
4 | joe | joe#dog.com
Note that I'm storing bob's two emails twice. This might not seem like much but if bob has 5 emails, and you add a table_3, then you're storing 15 records to only refer to 5 unique pieces of information.
Now let's say you're adam, and you want to update your email, let's say you want to change your email to adam#cat.com. And you do it in program 1, which uses table_1, but you don't do it in program 2, which uses table_2. What do you get when you hit the update?
table_1 table_2
ID_1 | name | email ID_2 | name | email
1 | bob | bob#cat.com 1 | adam | adam#dog.com
2 | adam | adam#cat.com 2 | bob | bob#cat.com
3 | bob | bob#dog.com 3 | bob | bob#dog.com
4 | joe | joe#dog.com
Adam now has a different email depending on whether he uses program 1 or program 2. So to solve this, you'd need to go through table_2 every time you change stuff in table_1, which is an extra database call.
Case 2. Internal consistency
Now let's say bob wants to change his name to jill. What happens now?
table_1 table_2
ID_1 | name | email ID_2 | name | email
1 | jill | bob#cat.com 1 | adam | adam#dog.com
2 | adam | adam#dog.com 2 | bob | bob#cat.com
3 | bob | bob#dog.com 3 | bob | bob#dog.com
4 | joe | joe#dog.com
Oops, I accidentally only updated one row corresponding to bob in table 1, now it seems like bob#cat.com and bob#dog.com are two different people, when they actually are the same. So I'd have to go through the entire database and check every row for name = "bob". Then I have to do the same for table_2. Your database is quickly becoming unmanageable.
Database Normalization
Instead of having two tables.
table_1 table_2
ID_1 | name | email ID_2 | name | email
1 | bob | bob#cat.com 1 | adam | adam#dog.com
2 | adam | adam#dog.com 2 | bob | bob#cat.com
3 | bob | bob#dog.com 3 | bob | bob#dog.com
4 | joe | joe#dog.com
Take the information common to the two tables, namely name-email pairs, and put it in a user table
table_1 table_2 user
ID_1 | userId ID_2 | userId userId | name | email
1 | 2 1 | 1 1 | adam | adam#dog.com
2 | 1 2 | 2 2 | bob | bob#cat.com
3 | 2 3 | 2 2 | bob | bob#dog.com
4 | 3 3 | joe | joe#dog.com
This fixes a lot of issues, now when you want to look up a user's name/email, you go look it up in a user table based off a userId. If adam changes his email, it changes for both tables (because they both refer to the user table).
There's still one more thing, if bob changes his name, we shouldn't have to look through the entire user table to change every occasion of his name. So we can take this one step further.
table_1 table_2 user email
ID_1 | userId ID_2 | userId userId | name userId | email
1 | 2 1 | 1 1 | adam 1 | adam#dog.com
2 | 1 2 | 2 2 | bob 2 | bob#cat.com
3 | 2 3 | 2 3 | joe 2 | bob#dog.com
4 | 3 3 | joe#dog.com
Now we have no pieces of information that are redundant, no need to duplicate values, and changes in any one place affects every other table that refers to it.

#remram: Thanks, it works. I tried directly with PhpMyAdmin.
Some small modification:
UPDATE table_2, table_1
SET table_2.`email` = table_1.`email`
WHERE table_1.`name` = table_2.`name`;
#HansZ: Thank you also for the DataBase Normalization explanation.
In this case, remram solution is what I was needing. I was looking for a kind of Fuzzy VLOOKUP in MySQL, and this would be a way to get what I want
http://denglishbi.wordpress.com/2011/05/15/microsoft-fuzzy-lookup-add-in-for-excel-2010-walkthrough/
And here a small Explanation: I have a list of words that needs to be translated. Some of those words are already in the Master, and the Slave database is empty... At the end, I just need to translate the empty values

Related

How to properly join two tables to use alternative ORDER BY

Two tables...
people (personid, name, mainordering)
entries (userid, personid, altordering)
"personid" is the common field. My app displays a draggable list users can move around. When done, they click to "lock" in their order.
Table : people
+----------+---------+--------------+
| personid | name | mainordering |
+----------+---------+--------------+
| 1 | Bob | 2 |
| 2 | Charlie | 4 |
| 3 | Jim | 1 |
| 4 | Doug | 3 |
+----------+---------+--------------+
So using mainordering, it would display:
Jim
Bob
Doug
Charlie
entries table might have (for user 16):
+--------+----------+-------------+
| userid | personid | altordering |
+--------+----------+-------------+
| 16 | 1 | 3 |
| 16 | 2 | 1 |
| 16 | 3 | 2 |
| 16 | 4 | 4 |
+--------+----------+-------------+
So if user 16 has already submitted his entry BUT NOT LOCKED IT IN, I want to display his list using altordering. i.e.
Charlie
Jim
Bob
Doug
I'm struggling with the proper join to use. Here is what I tried and isn't working (it's simply ordering by mainordering still)...
$sql = "SELECT * from entries
WHERE userid=".$_SESSION['userid']."
LEFT JOIN people ON entries.personid = people.personid
ORDER BY altordering";
Any thoughts would be much appreciated. Thank you...
Are you sure you don't get an error when using WHERE before JOIN?
It should work like this:
SELECT people.*
FROM people
JOIN entries ON entries.personid = people.personid
WHERE entries.userid={$_SESSION['userid']}
ORDER BY entries.altordering
I assume entries.personid will always have a matching person in people, so you should use an INNER JOIN. You would use FROM entries LEFT JOIN people if you wanted to retrieve altordering even for non-existing people.

MySQL query for two users with common responses to a survey

I have a MySQL table with users who have completed a survey - in some cases, they have complete the survey multiple times. So it looks like this:
users|survey_attempt|question_num|response
---------------------------------------------
john | 1 | 1 | cat
john | 1 | 2 | dog
john | 1 | 3 | frog
john | 2 | 1 | dog
john | 2 | 2 | frog
john | 2 | 3 | dog
jim | 1 | 1 | frog
jim | 1 | 2 | bat
jim | 1 | 3 | bat
jim | 2 | 1 | cat
jim | 2 | 2 | frog
jim | 2 | 3 | bat
In this case, how would I find users who had common responses within the same attempt at the survey? So for instance, if I wanted to know who answered "frog" and "cat" within a unique attempt at the survey (regardless of which specific question the answer was for)?
In general, the database layout has flaws. I would suggest to use unique survey submission IDs. Because right now, you need to check user name AND survey attempt to determine if two or more rows belong to the same submission.
Anyways, you would need to self join the table and check for the answer you want but disregard the question:
SELECT A.users, A.survey_attempt
FROM table A
INNER JOIN table B ON A.users = B.users AND A.survey_attempt = B.survey_attempt
WHERE A.response = 'frog'
AND B.response = 'cat';
The table is matched with itself, in each result table you'll have all columns two times. Then the query will only select these rows where both user names and survey attempt numbers are equal. Finally, the WHERE statement checks for the answers you wanted. Nowhere, the question number is checked as you wanted to get the result regardless of specific questions.

Update unique column of multiple rows , skip the duplicates

Here is my main table Contacts
ID | Name | Mobile
1 | Jai | 123
2 | Dave | 456
3 | Peter| 789
ID -> Primary Key Column
Mobile -> an unique column
I have a new update request. The data resides in another table (say table dummy).
ID | Name | Mobile
1 | Jai | 456
2 | Dave | 789
3 | Peter| 123
To update data from table dummy to Contacts, I can easily fire an update query by joining these two tables and update the Mobile of Contacts. But it is possible only if the data to be updated from Mobile column of dummy table is unique.
That is, if the dummy table content is like below,
ID | Name | Mobile | Status
1 | Jai | 789 |
2 | Dave | 456 |
3 | Peter| 456 |
In this case, I want to skip the rows 1 & 3 and update only the second row.
And I need to update the STATUS column (Skipped or Updated).
Is it possible by few queries?

How to store multiple values in single column where use less memory?

I have a table of users where 1 column stores user's "roles".
We can assign multiple roles to particular user.
Then I want to store role IDs in the "roles" column.
But how can I store multiple values into a single column to save memory in a way that is easy to use? For example, storing using a comma-delimited field is not easy and uses memory.
Any ideas?
If a user can have multiple roles, it is probably better to have a user_role table that stores this information. It is normalised, and will be much easier to query.
A table like:
user_id | role
--------+-----------------
1 | Admin
2 | User
2 | Admin
3 | User
3 | Author
Will allow you to query for all users with a particular role, such as SELECT user_id, user.name FROM user_role JOIN user WHERE role='Admin' rather than having to use string parsing to get details out of a column.
Amongst other things this will be faster, as you can index the columns properly and will take marginally more space than any solution that puts multiple values into a single column - which is antithetical to what relational databases are designed for.
The reason this shouldn't be stored is that it is inefficient, for the reason DCoder states on the comment to this answer. To check if a user has a role, every row of the user table will need to be scanned, and then the "roles" column will have to be scanned using string matching - regardless of how this action is exposed, the RMDBS will need to perform string operations to parse the content. These are very expensive operations, and not at all good database design.
If you need to have a single column, I would strongly suggest that you no longer have a technical problem, but a people management one. Adding additional tables to an existing database that is under development, should not be difficult. If this isn't something you are authorised to do, explain to why the extra table is needed to the right person - because munging multiple values into a single column is a bad, bad idea.
You can also use bitwise logic with MySQL. role_id must be in BASE 2 (0, 1, 2, 4, 8, 16, 32...)
role_id | label
--------+-----------------
1 | Admin
2 | User
4 | Author
user_id | name | role
--------+-----------------
1 | John | 1
2 | Steve | 3
3 | Jack | 6
Bitwise logic allows you to select all user roles
SELECT * FROM users WHERE role & 1
-- returns all Admin users
SELECT * FROM users WHERE role & 5
-- returns all users who are admin or Author because 5 = 1 + 4
SELECT * FROM users WHERE role & 6
-- returns all users who are User or Author because 6 = 2 + 4
From your question what I got,
Suppose, you have to table. one is "meal" table and another one is "combo_meal" table. Now I think you want to store multiple meal_id inside one combo_meal_id without separating coma[,]. And you said that it'll make your DB to more standard.
If I not getting wrong from your question then please read carefully my suggestion bellow. It may be help you.
First think is your concept is right. Definitely it'll give you more standard DB.
For this you have to create one more table [ example table: combo_meal_relation ] for referencing those two table data. May be one visible example will clear it.
meal table
+------+--------+-----------+---------+
| id | name | serving | price |
+------+--------+-----------+---------+
| 1 | soup1 | 2 person | 12.50 |
+------+--------+-----------+---------+
| 2 | soup2 | 2 person | 15.50 |
+------+--------+-----------+---------+
| 3 | soup3 | 2 person | 23.00 |
+------+--------+-----------+---------+
| 4 | drink1 | 2 person | 4.50 |
+------+--------+-----------+---------+
| 5 | drink2 | 2 person | 3.50 |
+------+--------+-----------+---------+
| 6 | drink3 | 2 person | 5.50 |
+------+--------+-----------+---------+
| 7 | frui1 | 2 person | 3.00 |
+------+--------+-----------+---------+
| 8 | fruit2 | 2 person | 3.50 |
+------+--------+-----------+---------+
| 9 | fruit3 | 2 person | 4.50 |
+------+--------+-----------+---------+
combo_meal table
+------+--------------+-----------+
| id | combo_name | serving |
+------+--------------+-----------+
| 1 | combo1 | 2 person |
+------+--------------+-----------+
| 2 | combo2 | 2 person |
+------+--------------+-----------+
| 4 | combo3 | 2 person |
+------+--------------+-----------+
combo_meal_relation
+------+--------------+-----------+
| id | combo_meal_id| meal_id |
+------+--------------+-----------+
| 1 | 1 | 1 |
+------+--------------+-----------+
| 2 | 1 | 2 |
+------+--------------+-----------+
| 3 | 1 | 3 |
+------+--------------+-----------+
| 4 | 2 | 4 |
+------+--------------+-----------+
| 5 | 2 | 2 |
+------+--------------+-----------+
| 6 | 2 | 7 |
+------+--------------+-----------+
When you search inside table then it'll generate faster result.
search query:
SELECT m.*
FROM combo_meal cm
JOIN meal m
ON m.id = cm.meal_id
WHERE cm.combo_id = 1
Hopefully you understand :)
You could do something like this
INSERT INTO table (id, roles) VALUES ('', '2,3,4');
Then to find it use FIND_IN_SET
As you might already know, storing multiple values in a cell goes against 1NF form. If youre fine with that, using a json column type is a great way and has good methods to query properly.
SELECT * FROM table_name
WHERE JSON_CONTAINS(column_name, '"value 2"', '$')
Will return any entry with json data like
[
"value",
"value 2",
"value 3"
]
Youre using json, so remember, youre query performance will go down the drain.

Data Entry Tracking (Database Design)

I have developed a website (PHP) that allow staffs to add records on to our system.
Staffs will be adding thousands of records into our database.
I need a way to keep track of what record have been done and the process/status of record.
Here a number of Teams I could think of:
Data Entry Team
Proof Reading Team
Admin Team
When staff (Data Entry Team) completed a record - he/she will then click on the Complete button. Then somehow it should asssign to 'Proof Reading Team' automatically.
A record need to be checked twice from a Proof Reading Team. If StaffB finish proof reading then another member from Proof Reading Team need to check it again.
When Proof reading is done, Admin Team will then assign "Record Completed"
In a few months later record might need to be updated (spelling mistake, price change, etc) - Admin might to assign record to Data entry team.
Is this good data entry management solution? How do I put this into Database Design perspective?
Here what I tried:
mysql> select * from records;
+----+------------+----------------------+
| id | name | address |
+----+------------+----------------------+
| 1 | Bill Gates | Text 1 Text Text 1 |
| 2 | Jobs Steve | Text 2 Text 2 Text 2 |
+----+------------+----------------------+
mysql> select * from staffs;
+----+-----------+-----------+---------------+
| id | username | password | group |
+----+-----------+-----------+---------------+
| 1 | admin1 | admin1 | admin |
| 2 | DEntryA | DEntryA | data_entry |
| 3 | DEntryB | DEntryB | data_entry |
| 4 | PReadingA | PReadingA | proof_reading |
| 5 | PReadingB | PReadingB | proof_reading |
+----+-----------+-----------+---------------+
mysql> select * from data_entry;
+----+------------+-----------+------------------------+
| id | records_id | staffs_id | record_status |
+----+------------+-----------+------------------------+
| 1 | 2 | 3 | data_entry_processiing |
| 2 | 2 | 3 | data_entry_completed |
| 3 | 2 | 4 | proof_read_processing |
| 4 | 2 | 4 | proof_read_completed |
| 5 | 2 | 5 | proof_read_processing |
| 6 | 2 | 5 | proof_read_completed |
+----+------------+-----------+------------------------+
Is there alternative better solution of database design?
i think design it's well done. but may be you want to separate group into groups table, and record_status into status table. If you're storing a lot of records you would store a lot of useless information, at least create an enum type for record_status field and group field
table: groups
id - name 1 - admin 2 - data_entry 3 - proof_reading
...
table: status
id - name 1 - data_entry_processing ...
and if you want the users to be in different groups at a time, you could create users_group table
table: user_groups
group_id - user_id 1 - 1 2 - 1 1 - 4 3 -
4 4 - 4 ....
Hope this helps