2

I'm still a novice to databases, normalization, etc, and I might need some help. Enclosed here is a portion of my database structure, and I'm thinking that my approach is a bad idea. Here, our country can be classified into different provinces, and all cities/towns are under a specific province, and a barangay (the closest Layman's term is District, I guess). So if all places, where ever you may be in our country, you must have that certain barangay, city/town, and province. What I did is I used Foreign Keys to refer to tables barangay, city/town, province. Is this a bad idea?

How different is it if I created a tblCustomer_Address to separate Country_ID: Int FK, Province_ID: Int FK, CityTown_ID: Int FK, Baranggay_ID: Int FK from tblCustomer?

Thanks!

tblCustomer(
  Customer_Id: Int PK
  Customer_FName: String
  Customer_MName: String
  Customer_LName: String
  Country_ID: Int FK
  Province_ID: Int FK
  CityTown_ID: Int FK
  Baranggay_ID: Int FK
  Additional_Address_Details: String
 )
tblCountry(
  Country_Id: Int PK
  Country_Name: String
)
tblProvince(
  Province_Id: Int PK
  Province_Name: String
)
tblCityTown(
  CityTown_Id: Int PK
  CityTown_Name: String
)
tblBarangay(
  Barangay_Id: Int PK
  Barangay_Name: String
)

* EDIT: By the way, I forgot to mention. A part of my project is report generation, so I what I had in mind is to keep track of the locations. So I thought of having separate tables for barangays, city/town, provinces, to make each and everyone unique.

Matt
  • 22,721
  • 17
  • 71
  • 112
Wap
  • 587
  • 1
  • 4
  • 14
  • 2
    Welcome to StackOverflow: if you post code, XML or data samples, **please** highlight those lines in the text editor and click on the "code samples" button ( `{ }` ) on the editor toolbar to nicely format and syntax highlight it! Then you don't need any of those messy ` ` and `
    ` tags, either!
    – marc_s Jun 21 '12 at 08:42

3 Answers3

0

Pretty bad, as you've got to maintain the available options for country, city and districts.

Personally, I just create an addresses database table, which fields for address components as per the hCard microformat:

CREATE TABLE IF NOT EXISTS `addresses` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `extended_address` varchar(128) DEFAULT NULL,
  `street_address` varchar(128) NOT NULL,
  `locality` varchar(128) NOT NULL,
  `region` varchar(128) DEFAULT NULL,
  `postal_code` varchar(128) DEFAULT NULL,
  `country_name` varchar(128) NOT NULL,
  PRIMARY KEY (`id`)
)
Martin Bean
  • 38,379
  • 25
  • 128
  • 201
  • 2
    I'm not sure it's "pretty bad" - this depends on how it's used. If there are GUI dropdowns for country & province, it makes sense to put them into separate tables. Even for city etc., normalization may be needed. – sleske Jun 21 '12 at 08:50
  • Country names change faster than you would imagine, not to mention the various different languages. In addition, I would have to think about how to fit my own address into that schema. – Fionnuala Jun 21 '12 at 08:56
  • Yes. I was thinking of it that way, with dropdown and all. Anyway, I'm still trying to piece all the responses up together. Thanks for the replies! – Wap Jun 21 '12 at 08:59
  • 1
    @Remou Changing country names is not a problem as long as all you want to do is track current addresses. You just run a simple update changing the country's name across the table. You are of course right that in 3NF you should split it apart. But if it really doesn't matter (e.g. this will remain the only place countries are used, and you don't need to track historic addresses) you're just producing unnecessary joins etc. – janb Jun 21 '12 at 09:04
  • @janb I can see where you are coming from and I agree with you for the most part, but in my own country, not unusually, country names can be in one of two languages, which means that analysis by country could get complicated. – Fionnuala Jun 21 '12 at 09:12
  • Sure, if you need to track more than just one thing about the country, be it multiple names (like local name and english name) or anything else, then a separate country table becomes a necessity as countries are now real objects with multiple properties. – janb Jun 21 '12 at 09:32
0

Well it seems to me that a barangay will exist in a city or province, a city will exist in a province, and a province will exist in a country. How about a structure where you havea location table with a location type of Barangay, City, Province, Rural or country and a parentID pointing to the parent location in the hierarchy. Then your customer has a location id pointing to anywhere in the hierarchy. New locations can be added as existing in a city, province (for rural) district or country. Table would look like this:

tblLocation(
LocationID int PK,
ParentID int FK references tblLocation LocationID,
LocationType int FK references tbllocationTypes,
LocationName
)

Couldn't add this as a comment, so here is a more full implementation:

CREATE TABLE LocationType
(
    LocationTypeID int not null primary key,
    LocationTypeName varchar(20) not null unique
)
GO
CREATE TABLE Location (
    LocationID int not null primary key,
    ParentId int null references Location (LocationID),
    LocationName varchar(100),
    LocationTypeID int not null references LocationType (LocationTypeID)    
)
GO
CREATE Table Customer (
    CustomerID int not null primary key,
    FirstName varchar(50),
    MiddleName varchar(50),
    LastName varchar(50),
    LocationID int references Location (LocationID)
)
GO
CREATE TABLE City(  
    CityID int not null primary key references Location (LocationID),
    PostCode varchar(20) not null
)
GO
CREATE VIEW DetailedLocation AS 
    SELECT L.*, C.PostCode FROM Location AS L
    LEFT OUTER JOIN City AS C
    ON C.CityID = L.LocationID
Kell
  • 3,252
  • 20
  • 19
  • Why didn't I think of this...of course it has to have a hierarchy. Mine can be, for instance, in a barangay but in a city/town that it shouldn't be under to (in short, barangay under a different city/town). Thanks – Wap Jun 21 '12 at 09:11
  • I think this approach just asks for problems. You're assuming none of the different location types will ever need their own properties. If you suddenly need towns to have a postal code, what do you do? Add a field to tblLocation? It would have to be empty for most rows, which is pretty bad. – janb Jun 21 '12 at 09:35
  • Just when I thought that this approach makes sense. I'm going nuts on what to do, why did I choose to have this degree in the first place?haha here's another variable that I forgot to consider - ZIP code. I was also planning on using that for "smart" identification of landline number prefix. I might as well not to. – Wap Jun 21 '12 at 09:52
  • @janb: It would be quite simple to add an entity called town that has a postal code, and a primary key that relates to the location's primary key. I.E. Town is a location. The same is true for any additional information that belongs to any of the other entity types. They are all locations and the hierarchy is appropriate. – Kell Jun 21 '12 at 09:59
  • But then retrieving information about a location based on its type becomes needlessly complex imho. You'd have to look up a certain table based upon the type, or not for some types. Basically you created a magic number. – janb Jun 21 '12 at 10:24
  • I'd create a view that would outer join city to location to return the postal code, which would return null for all other locations. The same strategy would be used for additional data on any other location types. This results in a simple view to get data and no additional garbage fields in the table. – Kell Jun 21 '12 at 10:31
  • This is way out of my league; I couldn't follow. But needless to say, I'd try both your solutions. Thanks janb and Kell. Pretty interesting approach, and here's a chance to learn outer join as well. – Wap Jun 21 '12 at 13:16
  • @Kell Sure, there are plenty of workarounds to make it work but I think having some kind of magical extra properties attached in a different table based on a field's value is plain bad practice and should be avoided. I can understand choosing to ignore that and still go for it, but one should be aware of the matter. – janb Jun 21 '12 at 15:45
  • @Janb It's not really a workaround. It's pretty standard implementation of a generalization hierarchy where you have the "is a" relationship. You'd use this for organisation structures, locations, etc. The view would normally include things like depth and path so you could build a tree in a GUI – Kell Jun 21 '12 at 16:10
0

The problem is that you are not handling addresses the right way. If you REALLY do not need the full address (or am I just missing this here?) than just having a Baranggay field in the customer table would be "okay". In any other case you should have an address table and just reference the addressID within the customer table. Unless of course a customer should be able to have multiple addresses, in which case you should introduce a CustomerAddressRel table for this m:n relationship.

Anyways, the whole splitting up of the address into multiple fields and/or tables here is pointless. A specific baranngay will forever belong only to one town, that town to one province, and that province to one country (country? if this is about multiple countries you need a different format anyways as baranngay is not an international concept!). So it really is good enough to track the baranggay in the address and have a different table which saves what town and province a baranngay belongs to.

Sorry for the long text but I feel it won't help you at all if I put up a revised scheme. You need to understand the reasons for certain decisions and then make the best decision based on your current dataset and the expected reach. If you ever possibly could go international, make sure the data scheme is ready for it right now.

Edit:

Okay then, I think it is best after all if I put it down. If you want to be future-proof and flexible, at least as long as you keep limite to th Philippins and a Barangay belongs to a town:

tblCustomer(
    Customer_ID: Int PK
    Customer_FName: String
    Customer_MName: String
    Customer_LName: String
)

tblCustomerAddressRel(
    Customer_ID: Int FK
    Address_ID: Int Fk
    Type: (Mailing, Billing, Historic,...)
)

tblAddress(
    Address_ID: Int PK
    Baranggay_ID: Int FK
    Additional_Address_Details: String (<< this looks like a bad idea btw)
)

tblCountry(
    Country_ID: Int PK
    Country_Name: String
)

tblProvince(
    Province_Id: Int PK
    Province_Name: String
    County_ID: Int FK
)
tblCityTown(
    CityTown_ID: Int PK
    CityTown_Name: String
    Province_ID: Int FK
)
tblBarangay(
    Barangay_ID: Int PK
    Barangay_Name: String
    CityTown_ID: Int FK
)
janb
  • 360
  • 5
  • 16
  • Thanks. I'm sorry if I'm not so clear, probably because of my english. How do I explain this, a barangay names here are not unique and it can be used from one city to another; only cities/towns, provinces are unique. What I thought when I split them to multiple tables are to make them more identifiable when I extract data (at least I thought it would be), and as mentioned by @sleske, I planned for a dropdown menu. Not being a douche here, I just want to understand. – Wap Jun 21 '12 at 09:20
  • I was about to incorporate @Kell's idea of hierarchy in my initial approach and see if it fits, and I guess that's just about it in what you did. Although that multiple addresses is pretty neat, I didn't see that at all, thank you janb...I'm learning a lot here. Figured Additional_Address_Details would be look bad, even just by looking at the bad naming.haha My idea was just to store more specific address details (like block, street number) just for the sake of it. I'm more after being able to access the barangay, city, province addresses for a specific customer. Again, thanks – Wap Jun 21 '12 at 10:02