Four-(or five-)way Table Relationship in Laravel - php

I have tried reading Laravel documentation and other, similar posts about Laravel database relationships, but I cannot seem to wrap my head around it and how it applies to my use case.
I run a web site for high school athletics. I have 5 tables:
schools - Standalone list of all schools in the state.
sports - Standalone list of all sports sanctioned by the state.
seasons - Standalone list of seasons (one season per school year).
leagues - Standalone list of leagues/conferences.
league_divisions - List of divisions for leagues that have multiple divisions (think "Big Ten East" and "Big Ten West") where leagues = parent and league_divisions = child. Note: A league would only have child records in this table if it had divisions; Most high school athletic conferences/leagues do not have divisions, and therefore would not have a corresponding record in this table.
Every so often, schools change leagues, or may change which division of a league they are a part of. (think "school_leagues")
Similarly, a school may begin to field a new sport (School A never had girls soccer in the past, but now they have a team) or discontinue an old one (School B no longer has a football team). (think "school_sports")
Also, while the state may sanction 25 sports, a league itself may only sanction 10. My web site is for the League itself, so I would also need a way to list which sports a league sanctions. (think "league_sports")
In my old (pre-Laravel) data model, I just had a "school_leagues" table that stored what league (and division, if applicable) a school belonged to for a particular range of seasons (via start_season_id, end_season_id). Additionally, in the HTML, I simply hard-coded a static list of which sports a league sanctioned and which teams should appear in that sport's standings.
However, as I rebuild my data model, I'm thinking I may need a more complicated relationship table(s) that joins Schools, Sports, Seasons, Leagues, and (optional) League Divisions.
Additionally, instead of using start_season_id and end_season_id (where end_season_id IS NULL if the relationship is still valid), will Laravel conventions force me to have 1 record per school per sport per season per league/division? (This would directly join to season_id as opposed to having start/end_season_id columns)
Any help is appreciated!
I could simply go with 3 relationship tables: school_leagues, school_sports, and league_sports, and all would join to season by either season_id (1 record per year) or start/end_season_id.
OR I would have 1 master table that joins school_id, sport_id, season_id, league_id, and (optional) league_division_id. It would have 1 record per instance, so each year I'd generate a new group of records.

Laravel / Eloquent has a serviceable scheme for many-to-many relationships. https://laravel.com/docs/5.8/eloquent-relationships#many-to-many In your app you have several many-to-many relationships, for example schools >----< sports . Eloquent uses a join table (called something like schools_sports to represent this in the DBMS.
To handle the complexity here, you probably need a new entity in your database design. Let's call it teamseason. There's one of these for each school, sport, season, and league. It relates to one each of those entities, and it might have attributes like won, lost, captain, and other data points relating to the team and season.
For example,
Stuyvesant High School (school) had a
Precision Air Rifle (sport) team
In Spring 2018 (season) playing in the
New York City Geeksports League (league)
They won 10 and lost 3 matches, and the captain was Deadeye Robinson (attributes)
You'll need another of these entities for the Spring 2019 team.
A table for it might look like this:
teamseason_id PK
school_id FK to school.school_id
sport_id FK to sport.sport_id
season_id FK to season.season_id
league_id FK to league.league_id
won int
lost int
captain varchar(128)
I'd throw in division, but I don't understand the structure.
This looks like it might be some kind of four-way join table, but it's more than that. I added the won/lost/captain attributes to emphasize that it's its own entity.
The trick is to identify an entity for each real thing in the world of your app, then identify the relationships between entities. (It takes practice to do this well.)

Related

How to handle multiple many to many relationships

