Designing database: Linking lots of values between tables - mysql

Not worded my question very well, but with these tables:
USER TABLE ANIMALS
u_id username a_id animal
-------------------------- ---------------------------
2 alice 1 cat
4 brian 2 small dog
7 carla 3 big dog
4 rabbit
5 guinea pig
etc.
I want a user to be able to add however many animals they own to their profile.
What new tables/fields and datatypes would be the best way for me to go about this?
Thank you.

If you need to allow multiple types of the same animal per user (Janet can have more than one Rabbit) then do the following. Make UserId and AnimalID your primary key.
I would just do
UserAnimals
------------
UserId
AnimalID
Filled with data your table might look like this:
UserAnimals
------------
UserId || AnimalId
4 || 3
4 || 2
7 || 4
Brian has a small dog and a big dog. Carla has a rabbit.

Essentially you need a table which will map user ids to animal ids.
If you want to add them 1 at a time, you could just use a table like so:
UserAnimals
-----------
UserID (fk to User Table)
AnimalId (fk to Animal Table)
Assuming they might own, say 3 dogs, and you want to track the number, you could either have a row per animal or you could modify the table to include a count of the animals of each type:
UserAnimals
-----------
UserID
AnimalID
Count
I'd probably do it that way if I knew that there was a good chance that folks would have multiples of a given animal, otherwise there's a little more work to do whenever retrieval takes place to arrive at a total.
I guess one could make the argument that the ID field isn't absolutely necessary for the animals either. It could just be a lookup table of strings, though that requires a bit more space for storage and complicates things a little bit if you decide that you want to modify animal names for some reason.

I would recommend you many to many relationship table.
Example:
table: users_x_animals
-----------------------
pid | u_id | a_id
1 2 3
2 4 5
3 2 5
4 7 1
5 4 2
This way if you have index (separate) on u_id and a_id you can either query for "animal with id X is owned by users" or the other way around "user with id x owns these animals".
Hope that helps. :)

Related

Look for MySQL table structure recommendation

I have two table now:
conference table: id, name
people table: people_id, name
what I want to do
I want to make a new table so that I can get all attend people by conference id but also get all conference a specific man attended by people_id.
what I have thought
make a new table whose columns is all the people's id, and insert each conference as row, if the people shows in conference, we make it 1, otherwise 0. But it's too sparse and difficult to show which people attend a specific conference because we have many columns.
UPDATE
thanks for your comment. Now I create a table like this:
I think it's much better than the table before.
How about this?
A join table called conferences_people.
cp_id | conference_id | people_id
-------+---------------+-----------
1 | 1234 | 1
2 | 1234 | 4
3 | 1234 | 5

How to design one user "likes" another?

I would imagine this is kind of like friends, but doesn't need to be two-way. So like this:
from_user to_user
-------------------
John Mary
Mary John
John Susan
Mary Dave
I was curious if there were any issues with doing it as shown below.
user1 user2 mutuality
--------------------------------
John Mary 2
John Susan 1
Mary Dave 1
The second seems like it would have more complicated queries and checks, but wouldn't it end up saving space? For example, if Susan ends up falling for John one day, you'd check user2 for Susan and user1 for John. If it exists, update the mutuality to 2. If not, insert a new row [Susan, John, 1]. Something like that?
What's the best way of doing this?
I would choose the first method. You will not end up saving enough space with the second method to be an issue. Since each choice (like) is an action, having a separate record to store that action matches the work flow. John likes Mary, add a record. Mary likes John, add another record. Mary no longer likes John, delete that single record. This is easier to maintain (for me). I find keeping things in smaller granular parts keeps it simple.
In terms of design, I would recommend that instead of using string names in the likes table, you should have a users table with each user have a primary key id (unique). This way, users can modify names without breaking the relationships.
The table data would look like this:
Users table
id Name
1 John
2 Mary
3 Susan
4 Dave
Likes table
From To
1 2
2 1
1 3
2 4
The tables would have the following structure
users
-----
id (integer autoincrement)
name (varchar)
likes
-----
id (integer autoincrement)
fromid (integer)
toid (integer)
The sql would look like this to produce the list
SELECT f.name as fromName, t.name as toName
FROM (likes JOIN users AS f ON likes.fromid = f.id)
JOIN users AS t ON likes.toid = t.id;
The second method allows the following anomaly:
user1 user2 mutuality
--------------------------------
John Mary 2
Mary John 1
Do John and Mary like each other mutually (as implied by the first row), or just Mary likes John uni-directionally (as implied by the second row)?
The first method doesn't suffer from such inconsistencies, and data integrity is generally more important than saving some space.
BTW, if you introduce an integer surrogate key and reference it from the junction table (instead of the actual names), the junction table will become much leaner, negating much of the space advantage of the second method.

