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

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.

Related

Normalization of an address table advice needed

I have a database with several tables
Student
Teacher
Parents
Staff
All need to have a reference to an address table
Address
door number
street
town
city
postcode
How can I create a address table with little duplication of data? Is the only way to have separate tables for each?
Have a separate Address table with the following columns
address_id
door_number
street
town
city
state
country
postcode
Now in each of the tables - Student , Parent , Teacher , Staff - have an address_id column and create a foreign key to the address_id in the address table.
Assuming Student and Parent are already related, you can have the address just in the Parents table.

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.

MySQL Create pivot table from existing column in existing table

I've got a prexisting table that contains all kinds of customer information. Currently it also has the "city" as well as the "region" and the "state" listed in a 3 columns as strings. Redundant info!
I'd like to create three new tables, one for the city and one for the region and one for the state, that will contain single entries for each of the cities etc, and then reference the ID back into the existing customer table with a location_id.
How would I go about exporting the distinct city names into the cities table, and the distinct regions into a regions table, and then have the cities reference the region_id and state_id table as well so that the information is all grouped!
Amatuer question for sure, but I appreciate any help!
You don't want three different tables! You want one table with three columns: city, state, region.
The reason is that city does not exist by itself. Consider (in the US) Springfield, IL. And Springfield, MA. Or Miami, FL and Miami, OH. What you have is a dimension of the data that has hierarchies. The right way to store this is at the lowest level (city in your case) with a "dimension" table providing the other information.
Assuming that your original data is correct, you can do something like this:
create table Cities (
CityId int auto_increment not null primary key,
City varchar(255),
State varchar(255),
Region varchar(255)
);
insert into Cities(City, State, Region)
select distinct City, State, Region
from YourTable;
I realize that this is not "standard normal form". But for most applications this works well. If you are doing this for an application where you want to pick states from a list, for instance, create an index on state and the query will be fast.
There are some circumstances where you might want separate tables at the state and region level. This would be the case if you had lots of different columns at those levels. And, in particular, if you were modifying the values in those columns. A flattened dimension (such as described here) is most appropriate when the data is static (cities don't change states very often). Normalization is most appropriate when you are changing values in the different levels.

mysql/RoR database design

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...

efficient database design inheritance

I want to design a database with have 2 categories.
There are 2 subcategories in each category, but they are very similar to other category like:
preventive equipment maintenance:
cat1
id, equipment,model, series, accesories,date, cost, status
cat 2
id, equipment,model, series, accesories,date, cost, status
corrective equipment maintenance
cat1
id, new equipment, old equipment, borreowed equipment, description
cat 2
id, new equipment,model, series, accesories,date, cost, old equipment, borreowed equipment, description
So as you can see the only diference between data collected on preventive equipment maintenance is the cat (either cat1 or cat2).
To solve this I thought to make a table like
CREATE TABLE `preventive_e`(
id INTEGER NOT NULL PRIMARY KEY,
equipment VARCHAR(25) ,
cat VARCHAR(4) ,
CONSTRAINT `uc_Info_E` UNIQUE (`id`)
);
INSERT INTO `preventive_e` values (1,'nintendo','cat1');
INSERT INTO `preventive_e` values (2,'psp','cat2');
Now in corrective it would be the same, however they are not the same fields, they are almost the same fields, if is cat1 i want to store only some fields, but if is cat 2 i want to store same fields but some more fields
Is there a way to use inheritance or something?, extending the fields but being able to add more particular fields? How would a query look like.
sqlfiddle
why not call the table something generic to both like equipment_maint and have a column acting as a flag for it's usage.
Fiddle
CREATE TABLE `equipment_maint`(
id INTEGER NOT NULL PRIMARY KEY,
equipment VARCHAR(25) ,
cat VARCHAR(50) ,
type varchar(20), /* usage on type of maintenance */
CONSTRAINT `uc_Info_E` UNIQUE (`id`)
);