I have a Laravel project in which there is likely to be multiple many to many relationships but I feel like I'm going around in circles in terms of the correct use of pivots tables.
The entities are as follows:
Centre: an office that is going to open soon and has information such
as name, location, postcode, opening date
Task: a task that must be completed before a centre can open, it has information such as name, department and centre type
Department: a department represents a key area such as IT, Marketing, Sales etc. Each task would have a reference to a department.
User: a user is a user of the system, they belong to a department and they can complete tasks.
Considerations:
A department has users, so users would have a department_id
A task has a department so would also have a department_id
A centre has departments so a pivot called something like centre_department with centre_id and department_id
A user has tasks assigned to them but only tasks that belong to a centre
The bottom statement is where I'm going in circles because:
A Task is to be assigned to a Centre which is fine as you could make a table like centre_task with centre_id and task id
A user has tasks assigned to them, however, is it okay to have a task_user table that has user_id and a centre_task_id, effectively a pivot table that uses another pivot table?
This is because a user can't be directly assigned to a task, they can only be assigned to a task within a centre as the tasks have a many to many relationship with centres.
If I were to assign a user just using task id, they would be assigned to that task in every related centre.
So, again is it okay to have a pivot table that uses another pivot table, or does this display an issue with the structure I have suggested?
Intended flow
A user creates a task, assigns it a department and a type so that this task is only relevant to a specific department and type of centre.
A user can assign a task within a centre to a user who is in the department that's relevant to the department of the task
The task in the centre would then have an assignee and a deadline
In theory I'd end up with a pivot table that has the following:
user_id
centre_task_id
deadline
date_completed
Essentially I just feel like I'm connecting too many pieces?
Laravel does the linking for you, simply use (in this case) morphToMany() & morphedByMany() in your Models to establish a relation between two tables. There is a very good Laracast and also a very good Documentation. I have linked this below:
Laracast Video very nice Explaination for Many-To-Many Relations
Laravel Documentation for Eloquent ORM In General

How to normalize my MySQL Database

I have PHP/MYSQL car rental site. In the MYSQL table i store
car license plates
car specs (like AC, brand and such)
price per day (30 colums), since price for 1 day is X euro per day, and for 30 days let's say is Y euro per day
insurance per day (this is a per
car thing because it depends on the specific car history, year,
brand, model and such). So since there are 30 days in a month, we
have here another 30 columns, since insurance for 1 day <> insurance
for 28 days let's say
Now if i put all this stuff in I will have about 70 colums.
Any smarter way of doing it to avoid a performance blow?
I do not control the prices and there is not a daily price or daily insurance formula.
One ideea would be to use the car plates as an index and blow it in 2 tables, one with prices (35 rows), one with insurance (35 rows). Any other?
The DB has 1000 cars or so. I get about 10.000 queries a day in the DB
Kind thanks.
A quick an dirty attempt below. I'd move prices and insurence costs in dedicated tables, each having a car_id and days field.
Select brand,type,ac,seats FROM cars
LEFT JOIN prices ON cars.id = prices.car_id
LEFT JOIN insurence_costs ON cars.id = insurence_costs.car_id
WHERE
licensePlate = 'HH-OH-234'
AND prices.days = 28
AND insurence_costs.days = 28
Update: Added the license plates. I'd just put them in car specs. In general they are car related but may change sometime in future. If they change quite often I'd rather move them in a dedicated table too.
I would actually save the price per renting day depending on the overall renting span to the db. That way, you could do something like
SELECT price FROM prices
WHERE car_id = 123 AND days = MAX(days);
That way you could multiply the "last" price with the actual amount of renting days for any rents above 30 days. But thats up to pricing definitions.
To normalize a database (or more general to design a database) you have to, clearly, determine the entities that you have.
From your description, you have four entities as follows:
Car
Specification
Price
Insurance
Every entity of the above should has a table to handle its properties (columns).
After, defining the entities, the real normalization is to define the relations between the entities, either through, keys properties (columns) or through new entity (table), for example, in Many to Many relations. Lets discus the relations:
Car: one car should has one specification, price and insurance. i.e the relation is one to one. So, cars table should has specification_id, price_id and insurance_id columns that relate it with the other three tables.
On the other hand the other three tables (entities: specifications, price and insurance) may have many cars so its relation to car is one to many and it is covered by defining the foreign keys in the cars table (specification_id, price_id and insurance_id)
How could it work?
Before inserting new car, you have to complete the other entities. In other words, a list of all available, specifications, prices, insurances should be found in there respectable tables (entities) and if you have got a new car that has no any defined one of them, then you have to create new entity that covers its need before inserting or creating it. i.e inserting new specification and/or new price and/or new insurance that car should belong to.
Notice: this is not a law, you or other one may able to invent another entities relations. However, what I have regarded here is a
general hint based on relational database design methodology