MySQL query get column value similar to given

Sorry if my question seems unclear, I'll try to explain.
I have a column in a row, for example /1/3/5/8/42/239/, let's say I would like to find a similar one where there is as many corresponding "ids" as possible.
Example:
| My Column |
#1 | /1/3/7/2/4/ |
#2 | /1/5/7/2/4/ |
#3 | /1/3/6/8/4/ |
Now, by running the query on #1 I would like to get row #2 as it's the most similar. Is there any way to do it or it's just my fantasy? Thanks for your time.
EDIT:
As suggested I'm expanding my question. This column represents favourite artist of an user from a music site. I'm searching them like thisMyColumn LIKE '%/ID/%' and remove by replacing /ID/ with /
Since you did not provice really much info about your data I have to fill the gaps with my guesses.
So you have a users table
users table
-----------
id
name
other_stuff
And you like to store which artists are favorites of a user. So you must have an artists table
artists table
-------------
id
name
other_stuff
And to relate you can add another table called favorites
favorites table
---------------
user_id
artist_id
In that table you add a record for every artist that a user likes.
Example data
users
id | name
1 | tom
2 | john
artists
id | name
1 | michael jackson
2 | madonna
3 | deep purple
favorites
user_id | artist_id
1 | 1
1 | 3
2 | 2
To select the favorites of user tom for instance you can do
select a.name
from artists a
join favorites f on f.artist_id = a.id
join users u on f.user_id = u.id
where u.name = 'tom'
And if you add proper indexing to your table then this is really fast!
Problem is you're storing this in a really, really awkward way.
I'm guessing you have to deal with an arbitrary number of values. You have two options:
Store the multiple ID's in a blob object in JSON format. While MySQL doesn't have JSON functions built in, there are user defined functions that will extract values for you, etc.
See: http://blog.ulf-wendel.de/2013/mysql-5-7-sql-functions-for-json-udf/
Alternatively, switch to PostGres
Add as many columns to your table as the maximum number of ID's you expect to have. So if /1/3/7/2/4/8/ is the longest entry, have 6 columns in your table. Reason this is bad: you'll have sparse columns that'll unnecessarily slow your tables.
I'm sure you could write some horrific regex to accomplish the task, but I caution on using complex regex's on enormous tables.

Using row values from one table to determine fields to select from another table in MySQL

