I have two entities: Event and Location. The relations are:
1 Event can have 1 Location.
1 Location can have many Events.
Basically I want to store events. And each event is hosted in a specific location. When I say specific location I mean:
Street, Number, City, Zip Code, State, Country
I basically have a design question, that I would like some help with:
1 - Right now I am thinking on doing the following:
Event table will have a location_id that will point to a specific location row in the locations table. What happens with this is that:
I will have many repeated values in each row. For example, if an event is happening in 356 Matilda Street in San Francisco, and another one is happening in 890 Matilda Street in San Francisco. The values Matilda Street and San Francisco will be duplicated many times in the location table. How can I redesign that to normalize this?
So, basically I would love to hear a good approach to solve this question in terms of a relational database, like MySQL.
If you want a strictly normalized database, you could have a table for street names, another for cities, another for states, and so on. You might even have an additional location table that holds unique combinations of street, city, and state; you'd add rows to this table each time an event occurs at a previously unknown location. Then each of your events would reference the appropriate row in the location table.
In practice, though, it's sometimes better simply to store the location data directly within the events table and tolerate the extra memory usage; there's always a trade-off between speed and memory use.
Another consideration: what happens if a street is renamed? Do you want old events to be associated with the old name or the new name?
Each location in the locations table should be uniquely identifiable by its PRIMARY KEY. Records in the events table then reference their associated location with column(s) that contain the value of that PRIMARY KEY.
For example, your locations table might contain:
location_id | Street | Number | City | Zip Code | State | Country
------------+----------------+--------+---------------+----------+-------+---------
1 | Matilda Street | 356 | San Francisco | 12345 | CA | USA
2 | Matilda Street | 890 | San Francisco | 12345 | CA | USA
Then your events table might contain:
event_id | location_id | Date | Description
---------+-------------+------------+----------------
1 | 1 | 2012-04-28 | Birthday party
2 | 1 | 2012-04-29 | Hangover party
3 | 2 | 2012-04-29 | Funeral
4 | 1 | 2012-05-01 | May day!
In this example, location_id is the PRIMARY KEY in the locations table and a FOREIGN KEY in the events table.
Your Locations table should have a unique ID such as 1=Matilda Street, 2=Market Street - one record for each possible location NO DUPLICATES, then your Events table should have a location ID that uses one of those IDs - again, one for each event, no duplicate.
You can then join them like this;
SELECT events.event_name, locations.location_name
FROM events
JOIN locations on locations.location_id = events.location_id
The duplication is very normal because each of them is an unique location. And beyond that, the design you think is very usable when you try to filter the places in san francisco.
Related
I have a DB in which I have several addresses.
I need to get one row for each different country in the DB.
For example if I have
| id | name | column | country |
| -- | -------------- | ------ | ------- |
| 1 | Main address | 10 | UK |
| 2 | Second address | 3 | France |
| 3 | Third address | 78 | USA |
| 4 | Fourth address | 46 | France |
| 5 | Fifth address | 44 | France |
| 6 | Sixth address | 11 | UK |
I need to retrieve only 3 rows: 1 for UK, 1 for France and 1 for USA. The row I get for each country is not important but I need the full row. (For UK id 1 or 6 does not matter but I need all columns).
How can I do that in Laravel (preferably using Eloquent).
I cannot use group by because all columns have different values...
Depending on how big your data set is (this will get inefficient if very large) you can do something like this...
//Select and get the countries column.
$countries = DB::table('addresses')->select('country')->get();
//Get the unique values of countries from the collection
$uniqueCountries = $countries->unique();
//Array which will contain a single address from each country.
$singleAddresses = [];
//Loop over each unique country you retrieved from the database.
foreach($uniqueCountries as $country){
//Grab the first address to occur for whatever country is currently being iterated over in the loop.
$singleAddress = DB::table('addresses')->where('country','=',$country)->first();
//Push the first address found for the country into the array of single addresses from various countries.
array_push($singleAddresses,$singleAddress);
}
//Dump the array of collection to the page to make sure the output is what you want.
dump($singleAddresses);
Basically you'll want to grab only the countries column from your database through the select statement. This data is then returned to you as a collection. On that collection you can then use the unique method to get all the unique instances of country names.
Once you have your unique list of country names you can move onto grabbing an address for each country. This is done by looping over the unique set of countries one at a time. Making a database request to only select addresses where that county is, and then grab the first instance of an address within that country.
Once you have the object of that address data you'll want to push it into an array containing all the other single addresses from the countries you've retrieved.
Once the loop completes you'll have an array of Laravel collection objects with a single address from each country in your database.
Some other notes...
If you need the address to be random by country you'll want to modify your selection statement to use ->get() for all addresses from a country. Then you'll call on that data set using the collection random method to grab a random address from that country.
If your data set for these addresses and countries is extremely large you'll want to look into using the caching systems built into Laravel or lean on curated lists of data like this list of countries to help do some of the heavy listing.
I just pushed all of the address collections into an array because it was quick and easy. However Laravel does support making empty collections, which you can then use other collection methods on to manipulate your data. In my experience I've found advantages and tradeoffs to both so take that for what you will.
I managed to get what I needed using ANY_VALUE to avoid the problem of the different values and AS to be able to use the fields easily.
$addresses = Address::select(DB::raw('ANY_VALUE(name) AS name, ANY_VALUE(column) AS column'), 'country')->groupBy('country')->distinct()->get();
It gives me an array with a single row for each country.
the first is the sectors table that has an id and sector name like this
id | sector
1 | Government
2 | Education
The second is the employee table like this (simplified)
Id | name
1 | sam
2 | tom
Finally I have a sectorMap table (this is used to join the two tables above together) like this
Id | sectorid | employeeid
1 | 1 | 2
2 | 1 | 1
3 | 2 | 2
So in this instance, once I join everything together and view the sectors or each employee, it would show that tom has two sectors (government, education) and sam only has one (government)… hope that makes sense
My question is, within my application, the user has the ability to change these sectors by selecting from a multiple selection dropdown in html. For some reason I thought that by doing an update on duplicate expression would work, however seeing how I have multiple rows of data, I would need to delete all rows within the sectormap table that do not reflect the new selection and contain the selected employees id. What would be the best way of going about that?
For instance, in this case, lets say I open the application and see that tom has two sectors tied to him (government, education) and I only wanted him to have one (government). When I deselect education and select GO. The application returns a list to the server that contains (‘government’). How can I formulate an expression to delete the education sector row from the sectormap table that contains his id?
Your answer is in your question.
1st when you are deselecting education. You will get data of (‘government’). right?
So just invert your query. select those records which is not (‘government’), those are education.
So, education records are you can delete.
Hope this will help you. thanks:)
I am working on database for scoring system for my friend. I have table with games and second table with names of sports (footbal, tenis, floorball). I want to store scores of the games but I don't know how to design database for specific needs of scores.
For example:
Football score - 1:2, 2:2 (1st and 2nd half)
Tenis sets - 6:4, 7:6
Floorbal - 1:0, 3:0, 3:2 (1st, 2nd and 3rd part of the game)
I need this score linked to games table, but I need specific table columns for storing score for every game.
I think about:
Multiple tables and and foreign key, but this is not possible in mysql.
Then I think about storing data in json in one row and then parse it specifically based on sport, but probably this is not very good solution.
The only problem from my point of view is:
How create table/s for storing scores in different format based on type of sport?
Thank you for any help
E.g.:
match_id | period_id | team1_score | team2_sore
1 | 1 | 1 | 2
1 | 2 | 2 | 2
2 | 1 | 6 | 4
2 | 2 | 7 | 6
3 | 1 | 1 | 0
3 | 2 | 3 | 0
3 | 3 | 3 | 2
You mention MySQL, so it appears that you want to develop a relational database.
The first step is to define the relations. Based on your example.
A game has one sport.
A sport has zero or more games.
A game has one or more period scores.
A period score has one game.
Based on these relationships, we can define 3 tables.
Sport
-----
Sport ID
Sport name
...
Game
----
Game ID
Sport ID
Game name
PeriodScore
-----------
PeriodScore ID
Game ID
Period
Score
The primary ID fields are known as blind keys. They are auto-incrementing integers. Their sole purpose is to tie the game with the sport, and the period scores with the game. Otherwise, they have no meaning at all. The primary ID fields are the primary (clustering) keys of their respective tables.
The Sport ID in the Game table is a foreign key. This key points back to the Sport table, so you can get the name of the sport. You can create a unique index on (Sport ID, Game ID) if you ever want a list of the games for a particular sport.
The Game ID in the PeriodScore table is another foreign key. You must create a unique index on (Game ID, PeriodScore ID) so that you can retrieve the period scores in the correct order.
When you want to create a relational database, you first define the relationships, then go through a process of normalization.
I have a database that has to work with 2 countries, IT and RO.
I have a table called User, that contains also the birthplace.
User
| id | name | surname | birthplace |
| 1 | Test | Test | New York |
I also have 2 tables for the birthplace, one for the IT ones and one for the ROs. I cannot store all the cities in one table because IT and RO have a different gerarchy (region, province, district...). So my first thought was to do a birthplace field for each country, like this:
User
| id | name | surname | birthplaceIT | birthplaceRO |
The problem is that every time a nation is added, I'd have to modify the database and the application. On the other side, I cannot make a "birthplace" table because the IT and RO addresses are not compatible.
So, I cannot do this:
Birthplace
| idUser | country | city |
Because I cannot refer "city" to both the IT cities table and the RO ones.
Suggestions?
EDIT. In my PHP application i'm using Symfony with Doctrine, an ORM, so I NEED the Foreign Key constraint between the User and the CityID!
Instead of storing birthplace in User table, change it to let's name it birthplace ID - it can be simply integer but you can do something more sophisticated and use unique codes (your own or maybe there are "proper" geographical codes).
Then you can have table for each country specific birthplace and join tables based on birthplace ID. This way you can keep each country specific geographical hierarchy in its own table. If you need to add another country - you simply create another table for that country and join it with User.
I have a db schema where user data is stored using foreign key references , these foreign keys are admin defined . Also , there is some data which is stored without primary keys , however I have other constraints in place to avoid redundancy and other issues .
Due to the requirements of the application when a user 'updates' their info I have to delete all user records from the 'updated' table and reinsert all the user's records again . (I have looked into all other options)
Now because of my search solution (solr) , I need to track changes to the user data (updates/deletes) . I am planning on having a view to compare the last committed data to the real time data . I am fearful of how sustainable it would be to have a stored procedure running every 20 minutes or so , is there a better way of tracking data with SQL ?
You could create a change table that contains the same columns as the original table plus another column called "UpdatedOn." Then set up a trigger to write to this change table the original values when the original table is changed.
Example:
Original Table:
Name | Address | City
Jane Doe | 1 Main St. | New York
Change to Original Table:
Name | Address | City
Jane Doe | 2 Smith St. | Dubuque
...which triggers an insert to the Change Table:
Name | Address | City | UpdatedOn
Jane Doe | 1 Main St. | New York | 2012-01-01
There is information about using triggers in mysql here: http://dev.mysql.com/doc/refman/5.0/en/triggers.html