How to normalize my MySQL Database - php

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

Related

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

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

What is the simplest way of implementing pricing plans in mysql and php?

I am working on a project, and I am trying to find a way to associate my pricing plans table with a customer.
id name description price days
1 Free the free plan 0.00 0
2 Silver the silver plan 49.99 365
3 Gold the gold plan 99.99 365
My first thought was to add the plan id as foreign key to the customers table. But i also need to know when is the expire date (based on the purchase date and the days of the plan selected).
When attempting to do something like this, it is best to keep tables abstracted from each other.
user_pricing_plans - the table name
pricing_plans_id - the id for the record you want to associate with a user
user_id - the id of the user
date_expiration - the date the plan will expire
date_purchased - the date the plan was purchased
following an approach like this will allow you alter this table if needed to add extra information. you could also follow a similar approach in the future with another table.
the key to all of this is separating your concerns ( the data ) into separate containers.
Edit: to kind of hint at what I'm getting at about why separating the tables is a good idea, I added the date_purchased as a field in the user_pricing_plans table.
a dba I know once said that "mysql is not a place for developers - they try to create tables to work with their code. tables are meant to represent data. your code should be written to work with the data and the schemas that represent them - not the other way around"
I do not know why I can not add a comment to the best answer in the post.
As #Jonathon Hibbard points few years ago, there is another reason to separate the data between pricing plan and user model.
You used to have users who have one plan and choose another later, that is called, "history". To manage that, this third table is very important.
And in my opinion, more important, one thing is your pricing table, an another one is the final price you have with every client. Yo have knownledge people, close clients that you want "special" prices, this third table gives you the oportunity to set diferent prices for one plan with fixed price and a lot of other use cases.
Think about your main plan table like a product, the user is the client, and the third party as the ticket, with "temp pricing" aplied, ocassional discounts or whatever.

MySQL table designing for an Accounting system

I am designing an online accounting system as a college project. I have got the following simple transactions.
Sales on cash $300
Cash burrowed from Smith $250
Electricity bill paid $50
I have referred Double Entry Accounting in a Relational Database and designed the above Transaction table(minus sign means the amount is credited). The id 1 and 2 belong to transaction 1, id 3 and 4 belong to transaction 2 and so on. How can I identify each two rows as a single transaction in MySQL database.For example if the first transaction to be selected how can I do it since there is no relationship between the two rows. If this design does not sound good can you suggest an alternative.
You should drop the two line design unless it's really necessary. I would merge the rows and add an extra field where you could store if it was cash or not and the amount value would be + when credited and - if debited (or reversed, I"m not good at accounting :))
Good Job.
The only thing I might add is two number columns for debit and credit. That would look just like a journal in the text books or old bookkeeping books. It would be a little more visibly obvious and handle any number of double entries. Your current amount column could be calculated by debit - credit if you like.
I do not think you need to make it relational unless you wanted a specific chart of accounts as a table, more complicated and less elegant. But, for more flexibly you could generate real time chart of accounts from the journal.
Since you are using MySQL relational database, you can add several tables.
To answer your question, you need to create another table to hold general information for each transaction (e.g. you could call it a TRANSACTIONS). This table could include Transaction ID, and Date Column.
Now, reference the Transaction ID column of the TRANSACTIONS table in your currently existing table. This means record 1 and 2 will have one Transaction ID and so you can reference it as such in your queries.

How should I design the database structure for this problem?

