I have three entities in a MySQL based web application - Customer, Service and Note. Each customer can have multiple notes posted by different users. Similarly a Service can also have multiple notes. I would like to store all the notes in a single table for easy retrieval. Basically, there are lots of querying than insert/update to these tables.
The following is the database schema:
Table: Customer
id - integer
name - varchar
status - varchar
Table: Service
id - integer
name - varchar
status - varchar
price - float
Table: Note
id - integer
note - text
author - integer
type - varchar
cdate - datetime
I have prepared two approaches for establishing the relationship between these tables:
Approach #1
Table: CustomerNote
id - integer
customer_id - integer (References Customer table)
note_id - integer (References Note table)
Table: ServiceNote
id - integer
service_id - integer (References Service table)
note_id - integer (References Note table)
The second approach is to modify the Note table to save the Entity Name and ID of the record. This approach doesn't use the relations mentioned in approach #1
Approach #2
Table: Note
id - integer
note - text
author - integer
type - varchar
cdate - datetime
entity - varchar (possible values are Customer and Service)
entity_id - integer (related to id in the corresponding entity)
The second approach doesn't need any extra tables, but it's not easy to enforce foreign key relationship. As I said earlier, there are more querying than insert/update. So in that case which one would be more ideal and efficient approach?
I would also like to know if there are any performance issues if we implement a strict foreign key relationship.
Second approach is better in anyways with an index added to type field.
It will be better if you can convert type to an integer filed to represent these values . like 1 for Seevice and 2 for Customent. Will be faster if you use integer. But in any case, this approach will not satisfy your enforce foreign key.
Related
I want to create a database structure that can store data about families (primary key, name and its members).
I came up with the idea of doing it using these two tables:
TABLE "family":
- id (INT)
- name (VARCHAR)
- members (?)
TABLE "members"
- id (INT)
- name (VARCHAR)
I would like to reference members of the family by the id in the members table. But since MySQL doesn't have arrays, how am I supposed to store multiple members in one column? Or are there better DB structures for this case?
Kenta1561
Don't try to store multiple value in a single cell as arrays. It'll be nightmare for you later when you have to search rows based on one of the value in those arrays or join table with that column and other operations of the sort.
You can create a separate mapping table for that to keeps the things normalized.
You can create a separate table family_members with, say, three columns:
id (auto increment),
family_id (FK to family table),
member_id (FK to members table)
Or have an extra column in the members table as FK to family table if there is one to many mapping.
The mapping table helps if there can be many to many mappings.
Create Foreign key to Member_Id in tblFamily table
TABLE "tblFamily":
- Fam_Id (INT)
- Family_Name (VARCHAR)
- Member_Id (INT)
Create Primary key to Member_Id in tblMember
TABLE "tblMembers"
- Member_Id (INT)
- Member_Name (VARCHAR)
You can try below structure :
Table "Family"
- FAMILY_ID INT (PK)
- FAMILY_NAME VARCHAR
Now as your family can have multiple members, so instead of storing member_id in family table, it will be good to store FAMILY_ID in MEMBERS table.
Table "Member"
- MEMBER_ID INT (PK)
- MEMBER_NAME VARCHAR
- FAMILY_ID INT (FK) REFERENCES FAMILY.FAMILY_ID
This way you will be able to store multiple members for a family and using join on these tables will be able to print all information about the family in single query.
I have this design.
Table models:
id - primary key
title - varchar(256)
Table model_instances:
id - primary key
model_id - foreign key to app_models.id
title - varchar(256)
Table model_fields:
id - pk
model_id - foreign key to models.id
instance_id - foreign key to model_instances.id
title - name of the field
type - enum [text, checkbox, radio, select, 'etc']
Table model_field_values:
instance_id - forein key model_instance.id
field_id - foreign key to model_fields.id
value - text
Also there can be many values for some field (like for multiple select dropdown)
The problem is: value is always text field, because I want to store different types of data (text, datetime, integer) and this table contains all values for all instances of all models.
For example, if I have 10 models and every model has 1000 instances with 10 fields then model_field_values (at minimum) would contain 100000 rows, if some fields are multiple, then it would contain (120000-150000 rows).
SQL's select using value field would be slow.
Solution 1:
For every model create new model_field_values like:
model.id = 1, model_field_values_1
...
model.id = 10, model_field_values_10
Solution 2:
Because model_fields contains all fields for model, we can create model_field_values like this
model_fields for model.id=1 (by primary key): 1 - text, 2 - integer, 3 - datetime, 4 - smalltext
Fields for model_field_values_1: field_1 text, field_2 integer, field_3 datetime, field_4 varchar(256)
This solution is not good for fields with multiple values, because every multiple value should have another table with link to the row in model_field_values_1, but it is good for searching through database because mysql would use native datatypes in where clauses (not text fields).
May be I miss something? May be there is a better design?
This database would be used in crm-system, where user can create different model with many instances in these models, so I can not preconfigure all tables with all columns.
Note: 200,000 rows (two tenths of a megarow) is, in the usual operation of MySQL, a medium sized table. It's generally possible to index such a table fairly efficiently. http://use-the-index-luke.com/
That being said, I think I understand your problem. It is, in the jargon of object-oriented design, polymorphism.
You have this model_field_value table, containing
instance_id
field_id
value
Your problem is, the value's native data type is sometimes VARCHAR(255), sometimes DATETIME or maybe TIMESTAMP, and sometimes INT.
And you'll sometimes need to do queries like this one
SELECT fv.instance_id
FROM model_field_value fv
WHERE fv.field_id = something
AND fv.value >= '2017-01-01'
AND fv.value < '2018-01-01'
to find DATETIME values that happened in calendar year 2017. For example.
This is generally a pain in the neck with key/value storage like what you need. For a query like my example to be sargable, you need to be able to put an index on a DATETIME column. But if you don't have such a column, you can't index it. Duh.
Here's a suggestion. Give your table these columns.
instance_id INT pk fk
field_id INT pk fk
value VARCHAR(255) a text representation of every value.
value_double DOUBLE a numeric representation of every numeric value, or NULL
value_ts TIMESTAMP a timestamp value if possible, or NULL
This table will contain redundant data, and you'll have to be very careful when you're writing it to make sure it's correct. But you will be able to put indexes on the value_ts and value_double columns, so you can make those kinds of queries sargable.
Just an idea.
In a relational supertype/subtype structure where, for example, I have a supertype table entity with an entity_type column and a number of subtype tables, is there any way I can go about querying all entities with their full records, that is somehow joining to each of the subtype tables automatically?
So, with:
TABLE entity
-- entity_id (INT pk)
-- entity_type_id (INT fk)
TABLE entity_type
-- entity_type_id (INT pk)
-- name //Person, Building, Animal (TEXT)
TABLE person
-- entity_id (INT fk)
-- person_name (TEXT)
-- person_age (INT)
TABLE building
-- entity_id (INT fk)
-- age_built (INT)
etc.
what if I wanted to query all entities, and in my result set get all person-specific columns (person_name, etc.) if the record was a person and age_built, etc. if the record was a building? I thought about storing the subtype table names in the type table but understand you can't dynamically reference those like that.
Am I being an ignorant DB newb here or is this in any way possible without explicitly defining the join and doing a query for each subtype table?
I'm asking this because elsewhere in my DB I'm going to have a lot of references to an entity_id (that could be any kind of entity) and I don't want to run an initial query to just to check its type first.
Working in MySQL, no preference to engine.
Don't do this unless you really know what you are doing (and then probably don't do it!). This fits into the entity attribute value anitpattern. Better to model out the entities which relate to each person/animal/building separately.
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:2314483800346542969
Either that or you could consider having multiple fk columns from entity type to the linked entities. How many entities are you expecting to reference entity_type?
Maybe a newbie question about foreign keys, but I want to know the answer.
Let's say I have 2 tables:
products
--------
product_id (int)
name (unique) (varchar)
description (text)
vendor (varchar) (foreign key: vendors.name)
AND
vendors
--------
name (varchar)
I know that I should use a vendor_id (int), but this is just an example to help me ask my question.
So: if I create vendor: Apple, and product: 1, iPhone 4, Description.., Apple then the varchar "Apple" will be stored both in products and vendors, or just in vendors (because of the foreign key)?
Is this a wrong db design?
This is called "normalization" in the database. In your example, there are a couple things to consider:
In order for products to have a foreign key to vendors, vendors needs a key. Is name the primary key for vendors? If so, then the foreign key would also be a varchar. In that case, yes, the value "Apple" would be stored in both. (Note that this isn't a very good idea.)
If you add a vendor_id integer column to the vendors table, and it is the primary key for that table, then you can add a vendor_id (or any other name) column to the products table and make it a foreign key to the vendors table. In this case, only that integer would be stored in both tables. This is where the data becomes normalized. A small, simpler data type (integer) links the tables, which contain the actual data which describes the records.
Only that key value is stored in both tables. It's used as a reference to join the tables when selecting data. For example, in order to select a given product and its vendor, you'd do something like this:
SELECT products.name, products.description, vendors.name AS vendor
FROM products INNER JOIN vendors ON products.vendor_id = vendors.vendor_id
WHERE products.product_id = ?id
This would "join" the two tables into a single table (not really, just for the query) and select the record from it.
It will be stored in both. The foreign-key constraint requires that every value in products.vendor appear somewhere in vendor.name.
(By the way, note that MySQL only enforces foreign-key constraints if the storage engine is InnoDB.)
I have to save this information in a database
Person -> is married to -> Person
Where should I save that information? What is the proper design pattern should I apply here?
Thank you!
If you can only be maried to one person: 1:1
-------------
- Person -
-------------
id (key)
maried_to_id (foreign key)
If you can be maried to more than one person or want to keep track of previous mariages, n:n
-------------
- Person -
-------------
person_id (key)
-------------
- Mariage -
-------------
first_person_id (foreign key)
second_person_id (foreign key)
start_date
end_date
(also first_person_id + second_person_id + date form a unique key for mariage. You could leave out the date, but then remariages wouldnt be tracked)
Here is a hypothetical schema you can use. All people are in a single table, and each person has a unique id. Marriages are in a relationship table, with foreign keys.
PERSONS
- ID - INTEGER, PK
- FIRSTNAME - VARCHAR(20)
- LASTNAME - VARCHAR(20)
- SEX - CHAR(1)
- ... any other fields
MARRIAGES
- PERSON1_ID - INTEGER, FK
- PERSON2_ID - INTEGER, FK
- MARRIAGE_DATE - DATE
- ANULLMENT_DATE - DATE
- ... any other fields
This is a great question for teaching schema design. What seems like a simple problem can easily become quite complicated:
E.g., how to handle:
- mariages of more than two people
- different types of marriage (legal, religious, other)
- concurrent marriages
- repeat marriages
- divorce
- self-marriage (hey, it happend on Glee!)
The trick, if there is one, is to carefully think out all the permutations of what you are trying to model. Only then do you actually go ahead and model it.
I would recommend Following structure
Lets say table name is Person.
PersonId (int, Key)
MarriedTo (int,
nullable)
.....
No need to create foreign key relation ship.
This sounds like a use for a simple lookup table- the important part is having two fields, one a foreign key for Person1's ID field the other a foreign key for Person2's ID field. Any details about the marriage ( dates, whether it is still current and so on ) would also be stored in this table.
That would facilitate people having had multiple marriages, polygamous relationships and so on. If you want a simple 1:1 relationship you could just include a foreign key reference to the spouse in the person field, but it would be considerably less flexible.
You could do it with a "Spouse" column on the "Person" table which can be null (for the case of an unmarried person).
If married this holds the id of the other person, as is a foreign key.
A better solution would be a separate "Marriage" table that has at least three columns:
MarriageId
Person1Id
Person2Id
...
The person id's are foreign keys into the "Person" table, and you should make the combination of MarriageId, Person1Id and Person2Id unique to avoid adding a row where the people are swapped over.
Though it should be pointed out that both these models are quite basic and make assumptions about how many people can be in one marriage ;)