mysql/RoR database design - mysql

Is it ok for a table to have two of the same foreign keys as columns?
I.e. I have two tables, one is Country, the other is City. In the Country table:
COUNTRY
--------------
id
name
capitalcity <--- this would have foreign key 'city_id'.
populouscity <-- this would also have a foreign key 'city_id'.
created_at
updated_at
CITY
-------
id
name
populous (bool)
capital (bool)
created_at
updated_at
Keep in mind that the capital city may or may not also be the most populous.
I have wondered if I should just seperate out the two boolean colums of city, have city as city with name only, and have a populous table that references to city, and capital that references to city too. And have two seperate foreign keys in the countries table from the two new tables?

I would go about the design this way
COUNTRY
--------------
id
name
CITY
-------
id
country_id ( useful to know what country a city is in )
name
created_at
updated_at
CAPITALS
----------
id
city_id Unique
POPULUS
-------
id
city_id Unique

Yes it's OK. People sometimes avoid such "explicit" FKs because they are not "flexible", but if you know you'll always need to relate to exactly these two cities, this is the appropriate design. In any case, you don't need these FKs and bool flags.
What I don't see is how you connect non-capital and not-most-populous cities to the country. If you're not careful about how you design your keys, you could end-up with the situation where a city can be a capital of the country it does not belong to.
Using an identifying relationship avoids this issue:
So, every city is identified by a number (CITY_NO) within its country. When the PK is migrated back from CITY to COUNTRY, the COUNTRY_ID is "merged" back to its origin, so there cannot be a country mismatch (note FK1 and FK2 on COUNTRY.COUNTRY_ID).
CAPITAL_NO and POPULOUS_NO are left NULL-able so they can temporarily remain NULL to solve the chicken-and-egg problem caused by circular FKs. This works because InnoDB enforces FKs using MATCH SIMPLE method, so it is enough for just one component of the composite FK to be NULL to avoid FK violation.
BTW, consider whether you actually need POPULOUS_ID - if you keep the population of all cities, then you can derive which one is most populous simply by finding MAX.
You can always add a surrogate key such as CITY_ID if you need it for child FKs or to pacify your ORM...

Related

In what context should the Primary Key be unique?

I'm making an EER diagram and I've a Hotel, that has Halls, that has Rooms.
Hotel has identifying relationship with Wards, then Halls have identifying relationship with Rooms.
So the Hotel has its own unique ID as PK, then the Hall has its own unique ID and the ID of the Hotel as PK.
Then Rooms has HotelID,HallID, RoomsID as its PK.
My thinking process is that a ward for instance can happen to have the same HallID as an other from a different hotel, therefore to identify this specific ward in the context of the entire 'world' I'm building its ID being the only member of the PK wouldn't be enough.
So for example if I were to have HallID as the only member of Hall's PK then if I were to run a query that gets me the Halls with ID=5 I would potentially get more than one tuple.
My structure is as follows:
Hotel(HotelID) -> (Identifying Relationship)
Hall(HallID,HospitalID) -> (Identifying Relationship)
Room(HallID,RoomID,HotelID) {the fields in parentheses are the PK members}
The Ward has a foreign key as part of its PK (HospitalID), similarly Room has two FKs as part of its PK(WardID,HotelID)
I'm confused as to whether I am including more than enough fields in my PK or if my method is correct as it is now, the problem is that I think e.g. having WardID as the only PK in Ward wouldn't be enough to uniquely identify it in the context of the world, that's why I'm including HospitalID as part of its PK.
Is my modelling correct?

Normalization to 3NF?