I am rebuilding the background system of a site with a lot of traffic.
This is the core of the application and the way I build this part of the database is critical for a big chunk of code and upcoming work. The system described below will have to run millions of times each day. I would appreciate any input on the issue.
The background is that a user can add what he or she has been eating during the day.
Simplified, the process is more or less this:
The user arrives to the site and the site lists his/her choices for the day (if entered before as the steps below describes).
The user can add a meal (consisting of 1 to unlimited different items of food and their quantity). The meal is added through a search field and is organized in different types (like 'Breakfast', 'Lunch').
During the meal building process a list of the most commonly used food items (primarily by this user, but secondly also by all users) will be shown for quick selection.
The meals will be stored in a FoodLog table that consists of something like this: id, user_id, date, type, food_data.
What I currently have is a huge database with food items from which the search will be performed. The food items are stored with information on both the common name (like "pork cutlets") and on producer (like "coca cola"), along with other detailed information needed.
Question summary:
My problem is that I do not know the best way to store the data for it to be easily accessible in the way I need it and without the database going out of hand.
Consider 1 million users adding 1 to 7 meals each day. To store each food item for each meal, each day and each user would potentially create (1*avg_num_meals*avg_num_food_items) million rows each day.
Storing the data in some compressed way (like the food_data is an json_encoded string), would lessen the amount of rows significally, but at the same time making it hard to create the 'most used food items'-list and other statistics on the fly.
Should the table be split into several tables? If this is the case, how would they interact?
The site is currently hosted on a mid-range CDN and is using a LAMP (Linux, Apache, MySQL, PHP) backbone.
Roughly, you want a fully normalized data structure for this. You want to have one table for Users, one table for Meals (one entry per meal, with a reference to User; you probably also want to have a time / date of the meal in this table), and a table for MealItems, which is simply an association table between Meal and the Food Items table.
So when a User comes in and creates an account, you make an entry in the Users table. When a user reports a Meal they've eaten, you create a record in the Meals table, and a record in the MealItems table for every item they reported.
This structure makes it straightforward to have a variable number of items with every meal, without wasting a lot of space. You can determine the representation of items in meals with a relatively simple query, as well as determining just what the total set of items any one user has consumed in any given timespan.
This normalized table structure will support a VERY large number of records and support a large number of queries against the database.
First,
Storing the data in some compressed way (like the food_data is an
json_encoded string)
is not a recommended idea. This will cause you countless headaches in the future as new requirements are added.
You should definitely have a few tables here.
Users
id, etc
Food Items
id, name, description, etc
Meals
id, user_id, category, etc
Meal Items
id, food_item_id, meal_id
The Meal Items would tie the Meals to the Food Items using ids. The Meals would be tied to Users using ids. This makes it simple to use joins in order to get detailed lists of data- totals, averages, etc. If the fields are properly indexed, this should be a great model to support a large number of records.
In addition to what's been said:
be judicious in your use of indexes. Properly applying these to your database could significantly speed up read access to your tables.
Consider using language-specific features to minimize space. You mention that you're using mysql; consider using ENUM when appropriate (food types, meal types) to minimize database size and to simplify management.
I would split up your meal table into two tables, one table stores a single row for each meal, the second table stores one row for each food item used in a meal, with a foreign key reference to the meal it was used in.
After that, just make sure you have indices on any table columns used in joins or WHERE clauses.

Display rows based on $array

I have a table in postgres called workorders. In it are various headings. The ones I am interested in are labor, date_out and ident. This table ties up with wo_parts (workorder parts). In this table are the headings I am interested in, part and workorder. Both are integers. (part auto number) The final table is part2vendor and the headings are retail and cost. Right, basically what happens is.....I create a workorder (invoice). This calls a part from part2vendor. I enter it and invoice it off. In workorder a row is created and saved. It is given an ident. In wo_parts, the part i used is recorded as well as workorder number and qty used. What I want to do is create a report in php that pools all this info on one page. IE. if i choose dates 2009-10-01 to 2009-10-31 it will pull all workorders in this range and tell me the total labour sold and then the PROFIT (retail less cost) of the parts I sold, using these 3 tables. I hope i have explained as clear as possible. any questions please ask me. Thank you very much for your time.
You will want to read up on SQL - keywords to look for include "aggregate", "SUM" and "GROUP BY".
You query will look something like (but this will certainly need correcting):
SELECT
SUM(wo.labor) AS tot_labor,
SUM(p2v.cost - p2v.retail) AS tot_profit
FROM
workorders AS wo
JOIN wo_parts AS wp ON wo.ident=wp.ident [?]
JOIN part2vendor AS p2v ON ...something...
WHERE
date_out BETWEEN '2009-10-01'::date AND '2009-10-31'::date;

Categories