Advice on database design and table structure needed

Im new to programming and databases in general. I've read PHP.MYSQL for DUmmies 4th edition thus far, and am trying to create a database of my own which stores the Menus/Inventories of shops. I am currently using XAMPP/MYSQL.
Sample tables of my database are as follows:
SHOPINFO
Shopname Outlet Category Subcategory Item
PizzaHut Main Drinks Carbonated Cola
PizzaHut Main Drinks Non-carbonated Orange Juice
BurgerKing Central London Burgers Beef Whopper
BurgerKing South London Burgers Beef Whopper Jr.
BurgerKing South London Drinks Carbonated Cola
I am currently wondering if i should split the above table up into :
SHOPINFO
Shopname Outlet Category Subcategory Item
PizzaHut Main 1 1 1
PizzaHut Main 1 2 3
BurgerKing Central London 1 5 4
BurgerKing South London 1 5 7
BurgerKing South London 3 3 2
Where the Categories,Subcategories and Items are all split up into different tables where they are identified by their CategoryID,SubCategoryID and ItemID respectively.
The 2 Major Questions i have regarding this decision are:
1.Would it really be beneficial to split the table up? I am asking this as would it not be far easier to query the first table rather than the second table? E.g i could simply do something like
$query="SELECT * FROM SHOPINFO WHERE Shopname='BurgerKing' AND
Outlet='South London' AND Category='Drinks' AND
Subcategory='Carbonated'";
$result=mysqli_query($cxn,$query) or die("Error");
while($row=mysqli_fetch_assoc)
{
extract($row);
echo "$Item";
}
instead of the query that would have to be done if the table was split(Which i have no idea how to do, and which makes my mind hurt).
2.If i were to split the table up, i'm guessing that i would have to create separate tables for each shop for the Category,SubCategory and Item, using the Shopname & Outlet as primary keys, which i would then link to the SHOPINFO table with foreign keys, probably using ON DELETE CASCADE & ON UPDATE CASCADE. The main question is, exactly what benefits would doing this bring about, apart from making the querying more complicated?
PS: My concerns are regarding future scalability.(E.g Adding countries,Cities,States to Outlets in the future)
Advice,Help,Opinions,Insults and Flaming are appreciated.
Thanks!
I think that your entire structure is wrong. You need to split everything up into separate tables, starting with a table of companies - Pizza Hut and Burger King are the only entries which you have shown. Then you need a table of branches which would contain a foreign key to the company along with atomic data about each branch, like its branch number, address etc. Then you need a category table, whose data seems to be either drinks or burgers, followed by a subcategory table (carbonated, non-carbonated, beef, chicken, etc) which contains a foreign key to the category. The you need a products table (cola, orange juice, whopper, whopper jnr) which has a foreign key to the subcategory. Finally, there would be a branch-products join table which has two fields (branch number, product number).
This structure, whilst seemingly cumbersome, is the most flexible and allows one to write all kinds of queries with little difficulty - total sales by company, total sales by branch, etc. This may not be clear when you are defining your database but you will appreciate this in the future when you are asked for some data aggregation which you had not foreseen.
Keeping everything in one table is a very bad idea: let's say that Burger King is taken over by The Grill Master (an invented name): this way you only have to change one record to reflect the change, whereas when using one huge table, you would have to update many records.
The 'huge one table' approach comes from people who use Excel as their database manager and basically have no experience of anything more complicated. The professional answer is to use a relational database with everything split up into tables.
I apologise if the above seems condescending; I am a doctoral candidate who is looking at the use of Excel within companies which use relational databases, so I am somewhat biased in my views.

