mysql - Database organization for representing location - mysql

I need to create database which will contain the following entities in country:
Regions
Municipalities
Now comes the hard part for me:
Municipality can also be city, where city can (but not always) have its own municipalities.
Municipality can have several cities.
Municipality in both cases contains several settlements
I wanted to create several tables, for example:
regions (region_id, region_name)
municipalities (municipality_id, municipality_name, region_id).
cities (city_id, city_name, region_id)
city_municipalities (city_municipality_id, city_municipality_name, city_id)
settlements (settlement_id, settlement_name, municipality_id, city_municipality_id)
i think that here i make problem. There would be a lot of NULLs for municipality_id or city_municipality_id, since i cant have both field filled.
But right now it comes to my mind to have two tables organized like this:
geo_entity(geo_id, geo_name, geo_type_id, parent)
geo_entities_type (geo_type_id, geo_type_name)
this table will contain definitions of what geo_entity entry is, like:
1 Region
2 Municipality
3 City
4 City Municipality
5 Settlement
What should i stick to? Do you have a better approach and which one?

Related

companies er model for different countries

I want to build a ER-model for companies.
Some fields for companies are the same, like the name, legal_address and others, but some fields are defined based on the country, where the company is registered.
For example if we take Russia, the company should have fields like inn, ogrn, etc.. (don't matter the names).
If we will take another country - the company will have another set of fields.
I need an advice of how to plan (architect) this.
Any ideas would be great.
At the moment I have this done:
[locations]
id
country
city
lat
lng
zip_code
[companies]
id
location_id
name
director
legal_address
actual_address
[company_russia]
id
company_id
inn
kpp
ogrn
stat_codes
reg_number_fss
reg_number_pfr
But I think there will be problems joining the tables and that each other country requires a separate table - is not a good approach.

Query to find lakes that are in multiple states

I have tables to hold information about Lakes, Counties, and States. I also have a table called LakeLocation that is simple a pair of foreign keys of a LakeID and CountyID, so I can know where they are. And each county has a StateName inside it.
A high-level view of it all is something like this:
Lake = {id,name,...}
County = {id, name, StateName ....}
State = {name, ...}
LakeLocation = {LakeID, CountyID}
I am trying to find out which states have lakes that are in more than one state. An example is Lake Tahoe which crosses four county lines and two state lines. I know that I will need a recursive query, but I only understand those for simple one table child/parent type relationships. Not this.
How can I design a query that does what I need? Thanks
You only need a group by to know what are the lakes
SELECT LakeID
FROM LakeLocation
GROUP BY LakeID
HAVING COUNT(CountyID) > 1
Then if you want lake names
SELECT *
FROM Lake
WHERE LakeID IN (<previous query>)

Using join or duplicating when shared column is small?

I am looking for a best practice for multiple tables in a vertical hierarchy having small shared data. Let's say three tables:
Country {
id
}
State {
id,
country_id,
FK_to_country_id,
}
City {
id,
state_id,
FK_to_state_id,
}
in above state belongs to country while city belongs to state and turns out to belong to country as well. The schema looks clean but when you want to look up which country a city belongs to, you have to use a JOIN with three tables. If there is another tier called County which belongs to city, the situation gets worse.
City {
id,
country_id,
state_id,
FK_to_country_id,
FK_to_state_id,
}
adding another column 'country_id' in City frees us from cumbersome JOIN but the database schema gets a little duplicate.
What's practice in real world?
That's what JOINs are made for; don't deprive them of their duty.
In real-world practice, it is absolutely normal to be joining multiple tables like that.
In your example, yes it would be redundant to have country ID's in the city table.
But it's not always the case. Consider an example where a city can exist without needing to be in a state (a lot of 3rd-world countries have no "state" designation), then you have to have that foreign-key country ID, because the State table is optional.

What is the most efficient way to make this MySQL database?

Ok, I have a database with with a table for storing classified posts, each post belongs to a different city. For the purpose of this example we will call this table posts. This table has columns:
id (INT, +AI),
cityid (TEXT),
postcat (TEXT),
user (TEXT),
datatime (DATETIME),
title (TEXT),
desc (TEXT),
location (TEXT)
an example of that data would be:
'12039',
'fayetteville-nc',
'user#gmail.com',
'December 28th, 2010 - 11:55 PM',
'post title',
'post description',
'spring lake'
id is auto incremented, cityid is in text format (this is where I think i will be losing performance once the database is large)...
Originally I planned on having a different table for each city and now since a user has to have the option of searching and posting through multiple cities, I think I need them all in one table. Everything was perfect when I had one city per table, where I could:
SELECT *
FROM `posts`
WHERE MATCH (`title`, `desc`, `location`)
AGAINST ('searchtext' IN BOOLEAN MODE)
AND `postcat` LIKE 'searchcatagory'
But then I ran into problems when trying to search multiple cities at one time, or listing all of a users posts for them to delete or edit.
So looks like I have to have one table with all the posts, and also match another FULLTEXT field: cityid. I am guessing I need full-text because if a user chooses an entire state, and my cityid is "fayetteville-nc" I would need to match cityid against "-nc" this is only an assumption and I would love another way. This database could easily reach over a million rows within 6 months, and a fulltext search against 4 columns is probably going to be slow.
My question is, is there a better way to do this more efficiently? The database has nothing in it now, except for some test posts made by me. So I can completely redesign the table structure if necessary. I am open to any and all suggestions, even if it is just a more efficient way to perform my query.
Yes, one table for all posts sounds sensible. It would also be normal design for the posts table to have a city_id, referring to the id in a city table. Each city would also have a state_id, referring to the id in a state table, and similarly each state would have a country_id referring to the id in a country table. So you could write:
SELECT $columns
FROM posts JOIN city ON city.id = posts.city_id
WHERE city.tag = 'fayetteville-nc'
Once you've brought the cities into a separate table, it might make more sense for you to do the city-to-city_id resolving up front. This fairly naturally happens if you have a city chose from a dropdown, for instance. But if you're entering free text into a search field, you may want to do it differently.
You can also search for all posts in a given state (or set of states) as:
SELECT $columns
FROM posts
JOIN city ON city.id = posts.city_id
JOIN state ON state.id = city.state_id
WHERE state.tag = 'NC'
If you're going to go more fancy or international, you may need a more flexible way of arranging locations into a hierarchy (e.g. you may want city districts, counties, multinational regions, intranational regions (Midwest, East Coast etc)) but stay easy for now :)

Basic table design Q

I am trying to understand this concept. For example: I have two tables City and Country.
Country
-------
id
abbreviation
name
City
-----
id
name
Country (name or id, or both? - This is the question)
To reference and keep a particular city in sync with the country it belongs to I guess this will be reference to country.id as a FK. This means an example of the city table will be: (200, New York, 19) - where 19 = USA in country table. But this doesn't help a person viewing the table because he wont know what 19 is without looking up in country table what 19 is.
So I want to add the country name also to city table so it reads: (200, New York, USA). I don't need the 19 to display because 19 is of no use to the reader but is only used in back to connect the tables.
So what should my tables colunms / FK look like to i can store in city table rows like this (200, New York, USA), yet ensure New york will always reference to USA in the USA lookup and keep the 19 which is the primary key for USA out of the city table so the tables look clean and easy to understand? And I assume if these are referenced, tomorrow if i update USA to be 20, it will update in the city table on its own, and same way if I rename USA to US it will update on city table on its own?
My DB is in MySQL
Why not use ISO 3166 country codes (2 character or 3 character) as the country ID? This leaves you with recognizable codes in the city table; you can map to the full name in the country table.
As for viewing the data, use a VIEW to create a good looking table:
CREATE VIEW CityInfo(CityID, CityName, CountryID, CountryName) AS
SELECT ci.id, ci.name, ci.country, co.name
FROM City AS ci JOIN Country AS co ON ci.Country = co.id;
You don't ... if you need to have "usable" tables in the DB, so someone can easily view something useful with select * etc. (or to make programing the SQL by hand easier). Then you create the tables as above, in normal form, and then create a VIEW which combines the tables.
Tables aren't supposed to be viewed by people: some application should be accessing the tables to present data to people in a way they can parse it. The reason you want to have country.id as a FK in your table is so that you don't have a million rows whose country name is "USA", because then all kinds of problems can occur, like what happens when you mistype and "US A" lands in one of the fields? Or what if you want to change what the user sees from "USA" to "United States"?
The right way to handle it is to use the country.id as you initially suggest, and then use a JOIN statement to present the data, like this:
SELECT city.name, country.name
FROM city JOIN country ON country.id = city.country
My syntax could be off, but that's in essence what you want.