I looking at trying to create a database that has keys with multiple values.
For example the key would be "benchpress" and the values would be "chest", "deltoid", "shoulder" .
I would have a bunch of these keys and then want to search the values and return all of the keys that contain what I was searching for. for example if I searched for chest I would get benchpress and other exercises that had that value.
I was wondering if this is possible and what the best way to do this is. I assume that I will have to use MySql for this.
Thanks!
You're probably going to want three tables to do this. One to hold all of your exercises, one to hold all of your muscles, and one to relate exercises to their respective muscles. You can then query the third table to figure out what muscles any one exercise targets using a JOIN statement.
The benefit of having three tables versus two is that each exercise definition and muscle definition is independent, so any exercise can target multiple muscles and any muscle can be targeted by multiple exercises.
Schema:
table exercise
id (int255) | exerciseName (varchar255)
table muscles
id (int255) | muscleName (varchar255)
table exerciseTargets
exerciseId (int255) | muscleId (int255)
Keys:
exercise.id: primary
exercise.name: unique
muscles.id: primary
muscles.name: unique
exerciseTargets.exerciseId: foreign key on exercise.id
exerciseTargets.muscleId: foreign key on muscle.id
Example query:
SELECT muscleName FROM muscles INNER JOIN exerciseTargets ON exerciseTargets.muscleId = muscles.id WHERE exerciseTargets.exerciseId = :exerciseId;
(where :exerciseId is the ID of an exercise.)
One way to do this in MySql would be to have two separate tables -- one for "exercise" and one for the affected muscle groups. These would be joined by a shared "key" (MuscleID). To add a new exercise to a muscle group, you'd just add it to the Exercise table with the correct "MuscleID".
For example:
create table Exercise (MuscleID int, exercise varchar(50));
insert into Exercise values (1, "benchpress"),(2, "leg press");
create table Muscles (MuscleID int, muscles varchar(50));
insert into Muscles values (1, "chest"),(1, "deltoid"),(1, "shoulder"),(2, "thigh")
select *
from Exercise as E
inner join Muscles as M on M.MuscleID = E.MuscleID
where E.exercise = "benchpress"
Demo: http://sqlfiddle.com/#!2/19c9c/1
However, this might not be a flexible enough system for you. The answer by #matt617 would most likely be a better option for a more comprehensive setup, but if you're doing something simple, this might work for you.
I would suggest looking into something more like an Ontology or a generic Graph Dataset.
An ontology formally represents knowledge as a set of concepts within a domain, using a shared vocabulary to denote the types, properties and interrelationships of those concepts. Whereas a Graph is a more free form notion of relationships (like a social network). All ontologies are in essence a graph but not all graphs are ontologies.
An VERY overly example of an RDF using the N3 format (which is the most common format for software ontologies) would be:
#prefix : http://www.example.org/ .
:bicep a :muscle.
:tricep a :muscle .
:quadracep a :muscle
then you would have a separate RDF for exercises
#prefix : http://www.example.org/ .
:benchpress a :exercise.
then you can start mapping them together:
#prefix : http://www.example.org/ .
:benchpress :uses :bicep :pectorals
There is also an XML format. For more information a good sample site is here: http://www.rdfabout.com/quickintro.xpd
Infact I wouldn't be surprised if RDFs for muscle groups exist in the open domain I just haven't looked much for them.
If you are more of a programmer at heart than an information scientist type then Neo4J is a great Graph DB that lets you implement graphs without doing full ontologies. It uses a pretty handy query languge called Cypher which describes the relationships http://www.neo4j.org/learn/cypher
I am sure you could make a MySQL DB that was sufficient for your needs but it will be very hard to maintain depending on the long term of your application.
Related
Let's imagine we have two categories of publications - movies and books. Is it better to create one MySQL table for all publications or two different tables and unite them every time we show them in the united feed?
EDIT: The structure is little different. it has some common and uncommon data
Assuming both categories got the same attributes,
there is no difference in query performance (According to Multiple Table Select vs. JOIN (performance) )
In that case the solution with one table uses slightly more storage than the two table solution as you need a further column for differentiation (e.g. type).
EDIT
As your structure is different, you should use the two-table-solution as you get NULL fields if you use the one-table-solution.
A bad example for the table Publications:
In the given example you do not need an additional attribute to differentiate the two types because you could determine the type by Pages or Director.
You should avoid NULL values, especially when they are not meant to be filled with data in the future.
I have this problem in a table where there are 4 columns which include terms describing the product. I want to make this terms editable (and you can add more) in my app and there are 4 groups of them obviously. I created a table who has all these terms altogether but the product table will have to create 4 relationships with the ID of the terms table.
Is this a good solution?
The main reason I don't want to make 4 different tables for the terms is because there aren't many of them and as the app progresses we might have even more different term groups, thus adding many small tables cluttering the database.
Any suggestion?
Update #1: Here is my current schema http://i.imgur.com/q2a1ldk.png
Have a product table and a terms (product_id, terms_name, terms_description) which will allow you to add as many or as little terms for each product as you want. You just need to retrieve all terms from the terms table with a particular product id.
You could try a mapping table:
apputamenti(id, ...)
term_map (apputamenti_id, term_id)
terms (id, text, type)
So you can add as many terms as you want.
Or if you want to specify the mapping with one more field, change:
term_map (apputamenti_id, term_id, map_type)
so you can use an enum for map_type like enum(tipologia, feedback, target) or whatever your original fields where
I am not a pro in MySQL, but want to do something like Object Layer above relational MySQL tables.
I want to have very many "structures" with a fields of type "bigint", "longtext", "datetime", "double" stored in just 7 tables.
entity_types (et_id, et_name) - list of "structures";
entity_types_fields (etf_id, parent_et_id, ....., etf_ident, etf_type) - list of structure properties stored in one table for ALL structures; etf_type contains int value (0,1,2,3) which referenced to one of 4 tables described below.
entities (e_id, et_id) - list of all available entities (id and type id of entity)
and 4 data tables (containing all data for entities) -
entities_props_bigint (parent_e_id, parent_etf_id, ep_data) - for BIGINT data properties
entities_props_longtext (parent_e_id, parent_etf_id, ep_data) - for LONGTEXT data properties
entities_props_datetime (parent_e_id, parent_etf_id, ep_data) - for DATETIME data properties
entities_props_double (parent_e_id, parent_etf_id, ep_data) - for DOUBLE data properties
What the best way to do selection from such data layer ?
Let I have list of e_id (id of entities), each entity can have any type. I want to get predefined list of properties. If some of entities don't have such property, I want to have it equal to NULL.
Do you have some info about how to do it ? May be you have some links or have already deal with such things.
Thanks!
You're reinventing the wheel by implementing a whole metadata system on top of a relational database. Many developers have tried to do what you're doing and then use SQL to query it, as if it is relational data. But implementing a system of non-relational data and metadata in SQL is harder than you expect.
I've changed the relational tag of your question to eav, because your design is a variation of the Entity-Attribute-Value design. There's a limit of five tags in Stack Overflow. But you should be aware that your design is not relational.
A relational design necessarily has a fixed set of attributes for all instances of an entity. The right way to represent this in a relational database is with columns of a table. This allows you to give a name and a data type to each attribute, and to ensure that the same set of names and their data types apply to every row of the table.
What the best way to do selection from such data layer ?
The only scalable way to query your design is to fetch the attribute data and metadata as rows, and reconstruct your object in application code.
SELECT e.e_id, f.etf_ident, f.etf_type,
p0.ep_data AS data0,
p1.ep_data AS data1,
p2.ep_data AS data2,
p3.ep_data AS data3
FROM entities AS e
INNER JOIN entity_type_fields AS f ON e.et_id = f.parent_et_id
LEFT OUTER JOIN entities_props_bigint AS p0 ON (p0.parent_e_id,p0.parent_etf_id) = (e.e_id,f.etf_id)
LEFT OUTER JOIN entities_props_longtext AS p1 ON (p1.parent_e_id,p1.parent_etf_id) = (e.e_id,f.etf_id)
LEFT OUTER JOIN entities_props_datetime AS p2 ON (p2.parent_e_id,p2.parent_etf_id) = (e.e_id,f.etf_id)
LEFT OUTER JOIN entities_props_double AS p3 ON (p3.parent_e_id,p3.parent_etf_id) = (e.e_id,f.etf_id)
In the query above, each entity field should match at most one property, and the other data columns will be null. If all four data columns are null, then the entity field is missing.
Re your comment, okay now I understand better what you are trying to do. You have a collection of entity instances in a tree, but each instance may be a different type.
Here's how I would design it:
Store any attributes that all your entity subtypes have in common in a sort of super-type table.
entities(e_id,entity_type,name,date_created,creator,sku, etc.)
Store any attributes specific to an entity sub-type in their own table, as in Martin Fowler's Class Table Inheritance design.
entity_books(e_id,isbn,pages,publisher,volumes, etc.)
entity_videos(e_id,format,region,discs, etc.)
entity_socks(e_id,fabric,size,color, etc.)
Use the Closure Table design to model the hierarchy of objects.
entity_paths(ancestor_e_id, descendant_e_id, path_length)
For more information on Class Table Inheritance and Closure Table, see my presentations Practical Object-Oriented Models in SQL and Models for Hierarchical Data in SQL, or my book SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming, or Martin Fowler's book Patterns of Enterprise Application Architecture.
I am working on a reviews website. Basically you can choose a location and business type and optionally filter your search results by various business attribures. There are five tables at play here:
Businesses
ID
Name
LocationID
Locations
LocationID
LocationName
State
Attributes
AttributeID
AttributeName
AttributeValues
AttributeValueID
ParentAttributeID
AttributeValue
BusinessAttributes
ID
AttributeID
AttributeValueID
So what I need is to work out the query to use (joins?) to get a business in a particular location based on attribute values.
For example, I want to find a barber in Santa Monica with these attributes:
Price: Cheap
Open Weekends: Yes
Cuts Womens Hair: Yes
These attributes are stored in the Attributes and AttributeValues tables and are linked to the business in the BusinessAttributes table.
So let's say I have these details from the search form:
LocationID=5&Price=Cheap&Open_Weekends=Yes&Customs_Womens_Hair=Yes
I need to build the query to return the businesses that match this location and attributes.
Thank you in advance for your help and I think StackOverflow is awesome.
Thinking about your data needs, you may be a perfect candidate for a schema-free document oriented database. On a recent episode of .Net Rocks (link to show), Michael Dirolf talked about his project MongoDB.
From what I understand, you could take each Business entity and store it in the database with all its associated attributes (LocationID, Price, Open_Weekends, Customs_Womens_Hair, Etc.). Each entity stored in the store can have different combinations of attributes because there is no schema. This natively accomplishes what you are trying to do with an Attribute and Attribute_Value table.
To search the database, just ask it for all entities that have the particular set of keys and values you need. No complex joins and no loss of performance. What you are doing is exactly what schema-free, document based databases are designed for.
Michael Dirolf: Yes, I think that a lot of the people who are switching are people who have sort of got themselves into corners where they are using relational database the way that we use MongoDB.
Richard Campbell: Right.
Michael Dirolf: So having columns that, a column key and a separate column value and inserting stuff that way so that they get done in schema and all sorts of crazy stuff like that…
Richard Campbell: Yeah, now in reflection I suddenly realized I just describe your perfect customer, a guy who has taken, you know, abusing SQL Server as they say. We’re going down this funny path and you just shouldn’t be here in the first place.
If you keep going down the path of building a relational attribute/value store, your performance will suffer with the combonatoric explosion that results.
Im trying to use to define a one-to-many relationship in a single table. For example lets say I have a Groups table with these entries:
Group:
Group_1:
name: Atlantic Records
Group_2:
name: Capital Records
Group_3:
name: Gnarls Barkley
Group_4:
name: Death Cab For Cutie
Group_5:
name: Coldplay
Group_6:
name: Management Company
The group Coldplay could be a child of the group Capital Records and a child of the group Management Company and Gnarls Barkley could only be a child of Atlantic Records.
What is the best way to represent this relationship. I am using PHP and mySQL. Also I am using PHP-Doctrine as my ORM if that helps.
I was thinking that I would need to create a linking table called group_groups that would have 2 columns. owner_id and group_id. However i'm not sure if that is best way to do this.
Any insight would be appreciated. Let me know if I explained my problem good enough.
There are a number of possible issues with this approach, but with a minimal understanding of the requirements, here goes:
There appear to be really three 'entities' here: Artist/Band, Label/Recording Co. and Management Co.
Artists/Bands can have a Label/Recording CO
Artists/Bands can have a Management Co.
Label/Recording Co can have multiple Artists/Bands
Management Co can have multiple Artists/Bands
So there are one-to-many relationships between Recording Co and Artists and between Management Co and Artists.
Record each entity only once, in its own table, with a unique ID.
Put the key of the "one" in each instance of the "many" - in this case, Artist/Band would have both a Recording Co ID and a Management Co ID
Then your query will ultimately join Artist, Recording Co and Management Co.
With this structure, you don't need intersection tables, there is a clear separation of "entities" and the query is relatively simple.
A couple of options:
Easiest: If each group can only have one parent, then you just need a "ParentID" field in the main table.
If relationships can be more complex than that, then yes, you'd need some sort of linking table. Maybe even a "relationship type" column to define what kind of relationship between the two groups.
In this particular instance, you would be wise to follow Ken G's advice, since it does indeed appear that you are modeling three separate entities in one table.
In general, it is possible that this could come up -- If you had a "person" table and were modeling who everybody's friends were, for a contrived example.
In this case, you would indeed have a "linking" or associative or marriage table to manage those relationships.
I agree with Ken G and JohnMcG that you should separate Management and Labels. However they may be forgetting that a band can have multiple managers and/or multiple managers over a period of time. In that case you would need a many to many relationship.
management has many bands
band has many management
label has many bands
band has many labels
In that case your orginal idea of using a relationship table is correct. That is home many-to-many relationships are done. However, group_groups could be named better.
Ultimately it will depend on your requirements. For instance if you're storing CD titles then perhaps you would rather attach labels to a particular CD rather than a band.
This does appear to be a conflation of STI (single-table inheritance) and nested sets / tree structures. Nested set/trees are one parent to multiple children:
http://jgeewax.wordpress.com/2006/07/18/hierarchical-data-side-note/
http://www.dbmsmag.com/9603d06.html
http://www.sitepoint.com/article/hierarchical-data-database
I think best of all is to use NestedSet
http://www.doctrine-project.org/documentation/manual/1_0/en/hierarchical-data#nested-set
Just set actAs NestedSet
Yes, you would need a bridge that contained the fields you described. However, I would think your table should be split if it is following the same type of entities as you describe.
(I am assuming there is an id column which can be used for references).
You can add a column called parent_id (allow nulls) and store the id of the parent group in it. Then you can join using sql like: "Select a., b. from group parent join group child on parent.id = child.parent_id".
I do recommend using a separate table for this link because:
1. You cannot support multiple parents with a field. You have to use a separate table.
2. Import/Export/Delete is way more difficult with a field in the table because you may run into key conflicts. For example, if you try to import data, you need to make sure that you first import the parents and then children. With a separate table, you can import all groups and then all relationships without worrying about the actual order of the data.