Making several tables with hasMany for a complex finding

I'm having trouble assembling the tables where I will search powers of attorney for several companies.
where:
Prosecutor will belong to several companies (X, Y, Z)
Companies have several branches (EU, Brazil, USA, etc ...)
The branches will have multiple units. (Energy, Oil, etc. ..)
The attorney will also have various powers (signing, trading, etc.).
The intention is that in the end, I can find an attorney who is able, for example, to sign the contract by energy unit of Brazil subsidiary company X.
Can someone help me with the and hasMany tables and with logic? Thanks!
Just create those tables as usual and then you will have to create relational tables.
prosecutors_to_companies (they may belong to several companies, right?)
prosecutor_id | company_id
1 2
1 4
2 6
Then create the next relational table:
companies_to_branches
company_id | branch_id
1 4
1 3
Then with help of JOINs retrieve the needed data.
This example may help you - http://www.sitepoint.com/understanding-sql-joins-mysql-database/

How to setup 1:many relationships in MySQL

I'm trying to build a searchable database of acronyms and their definitions that are specific to a certain industry. It has been years since I've done any real programming, so I'm a little behind the learning curve.
I'm writing the code in PHP, and I'm using MySQL as the database. If this can be done easier in Postgres, I'm not opposed to switching DBs, but I can't use Oracle or any other commercial system.
So here's the question:
I'd like to set it up so that each acronym can: (1) apply to 1, multiple, or no specific organizations; (2) have 1 or more associated definitions.
The complexity--at least in my mind :D--comes in that it is conceivable that some organizations might have a single acronym with multiple definitions that all relate to that one organization. At the same time, the acronym may have 1 or more definitions that relate to OTHER organizations as well.
Am I over complicating this?
I'd like to better understand how to setup the table structure and relationships in MySQL--what fields and relationships would be in each table.
A SQL statement would be helpful if anyone feels so inclined, but I'm hoping to at least get a solid grasp on the database schema so I can get the tables created and some sample data imported.
Many, many thanks to all...
Dan
The solution should contain 4 tables: Acronyms, Definitions, Organizations, and AcronymOrganization.
Acronym(id, acronym, definition_id)
Definitions(id, definition)
Organizations(id, organization)
AcronymOrganization(id, acronym_id, organization_id)
If I understand your question, you can use three separate tables. First, have the table of acronyms/definitions, then have a table of Organizations. Finally, have an AcronymOrganization table, that just references a key from the acronym table, and a key from the organization table. This way, you can have as many acronyms for an organization as you please.
After you set up the database, you need to use a couple inner joins to join the three tables, collecting only the acronyms for the appropriate organization ID.
I'd just create an acronym table, an organization table, and a definition table. Put two foreign keys in the definition table: one for the entry in the acronym table, and the other for the entry in the organization table.
If you want to have a n:m relationship between tableA and tableB, then you need a third table.
table A. Fields : ID,name
table B. Fields : ID,name
table AB. Fields : A,B (A is a reference to A.ID, B is a reference to B.ID)
[TABLEA]1-----*[TABLE_AB]*-----1[TABLEB]
Example
Contents of table a:
ID Name
1 John
2 Mary
3 Piet
Contents of Table b:
ID Name
1 Microsoft
2 Google
3 Philips
Contents of Table ab:
ID Name
1 2
1 3
2 2
3 1
3 3
Then select everything like this:
select a.name,b.name
from a,b,ab
where a.id=ab.a and b.id=ab.b
Result:
a.name b.name
John Google
John Philips
Mary Google
Piet Microsoft
Piet Philips

Categories