I have multiple tables in a MySQL database, and I would like to be able to use row values from one table as the columns to select from another table. For instance, suppose that my tables description and information were as follows:
-------------
| description |
-------------
id colalias privacy
-- -------- -------
1 fname 3
2 lname 3
3 salary 2
4 empid 1
-------------
| information |
-------------
id fname lname salary empid
-- ----- ----- ------ -----
1 Bob White 50000 12345
2 Tom Black 75000 54321
3 Sue Green 82000 67890
4 Ann Brown 63000 09876
Suppose that I want to return a table that pulls all data from information where the description.privacy is equal to 3. So I'd like to have an output of
fname lname
----- -----
Bob White
Tom Black
Sue Green
Ann Brown
since only the fname and lname fields have that privacy level. I'm not an expert in writing SQL queries, and I have no control over the existing database design. If this is an obvious thing to do, I apologize for being ignorant of it, but I would truly appreciate some guidance.
You are actually really hampered here by your data model, the link between privacy level and data should be best modelled in tables by data alone, not by linking data (privacy level) to structure (field names).
Do you have any scope at all to change the data model, even if only adding in new stuff (i.e. not changing/removing existing model)?
What you're trying isn't impossible, but it's much harder work...
Edit - quick example of using dynamic SQL:
http://forums.mysql.com/read.php?60,27979,30437
Edit - example of a data model that would help, albeit it is a big refactor to what you're perhaps working with, so the dynamic SQL route might be more practical...
field_name field_security_level user_id user_emp_id field_value
---------- -------------------- ------- ----------- -----------
fname 3 1 12345 Bob
lname 3 1 12345 White
UPDATE - NEW ANSWER
After #Brian commenting I have realized that per my comment below, a mySQL subquery is likely going to do the trick allowing you to query based on a previous result.
There is a fairly good overview on them at RoseIndia.net that will give you a good start.
OLD ANSWER
You're most likely looking for a LEFT JOIN to achieve this.
I'm assuming that the id columns are related to each other to start with. Personally I would have 2 separate primary keys and then relate 1 table to the other using a foreign key but moving on.
I would suggest you check out KeithJBrown.co.uk that has a good explanation and some good examples of different types of joins.
Finally, to only get the columns you want, you simply specify them as SELECT information.fname, information.lname in the SQL statement.
I hope this helps you get on the right track, also, next time do a bit of research with Google first, try a few things then when you get stuck ask for help.

MYSQL - SImple database design

I would like to develop a system, where user will get the data dynamically(what I mean dynamic is, without reloading pages, using AJAX.. but well, it does not matter much).
My situation is like this. I have this table, I called it "player", in this player table, I will store the player information like, player name, level, experience etc.
Each player can have different clothes, start from tops(shirts), bottoms, shoes, and hairstyle, and each player can have more than 1 tops, bottoms, shoes etc.
What I am hesitated or not very sure about is, how do you normally store the data? My current design is like this:
Player Table
===========================================================================================
id | name | (others player's info) | wearing | tops | bottoms
===========================================================================================
1 | player1 | | top=1;bottom=2;shoes=5;hair=8 | 1,2,3| 7,2,3
Tops Table
=====================
id | name | etc...
=====================
1 | t-shirt | ...
I am not sure if this design is good. If you are the database designer, how would you design the database? Or how you will store them?
Please advise.
Thanks
In short: instead of putting the column "wearing" in, you should make a table that connects the 2 tables (players and clothes.)
You'd get
players
id name
1 player1
clotheTypes
1 top
2 bottom
clothes
id name type
1 shirt1 1
2 shirt2 1
3 pants1 2
wearing
playerId ClotheId
1 1
1 2
But please, do read the article taht #badcat shared!
edit: as requested, some hints:
You don't want this generally:
id name computer
1 john work, laptop, desktop, oldcomputer
Because you that should be in a seperate table. Now you can actually add, later on, the brand and speed of the computers: you can't the way you're doing it right now.
Person
id name
1 john
computer
id name owner
1 work 1
2 laptop 1
3 desktop 1
....
Seems like you are new to this.
Please read this article on Wikipedia about database normalization:
http://en.wikipedia.org/wiki/Database_normalization
Personally I would not do it like in the example above, because you'd have to update the players' table every time some T-Shirt is added or removed.
You need to create an additional tables for clothes, something like this:
player
id_player //1
name //Jhon
level //6
experience //13
player_cloth
id_player //1
id_clothe //5
cloth_types
id_cloth // 5
type // hat
description // very warm
Once you have created the tables you need to relate this data, you only need the id_player value.