MySQL: several parents identifying their children from one table - mysql

I am designing a data model for tourism-site. I have a table for places (countries, resorts, hotels) and a table for tours. The tables are pretty different in fields so the cant be merged into one. Both of them have usual auto_increment as id. Places and tours have photos so there is a third table for photos. This table has 'parent' field in which I plan to store the parent (place or tour) id.
Which is the best way to design these tables? One table for all photos and two tables as 'parents' for the photos. For now I have added 'parent_type' column to photos table, so when my script displays a tour it calls photos by its (parent) id and type (parent_type) 'tour' from the photos table...
Upd:
Is there a more graceful solution? With just 3 tables and no 'parent_type' column?
(cant post a diagram... here's the link http://share.xmind.net/yentsun/tourism-site-data-model/)

Country, hotel and resort are sub-type of a place. The place table contains all fields common to places, while country, hotel and resort tables contain fields specific to each one. One tour contains many places, one place can be a part of many tours.
Here is example code for Place and Country -- it is T-SQL, but you'll get the idea.
CREATE TABLE Place
(
PlaceID int NOT NULL ,
Type varchar(2)
);
ALTER TABLE Place
ADD CONSTRAINT PK_Place PRIMARY KEY CLUSTERED (PlaceID ASC)
;
ALTER TABLE Place
ADD CONSTRAINT FK1_Place FOREIGN KEY (ParentID) REFERENCES Place(PlaceID)
;
CREATE TABLE Country
(
PlaceID int NOT NULL
);
ALTER TABLE Country
ADD CONSTRAINT PK_Country PRIMARY KEY CLUSTERED (PlaceID ASC)
;
ALTER TABLE Country
ADD CONSTRAINT FK1_Country FOREIGN KEY (PlaceID) REFERENCES Place(PlaceID)
ON DELETE CASCADE
ON UPDATE CASCADE
;
UPDATE after comment
Sorry, four tables is my best for this one.

There are no Parents involved - you just have photos with two atttributes - Place and Tour.
So use a Photos table with two foreign keys, one for Tour, the other for Place. And then of course
a Tours table and a Places table.
If you need to know which Tours went to which Places, deal with it directly with a Tour_Places table
which justifies itself independently.
As for "Parentness", this solution still lets you identify, for a Tour (or Place), which Photos are associated.

I had the same situation a while ago. I used a 'set' type for the parent_type. Never store names for your type, use integers because they can be read much faster. And also place indexes on your foreign keys.

Related

Creating a table but with other entities in a compound key?

I have 2 Primary key tables and 1 Compound table.
I want to have some other information apart from the 2 primary keys from the primary key table in the compound table.
Would I just repeat this data or is their a way to add other fields into a the compound field without repeating it?
Thanks.
Your current design looks close to right. But I think your EventVolunteer table should look like this:
CREATE TABLE EventVolunteer (
eventID INTEGER,
volunteerID INTEGER,
FOREIGN KEY eventID REFERENCES Event(eventID),
FOREIGN KEY volunteerID REFERENCES Volunteer(volunteerID),
PRIMARY_KEY(eventID, volunteerID)
)
This bridge table should exist to store relationships between events and their volunteers, and nothing else. All metadata for events and volunteers should be in the Event and Volunteer tables, respectively.
If you need to bring in some information, then you can do so via joining the Event and Volunteer tables with this bridge table. This join is much less of a penalty than you might think, if you have indices setup in the right places.

Same primary key as Foreign Key for two different tables

I want to make three tables i.e Provinces, Languages, and Cities.
My Provinces and Cities use Languages. So I made join tables i.e Provinces_Languages and Cities_Languages. All tables contains id and name as columns.
Provinces
id
name
Languages
id
name
Provinces_Languages
province_id
languages_id
Foreign Keys
Similarly for cities:
Cities
id
name
Using same Languages Table
Cities_Languages
cities_id
languages_id
Foreign Keys
However, it can't use the same primary key from language the table. I am getting this error:
How i can resolve this?
Thanks in advance
You already have a constraint called FK_Language. Use a different name
FK_Language exists already when you try to create it again.
You should create separate alter table statements, making sure that the FK get's dropped before you create it again.
Basically: You try to drop the FK and create it again at the same time, that won't work.
By the way, you should be consistent on whether to use Cities_Languages or langauges_cities.

Weak entity on mysql with no primary key

I have a question about transfering a weak entity from an e-r model to sql tables.
Specifically i am using mysql.
Lets say i have the table hotels in which i have primary key id for each hotel, named id.
Then i want to create a table for rooms. A room is considered weak entity because it cannot be identified without refering to a hotel and because it cannot exist without a hotel.
So lets say that rooms contain columns with data and two other columns.
First column is a foreign key to hotel id and a second column which is a room number.
Note than many rooms can have the same number but no room in the same hotel can have the same number. So this is a way to identify a specific room.
How can i put this into a table?
I cannot declare the number as unique because its not unique, i cannot declare it as a primary key either for the same reason. So am i creating a table without primary key?
Also, the foreign key "hotel_id" is a unique key since it is a primary key in hotels table.
I suppose i won't having problems using many rooms with the same foreign key.
To sum up.
My question is how to create the table rooms, is there any way to automatically identify each room except the obvious (identifying the room by selecting a room with specific number and hotel_id)?.
Thank you in advance.
The primary key in the Rooms table is composed of two columns (HotelID, RoomNumber). That combination must be unique for your data model to operate correctly.
You create a table rooms with an id column as primary key. This table has also the columns hotel_id (FK to hotels) and room_number. You define an unique index over (hotel_id, room_number).
That's all ;)

Featured value in one to many relation, which table should hold that?

say that i have a one to many relations where there are two tables, a Person table and a Belonging table. Now, each Person has ONLY ONE favorite belonging and a specific belonging cannot belong to another person as well.
My question is, where would that information be better kept ? In the Person table as a favorite_belonging_id or in the Belonging table as an is_favorite entry ? To my eyes, the first choice seems to be the better version, but I would like to hear what sql knowledgeable people have to say about it.
EDIT : A Person has many belongings but only ONE favorite belonging and each belonging can only belong to one person. It's a one to many association.
I'd be tempted to go with your first suggestion (a favourite_belonging_id column in the Person table), as one can then create a foreign key reference from (person_id, favourite_belonging_id) to (owner_id, belonging_id) in the Belonging table.
If one were to go the other route of creating a is_favourite flag in the Belonging table, there is no obvious way of ensuring the 1:1 nature of person-favourite belonging relationships (a composite UNIQUE index over (owner_id, is_favourite) would fail when a person has multiple belongings that are not their favourite).
That said, it doesn't feel like this information really belongs in the Person table, as it isn't really a property of the person but rather it's a property of the Belonging. If you feel strongly about it, you could create a Favourites table that has a UNIQUE (or PRIMARY) index over person_id.
to me it does NOT belong in the person table since it has nothing to do with the base person.
if you have only the belonging table - which i also assume has a person_id in it, then this is where you are expressing the relationship between the belonging and the person, and it is where the qualifier should also go.
another option is to have a third table in the middle linking the two - in this case, the favorite flag goes there.
edit:
my preference in design would be the third table option - here you can put a begin date and end date as well as the favorite flag - this would allow you to theoretically trade a belonging to another person at some point in time and still know what happened.
I see that pretty much all the different options have already been laid out in different answers, but instead of commenting on all to give you my impression on what I think you should do, I'll just create an answer myself.
Just to be clear on how I understand how the system works: All users can have multiple belongings, but any belonging can only be help by one person.
In this case, it makes the most sense to have a user_id in the belongings table that can tie a belonging to a person. Once a user_id is set, nobody else can claim it anymore.
Now, as to the 'favorite' part, there are several things you can do. What truly is the best way to do it strongly depends on the queries you plan on running on it. Some consider adding a JOIN table, but honestly this is a lot of additional data that is rather pointless; there is likely going to be the exact amount of rows in it as the user table and by putting it in a separate table, there is a lot you can't do (for example, see how many people DON'T have a favorite). Likewise, a JOIN table would make no sense for the user_belonging relationship, as there is a 1:1 relationship between the belonging and the amount of people who can have it.
So I believe there are two viable options: either add a field (/switch) in the belongings table to indicate of a user's belonging is his/ her favorite, or add a field to the user table to indicate which belonging is the user's favorite. I would personally think that the latter holds the most merit, but depending on the queries you run, it might make more sense to to the former. Overall, the biggest difference is whether you want to process things pre-insert or post-select; e.g. in the latter situation, you will have to run an independent query to figure out if the user already has a favorite (in the former case this won't be necessary as you would put a unique index on the field in the user table), whereas in a post-select situation you will have to do cross reference which of the selected belongings from the belonging table is the user's favorite.
Please let me know if I explained myself clearly, or if you have any further questions.
The following may not be the best options because it offers a somewhat unconventional method of flagging the favourite belonging. The advantage, though, is that this way you'll have just two tables with no circular references and every person will be guaranteed to have no more than one favourite belonging.
So, it's two tables, people (or persons) and belongings. The people table has this structure:
person_id INT AUTO_INCREMENT,
other columns as necessary,
PRIMARY KEY (person_id)
The belongings table is created like this:
belonging_id INT AUTO_INCREMENT,
person_id INT NOT NULL,
is_favourite enum ('1'),
other columns as necessary,
PRIMARY KEY (belonging_id),
FOREIGN KEY (person_id) REFERENCING people (person_id),
UNIQUE (person_id, is_favourite)
The key element is declaring is_favourite as a nullable enum with a single possible value. This way, when you declare a unique constraint on the pair of (person_id, is_favourite), you are allowed to have as many rows with the same person_id and empty (null) is_favourite as possible, because unique constraints ignore rows where at least one member is null. And you won't be able to create more than one person_id with is_favourite = '1', because that would violate the unique constraint.
Neither. My suggestion is to add another table person_favourite_belonging, like this:
CREATE TABLE person
( person_id INTEGER NOT NULL
--- various other columns about Persons
, PRIMARY KEY (person_id)
) ;
CREATE TABLE belonging
( belonging_id INTEGER NOT NULL
, person_id INTEGER NOT NULL
--- various other columns about Belongings
, PRIMARY KEY (belonging_id)
, UNIQUE KEY (person_id, belonging_id) --- this Unique constraint is needed
, FOREIGN KEY (person_id)
REFERENCES person (person_id)
) ;
CREATE TABLE person_favourite_belonging
( person_id INTEGER NOT NULL
, belonging_id INTEGER NOT NULL
, PRIMARY KEY (person_id)
, FOREIGN KEY (person_id, belonging_id) --- for this Foreign Key constraint
REFERENCES belonging (person_id, belonging_id)
) ;
This is just my preferred way of doing this. There are alternatives and all have their pros and cons. The pros with this approach are:
No circular path in the Foreign Key constraints (and therefore):
No chicken and egg problems when inserting, deleting or updating Persons, Belongings or Favourite Belongings.
All foreign key columns can be defined as NOT NULL.
The integrity can be enforced at the database level.
If your requirements change and you want to have 2 (or more) favourites per person, you only change appropriately the constraints at the Favourite table.
Check also my answer in this question (with an almost identical problem): In SQL, is it OK for two tables to refer to each other?
favourite_thing is a FK to the belonging table (if that table exists, otherwise it could be a domain) , but in an additional constraint, you can force belonging_id in the persons table to be unique.
UPDATE:
DROP table belonging;
CREATE table belonging
( id INTEGER PRIMARY KEY
, description varchar
);
DROP table person;
CREATE table person
( id INTEGER PRIMARY KEY
, description varchar
, favourite_thing INTEGER REFERENCES belonging (id)
);
-- Now add the unique constraint
-- NOTE: favourite_thing can still be NULL
ALTER TABLE person
ADD CONSTRAINT must_be_unique UNIQUE (favourite_thing)
;
UPDATE 2: if every belonging belongs to exactly one person, you could add an owner field to belongings:
CREATE table belonging
( id INTEGER PRIMARY KEY
, owner_id INTEGER NOT NULL REFERENCES person(id)
, description varchar
);
DROP table person CASCADE;
CREATE table person
( id INTEGER PRIMARY KEY
, description varchar
, favourite_thing INTEGER REFERENCES belonging (id)
);
ALTER TABLE person
ADD CONSTRAINT must_be_unique UNIQUE (favourite_thing)
;
Actually you present a one-to-one relation.
So you can:
1. Hold it in Person table.
2. Hold it in Belonging table.
3. Hold it in both.
4. Hold it in separate table.

Referencing Table & Referenced Table

I'm trying to understand relationships and naturally questions appear.
What does referencing table mean and what does referenced table mean? In the above example which one should be referenced and which one referencing?
Lets say for the sake of argument that the settlements table is a child table (settlement cannot exist without a country). Should this child table be referencing or referenced?
I prefer not to open a new question for such a little question:
What does that Mandatory checkbox mean? Does it mean that the settlements table is required or that country_id is required? Or maybe something else?
Found a really good explanation in the PostgreSQL documentation.
Say you have the product table that we have used several times already:
CREATE TABLE products (
product_no integer PRIMARY KEY,
name text,
price numeric
);
Let's also assume you have a table storing orders of those products. We want to ensure that the orders table only contains orders of products that actually exist. So we define a foreign key constraint in the orders table that references the products table:
CREATE TABLE orders (
order_id integer PRIMARY KEY,
product_no integer REFERENCES products (product_no),
quantity integer
);
Now it is impossible to create orders with product_no entries that do not appear in the products table.
We say that in this situation the orders table is the referencing table and the products table is the referenced table. Similarly, there are referencing and referenced columns.
The referenced table is the 'parent' table.
The referencing table is the 'child' table.
The clue is in the SQL DDL e.g.
ALTER TABLE Settlements ADD
FOREIGN KEY (country_id)
REFERENCES Countries (id);
Settlements references Countries, implies Countries is referenced.
settlements table (with the country_id field) is referencing to countries table (the id field)
I suppose mandatory checkbox has nothing to do with the relation. It is simply a not null constraint on the field. But you should consult the user manual of MySQL Workbench on this one.
The Mandatory check box, if it seems to have no effect in generated SQL, has some effect on the graphic. If unchecked, you can see little circle at concerned relation line extremity (for Relationship notation crow's foot).
It means that the foreign key could be null, aka. not mandatory.
One country can have many settlements so the country table is the referenced table and the settlement table is the referencing table. I don't know about mandatory field.