I want to have a list that consists of default and custom entries. So, for example, on my software when a dealership is created and want to put a car in their inventory I want them to be able to select from a list of types of cars that already exists in the database and also from types of cars they will be adding as needed but only for that dealership.
How should I build this?
Should I have a table with the default types and another one with the custom types of that dealership and when requested I return both? -> each query will have to access 2 tables.
Should I have a single table with a column with the dealership ID and when requested return all that have the dealership ID and all that don't have any dealership ID (the default ones)? -> each query will have to return results with both no ID and dealership ID.
Should I have a single table with a column with the dealership ID and every time a new dealership is created I duplicate the default entries but their ID on it? -> Can really become monstrous and with duplicate entries.
Is there a better way to do this?
Example:
I just created a dealership and when I try to add a car to my inventory I see the options Mercedes, Volkswagen and Kia. But I want to add a Jaguar and it's not on the list. I want to add it only to my dealerships's list, so the next time I try to add a Jaguar the option is already there.
PS: I have tried searching for a solution for this but couldn't find anything.
You definitely should avoid creating a separate table for each dealership.
Your second choice is best. You may want a table with columns like this:
id
zone_id
dealership_id
maker_id
maker_name
model_id
model_name
model_number
Then you can run queries like this:
SELECT model_name, model_number
FROM tbl
WHERE (dealership_id = :current_dealer: OR dealership_id IS NULL)
AND (zone_id = :current_zone: OR zone_id IS NULL)
AND (maker_id = :current_maker: OR maker_id IS NULL)
You can write a query like this to express the precise business rules for the choices for each dealer site.
Why add zones? Some vehicle makers have regional variations on their products. For example, internal combustion engines in California have more stringent regulations about exhaust than the rest of the US. The vehicle makers have zone offices in California to help coordinate that. Subaru sells a version of its vehicles specifically designed for New England in the Eastern US.
Related
I am asking this question which is to teach myself of using correct approach in a certain scenario than any how-to-code problem.
Since I am self taught student and haven't used relational tables before. With search and experiment, I have come to know the basic concept of relations and their usage but I am not sure if I am still using the correct approach while using these tables.
I do not have any official teachers so only place I can ask troubling questions is here with you guys.
For example, I have written a little code where I have 2 tables.
Table-1 is doctors which has an id (AI & Primary) and names table of varChar.
Table-2 is patient_recipts which has a doctor_name table of tinyInt
names table hold the name of the doctor
doctor_name table holds the corresponding id from doctors table
name and doctor_name are related to each other in database
Now when I need to fetch data from patient_recipts and display doctor's name, I will need to INNER JOIN doctor table, compare the doctor_name value with id in doctor table and get the name of the doctor.
The query I will use to fetch patients of a certain doctor, is something like,
$getPatList = $db->prepare("SELECT *
FROM patient_recipts
INNER JOIN doctor ON patient_recipts.doctor_name = doctor.id
WHERE dept = 'OPD' AND date_time = DATE(NOW())
ORDER BY patient_recipts.id DESC");
Now if I were to INSERT an action log entry in some other processor file, it would be something like (action and log entry),
$recipt_no = $_POST['recipt_no'];
$doctor_name = $_POST['doctor_name']; //this hold id(int) not text
$dept = $_POST['dept'];
$patient_name = $_POST['patient_name'];
$patient_tel = $_POST['patient_telephone'];
$patient_addr = $_POST['patient_address'];
$patient_age = $_POST['patient_age'];
$patient_gender = $_POST['patient_gender'];
$patient_fee = $_POST['patient_fee'];
$logged_user = $_SESSION['user_name'];
$insData = $db->prepare("
INSERT INTO patient_recipts (date_time, recipt_no, doctor_name, dept, pat_gender, pat_name, pat_tel, pat_address, pat_age, pat_fee, booked_by)
VALUES (NOW(),?,?,?,?,?,?,?,?,?,?)");
$insData->bindValue(1,$recipt_no);
$insData->bindValue(2,$doctor_name);
$insData->bindValue(3,$dept);
$insData->bindValue(4,$patient_gender);
$insData->bindValue(5,$patient_name);
$insData->bindValue(6,$patient_tel);
$insData->bindValue(7,$patient_addr);
$insData->bindValue(8,$patient_age);
$insData->bindValue(9,$patient_fee);
$insData->bindValue(10,$logged_user);
$insData->execute();
// Add Log
write_log("{$logged_user} booked OPD of patient {$patient_name} for {$doctor_name}");
OUTPUT: Ayesha booked OPD of patient Steve for 15
Now here the problem is apparent, I would need to execute the above mentioned fetch query yet again to get name of the doctor with ID comparison and bind the ID 15 to Doctor's name before calling the write_log() function.
So this is where I think my approach has been wrong altogether.
One way could be using actual doctor name in patient_recipts rather than ID
but this would i, in first place, kill the purpose of learning related tables and keys, learning design scenarios and troubleshooting.
Please help so I can understand and implement a better approach for days to come :)
Your table structure is correct, it's considered best practice to use the ID as the foreign key in other tables. If you want to include the doctor's name in the log message, you do have to do another SELECT query. A query like
SELECT name
FROM doctor
WHERE id = :doctor_id
is not very expensive.
But you can simply live with the log file only containing IDs. Look up the doctor's name later if you need to find out which doctor a particular log message is referring to.
BTW, when you use PDO, I recommend you use named placeholders (as in my example above) rather than ?. It makes the code easier to read, and if you modify the query to add or remove columns you don't have to change all the placeholder numbers.
I am currently trying to design DB(mysql) structure for my project which is an online shop for wholesale company - I already created everything when it comes to products, it's multiple variants etc but I have problem with following which is price and historic data for multiple suppliers:
Please find below main assumptions for the project:
We are going to have several suppliers for products
Thanks to the above each product will have few different prices
We want to be able to have historic price data for each product with each supplier
Variant 1
At first I thought about adding 2 tables to my DB:
suppliers table: supplier_id, name
prices table: id, product_id, price_supplier1, price_supplier2, price_supplier3, timestamp
However in such example whenever we want to add another supplier we need to add row to the database (I am not a db expert but I guess that's not the best approach)
Variant 2
Another idea was just to have price table with following:
suppliers table: supplier_id, name
prices table: id, product_id, supplier_id, timestamp
However in this case if we have 5 suppliers we get 5 records created for 1 products every single day so let's imagine that we have only 1000 products and want to keep historic data for last 6 months - such table would grow very rapidly
So to summarize - which approach is better or maybe there is a different one that I could implement? Thanks a lot for any suggestions.
You should go with variant 2. It's best practice to avoid frequent table restructure, which you would have to do in variant 1 any time you add or remove a supplier (although MySQL is fairly fast at this in recent versions). Using a single column to identify the distinct supplier values is better. It also promotes query reuse when you don't have to worry about column values changing or being dropped altogether. Also, space shouldn't really be a concern. To give you an idea, if your prices table had 1,000,000 rows (6 months), it would be about 40-50M in size (assuming only a primary key index). MySQL also offers compression and partitioning to reduce storage as well, if that's really a concern.
I will create 3 tables in mysql:
Movies: id-name-country
Tv-Series: id-name-country
Artists: id-name-country
Instead of entering country information into these tables seperately, i am planning to create another table:
Countries: id-country
And i will make my first three tables take country data from Countries table. (So that, if the name of one country is misspelled, it will be easy just to correct in one place. Data in other tables will be updated automatically.
Can i do this with "foreign keys"?
Is this the correct approach?
Your approach so far is correct, ONLY IF by "country" in Tv-Series and Artist you mean country ID and NOT a value. And yes you can use foreign keys (country id in tv-series and artist is a foreign key linking to Countries);
Edit:
Side note: looking at your edit I feel obliged to point out that If you are planning to link Movie/TV-Show with artist you need a 4th table to maintain normalization you've got so far.
Edit2:
The usual way to decide whether you need tables is to check what kind of connection 2 tables or values have.
If it's 1 to many (like artist to country of origin), you are fine.
If you have Many to many, like Movie with Artist where 1 artist can be in multiple movies and 1 movie can have multiple artists you need a linking table.
If you have 1 to 1 relation (like customer_ID and passport details in a banking system, where they could be stored separately in customer and Passport tables, but joining them makes more sense because a banks only hold details of 1 valid passport for each customer and 1 passport can only be used by 1 person) you can merge the tables (at the risk of not meeting Normalization 3 criteria)
I have a table for a list of people allowed in a building. Each resident is allowed to give 10 nonresidents access.
resident guest1 guest2 ... guest10
I want to search over all the guests, and then display the results in alphabetical order. Currently I have:
$result = mysql_query("SELECT * FROM residentlist WHERE guest1 LIKE 'searchquery' OR guest2 LIKE 'searchquery' ... OR guest10 LIKE 'searchquery'";
But I end up with extra guests that aren't like 'searchquery', so I need to do a bunch more if checks.
I'm new to mysql - am I missing something simple?
Also, I'm open to restructuring the table / adding tables if that's better.
You should restructure the tables. Create a new table called access or something with the fields accessId, residentId and guest.
accessId is the primary key, it is AUTO_INCREMENT INTEGER.
resident is the foreign key to the residentlist table.
guest is whatever you now search using your LIKE condition.
So for your 10 guests per resident, you will have 10 records in that access table.
Once you have that, you can use the query:
SELECT * FROM residentlist LEFT JOIN access ON access.residentId = residentlist.resident WHERE guest LIKE '<search query>';
Your current select statement will return all guests for a resident if a single one matches your search query. So if Bob allows Jack and Jane and you search for Jane, it'll return the entire row of Jack and Jane.
Yes, this should be redesigned to be a separate table that is simply Resident, Guest. The 10 maximum should be enforced on the application side rather than the database. See Shi's answer for an excellent explanation on how to structure it moving forward.
If you need to keep your current structure, you can obtain the desired results through the UNION operator.
SELECT guest1 FROM residentlist WHERE guest1 LIKE 'searchquery'
UNION SELECT guest2 FROM residentlist WHERE guest2 LIKE 'searchquery'
...
UNION SELECT guest10 FROM residentlist WHERE guest10 LIKE 'searchquery'
I feel like the database could be better organized. As a general rule, if you have a field name that is blah1, blah2, ... blahX, that is usually a red flag.
Anyways, sounds like you have two objects: a guest and a resident, and then a relationship between them.
So, you can have a resident table that has information about the resident and a unique identifier for the resident like residentId. So you have:
ResidentId
Name
Address ....
Then you have a guest table that specifies information about the guests:
GuestId
Name
whatever else...
Then you have a third table that actually relates the guest and resident (guestToResidentTable). This will have two fields:
ResidentId
GuestId
you might also want a unique id for each of these relationships - making three fields in this table
Both id fields are foreign keys from your other tables.
This way every guest will be related to each resident and like Derek said, you enforce the 10 guest limit in your application (not the database).
Then you can search the guest table for all guests like your search query. If you then want information about the guest and what resident he is related to, you just join on the other tables.
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 :)