I have to Normalize this table to at least 3NF
customerID | customerName | petID | petName | transID | transName | transDetails | Price
with the FD as follows
customerID -> {customerName, petID}
petID -> {petName, transID}
transID -> {transName, transDetails, Price}
Now my answer to this is:
customer(customerID, customerName) //customerID as PK
pet(petID, petName, customerID) //petID as PK and customerID as FK
transaction(transID, transName, transDetails, Price, petID) //transID as PK and petID as FK
I really don't understand it that much since I can't absorb the information right now because my brain is now a pulp from uni :( So am I right?
I looked at the FD much closely, should the actual 3NF be :
pet(petID, petName, transID)
customer(customerID, customerName, petID)
transaction(transID, transName, transDetails, Price)
It is unclear what is the proper relationship between customers and pets. From the functional dependencies it seams that all three entities are related 1:1, which means your first answer can work as long as the foreign keys are also unique (to prevent 1:N).
The second answer satisfies all three requirements for 3NF
every field functionally depends on the key
the whole key (no composite keys)
and nothing but the key (no candidate keys)
But I would keep the foreign keys away from the pet or customer table. Each can exist on their own and we want to avoid nulls in foreign key columns. The foreign keys belong in the transaction table because a transaction is what links a pet to a customer, regardless of the desired cardinality.

Autoincrement ID with a prefix

I'm designing a table 'employees', which contains an primary key which is auto increment and represents an ID of the employee.
I want to prefix the ID with an number designating the city: city 1: 1, city 2:2, etc.
So the IDs should look like xyy where x represents the city and yy the ID of the employee.
When I'm adding new employee I'm selecting the city x, and I would like to yy values to auto increment.
Is that possible using SQL commands?
That is not good database design. You really should have a separate column for the city in your table. If you have many cities, the cities should perhaps be in their own table. What you are trying to do is overly complex and although 'everything is possible', I would not recommend it.
You are effectively packing two fields into one and violating the principle of atomicity and the 1NF in the process. On top of that, your key is not minimal (so to speak).
Instead, keep two separate fields: ID and CITY.
ID alone is the primary key. In your own words, ID is auto-increment, so it alone is unique.
You can easily concatenate ID and CITY together for display purposes in your query or VIEW or even in the client code. There is no reason to "precook" the concatenated value in the table itself.
Given this requirement from the comments, "Unique ID should provide users with an info of the city, company requirements", I would do this.
table employee would have an employeeID as the primary key. Other fields would be firstname, lastname, birthdate, gender, etc
table city would have a cityId as the primary key. Other fields would be the name of the city, provinceState, Country, whatever is appropriate.
Table EmployeeCity would have have a primary key of EmployeeId, CityId, and StartDate. Not part of the primary key would be field EndDate.
The primary key of EmployeeCity satisfies the requirement of a unique identifier which leads to city information. Also, if an employee changes cities, it's a simple matter of updating one record and adding another.

database table design and relationship complexity

Could someone suggest the best design for the following scenario?
I have a database in which there is a table called City. This table has the following fields:
City id (Primary key)
City Name
State Id (which is linked to the State table)
My problem is I have 10 cities with the same name in one state. What will be the best design so I can represent one city name per id?
It does not matter that they have the same City Name, as long as they have different City Ids.
Just make sure to set the CityId as primary key in the City table. Also, it would be useful to make it an identity autoincrement column, so that it is inserted automatically and will always be unique.
Same goes for StateId in the State table.
Also, if you use a visual management tool for the database, make sure to set the foreign key relationship between the two tables:
FK_State.StateId_City.StateId.

what is the best way to design a city, state, country table?

I need help designing my country, city, state tables. I will provide sample data from my table so that you can help me better on my problem.
This is my country table:
Country
______
code name
US United States
SG Singapore
GB United Kingdom
This is my city table:
City
_____
id country city state
1 US Birmingham Alabama
2 US Auburn Alabama
.
.
29 GB Cambridge NULL
30 GB Devon NULL
My problem is that the only country that has the state field is the US. All other cities have a null value.
My temporary solution for this is to just create a special city table for the United States, then all other countries have another city table that doesn't have the state field.
I think this will just complicate the matter, because I have two tables for cities.
How can I improve this design?
Why not go relational?
Country ( CountryID, CountryCode, CountryName )
Region ( RegionID, RegionCode, RegionName, CountryID )
City ( CityID, CityCode, CityName, RegionID )
The 'Region' name is a big more generic than State, which means it would likely make more sense everywhere.
Why not a standard 3-way linked table set?
table country (
id int primary key,
name varchar(255)
);
table state (
id int primary key,
name varchar(255),
country_id int foreign key country (id)
);
table city (
id int primary key,
name varchar(255)
state_id int foreign key state (id)
);
This'll hold up for most cases, except a few degenerate ones like Lloydminster, Saskatchewan, which straddles two provincial borders.
There are lots of countries besides the United States that have political divisions between the national and municipal level. Australia has states, Canada has provinces, Japan has Prefectures, and so forth.
The question is how do you track this information and keep it consistent? You could have a "dummy record" at the middle level for countries that don't have one. Another way to handle this is to denormalize foreign keys to all levels down to the entity containing the address. If country and city are mandatory then their foreign keys would be not nullable whereas your state FK could be nullable.
If you go the denormalization route, you will need application logic to ensure that your foreign keys are consistent with each other.
If you go the dummy state record route, you will need application logic to ensure that dummy layers are hidden from users in the user interface.