Combining data between three tables - php

I'm creating a site (For School Purpose) where you can buy stuff from different companies.
On one of the sites I want to show all the companies, but only the companies from the category and the city you have chosen.
But I also want it to be ordered by popularity.
For every time a person is buying something, the popularity of the company in the chosen category and city will be raised by 1.
The categories are: Men, Women and Family.
For this, I'm using three tables:
Table 1 - partners
| partner_id | name | type | logo |
In the first table I have the company names, type and logo.
This table is only used to get the name, type and logo from each company.
Table 2 - single_partners
| id | partner_id | address | zipcode | city |
In the second table I have all companies in the entire country.
If one compay is located multiple times in one city, there will be multiple rows, but with a different id, address, zipcode and city. The partner_id will be the same of course.
Table 3 - partner_pupolarity
| id | partner_id | men | women | family |
In the third table the popularity of each company will be.
Here each company from every city will be stored with a popularity value (men, women and family). If the company have no popularity in any of the three categories, it won't be stored in the table.
I can show each companies from each city, but I cannot sort it by popularity according to the category.
Heres is an quick example of what I want:
On the first site you can choose a category: Men, Women or Family.
When you have chosen a category, you are going to choose a city by typing the zip-code.
Then you're going to see a list where the most popular companies will be shown, sorted by the category you have chosen, and the city. If a company exist multiple times in the same city, it should only show one.
If you have chosen Men and City 1, you will se the most popular companies from the men category in City 1.
If a company do not have any popularity value from that category, it will be in the bottom of the companies.
What I can do now is only to show the companies according to the city you have chosen, but I can's sort them by popularity.
This is what I have tried:
// Load partners
$load_partners = mysql_query("SELECT * FROM partners");
while($partners = mysql_fetch_array($load_partners)) {
$partner_id = $partners['partner_id'];
$partner_name = $partners['name'];
$partner_logo = $partners['logo'];
$partner_logo_dir = "media/partners/";
$load_single_partners = mysql_query("SELECT DISTINCT '$partner_name' FROM single_partners WHERE partner_id='$partner_id' and postal='5000'");
while($single_partners = mysql_fetch_array($load_single_partners)) {
$single_partners_id = $single_partners['partner_id'];
echo '<div class="partner" style="background: url('.$partner_logo_dir.$partner_logo.'); background-size: cover;" data-partner-id="'.$partner_id.'">'.$partner_name.'
</div>'."\n";
$order_partners = mysql_query("SELECT * FROM partner_popularity WHERE partner_id = '$single_partners_id'");
while($order = mysql_fetch_array($order_partners)) {
}
}
}
I think I somehow should combine the data from the three tables but I do not know how.
..or am I doing it all wrong by using three different tables?
Hope you can understand by question :)

What you can do to achieve this is using joins : Here is some MySQL doc about this
But here, using 2 tables for single partners and popularity is not really needed, since one line of single_partners is strictly equal to one line of partner_popularty, you can put them in the same table. You should put them in the same table, and using a default of zero if the partner has no popularity registered, so it'll show last when sorting by popularity.
So, then you'll have 2 tables :
Table 1 - partners
| partner_id | name | type | logo |
Table 2 - single_partners
| id | partner_id | address | zipcode | city | pop_men | pop_women | pop_family
Now your query to select all that becomes extremely simple (just select the partners, filter the city, order them and you're done), and with a little grouping and a join, you can also select partners sorted by popularity summarized in all cities :
SELECT p.*,
SUM(pop_men) AS total_pop_men,
SUM(pop_women) AS total_pop_women,
SUM(pop_family) AS total_pop_family
FROM partners p
JOIN single_partners sp ON sp.partner_id = p.partner_id
GROUP BY partner_id
ORDER BY total_pop_men DESC,
total_pop_women DESC,
total_pop_family DESC

SELECT partners.name FROM partners, single_partners, partner_popularity
WHERE single_partners.name = 'cityname' AND partners.id = single_partners.partner_id AND
partners.id = partner_populariry.partner_id ORDER BY partner_popularity.[category]
As far as i can understand this is what your looking for, or something similar, i dont really understand the whole meaning of it, it this select you will have to do three diferent ones, one for each category.
Sorry if i didn't help.

Related

How can I prevent the user update in the users' table if the country, city, and neighborhood were not related to each other?

There is a field, 3 dropdowns, and a button:
The field will allow the user to change his name.
The first drop-down will allow the user to choose the country.
The second drop-down will allow the user to choose the city which will be enabled after the user chooses the country. (It will show cities that are related to the chosen country)
The third drop-down will allow the user to choose the neighborhood which will be enabled after the user chooses the city. (It will show neighborhoods that are related to the chosen city)
The button will allow the user to save the changes.
There are 4 tables inside MySQL:
The users' table
ID
NAME
COUNTRY_ID
CITY_ID
NEIGHBORHOOD_ID
1
user_3281681
2
4
7
The countries table
ID
NAME
1
Germany
2
Canada
The cities table
ID
NAME
COUNTRY_ID
1
Berlin
1
2
Munich
1
3
Toronto
2
4
Ottawa
2
The neighborhoods table
ID
NAME
CITY_ID
1
Bergmannkiez
1
2
Old Spandau
1
3
Obermenzing
2
4
Cosimapark
2
5
Casa Loma
3
6
Distillery District
3
7
Westboro
4
8
Manotick
4
What do I want?
How can I prevent the user update in the users' table if the country, city, and neighborhood were not related to each other?
Here are some examples:
I'll accept the user update in this situation (NAME = ... | COUNTRY_ID = 2 | CITY_ID = 4 | NEIGHBORHOOD_ID = 7)
I'll reject the user update in this situation (NAME = ... | COUNTRY_ID = 2 | CITY_ID = 4 | NEIGHBORHOOD_ID = 3)
I'll reject the user update in this situation (NAME = ... | COUNTRY_ID = 1 | CITY_ID = 4 | NEIGHBORHOOD_ID = 1)
I'll accept the user update in this situation (NAME = ... | COUNTRY_ID = 1 | CITY_ID = 2 | NEIGHBORHOOD_ID = 4)
We all know the client side is not safe so we should verify insertions and updates before putting the data in the database so I want to prevent the user update in the users' table if the country, city, and neighborhood were not related to each other.
I know how can I prevent the user update if the country, city, and neighborhood were not related to each other using PHP and using MySQL triggers, but I'm here to ask if there is any other way to prevent that without writing the code.
Inside MySQL: Is there any way to automatically distinguish if the country, city, and neighborhood were related to each other or not?
Ask me if there is anything that is not clear. Thank you.
Drop COUNTRY_ID and CITY_ID from the users table. You can get them all with a proper join. For example
select u.*, co.NAME as country, ci.NAME as city, n.NAME as neighborhood
from users u
join neighborhoods n on u.NEIGHBORHOOD_ID = n.ID
join cities ci on n.CITY_ID = ci.ID
join countries co on ci.COUNTRY_ID = co.ID

Get data from 3 tables by one query

I have a small blog project
I have 3 tables
Posts
PostID | TITLE | WRITERS(USERS) | CATEGORIES
1 | SOME TITLE | 1,2 | 1,2
USERS
USERID | USERNAME
1 | Alaa
2 | John
Categories
1 | Business
2 | Marketing
I am trying to get this output
POST TITLE: SOME TITLE
Writers: Alaa And John
Categories: Business, And marketing
Please note that i am talking about a very big loop, 100 post in a page for many viewers
So, currently i have two ideas
First idea
1- take value from writers ( 1,2 )
2- Explode it by php
3- use mysql query to bring the writers
4- Do the same thing for categories
Second idea is to remove the columns writers, categories from the posts table and create a fourth table and call it connections, which will refer ids to each others ( connect everything together )
But i don't even know if i can do the mysql query
You can get all these values in one MySQL query.
SELECT p.TITLE AS `Post Title`,
GROUP_CONCAT(DISTINCT u.USERNAME) AS Writers,
GROUP_CONCAT(DISTINCT c.CategoryName) AS Categories
FROM Posts p
JOIN Users u ON FIND_IN_SET(u.USERID, p.WRITERS)
JOIN Categories c ON FIND_IN_SET(c.Id, p.CATEGORIES)
GROUP BY p.TITLE
Output:
Post Title Writers Categories
SOME TITLE Alaa,John Business,Marketing
Demo on dbfiddle
Note: storing values in comma separated lists (e.g. your WRITERS and CATEGORIES columns) is a bad idea and makes writing this sort of query problematic (it's only MySQL's FIND_IN_SET function which makes it workable at all) and you should look into properly normalising your data (one value per row). Here is an example of how your database could look normalised.

MySQL Duplicating Row Results in Table When Searching Across Multiple Tables

I have three tables in a mySQL db one for users, one for colours and one for the linking of the users to the colours
Table 1 users
==============
ID | Name
--------------
1 | John
2 | Jayne
3 | Fred
Table 2 colours
==============
ID | Colour
--------------
1 | Blue
2 | Red
3 | Yellow
Table 3 link
==============
ID | Name | Colour
--------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 3 | 2
5 | 3 | 3
As you can see, some users have more than one favourite colour (yeah, i know, how annoying).
At the moment, I can show them in a table, with their favourite colour(s) in a column.
BUT, I want to be able to filter the table results by colour.
I can do it no problem with having a filter of just one colour, BUT the problem comes along with two colours.
If I want to see which user has selected for example Blue AND Red, I get a result of zero.
How can I get this result, without creating a search which results in each row being dedicated to a colour and then in turn showing the same user twice (one for red one for blue).
I hope this makes sense
THANKS IN ADVANCE
EDIT
An example query I have used is
SELECT * FROM users, colours, link WHERE users.id = link.name AND link.colour = colours.id
Alternatively to show for specific colour
SELECT * FROM users, colours, link WHERE users.id = link.name AND link.colour = colours.id AND link.colour = 1
But for double filter which shows duplicates
SELECT * FROM users, colours, link WHERE users.id = link.name AND link.colour = colours.id AND link.colour = 1 OR link.colour = 2
If that looks right here is the code:
SELECT Name FROM users
WHERE ID IN (SELECT DISTINCT(Name) AS Name
FROM link L
WHERE 2 IN (SELECT Colour FROM link L2 WHERE L.Name = L2.Name)
AND 1 IN (SELECT Colour FROM link L2 WHERE L.Name = L2.Name))
And now let me try to explain what L and L2 are... First sorry for my English I'll do my best to make a sense for you...
We make subquery on the same table here so we need to use alias for the table. Alias we use to give temporary name table or column which will be used only for that query.
Example for alias is when we select some column from table (Price and Quantity) and let's say we want to calculate Price * quantity and SELECT that column as total (total will be the name of that column in table which we return after we execute the query). Column name total well be give alias. we crate alias like:
SELECT Price, Quantity, (Price * Quantity) AS **total**
FROM t1...
That will return table with three column Price, Quantity, Total... if we don't use this AS total the name of that column will be Price * Quantity...
So here we use L and L2 just to know which column Name is from which part of SELECT query. If we wouldn't use alias in subquery
SELECT Colour FROM link L2 WHERE L.Name = L2.Name
we would have problem because subquery which locks like this:
SELECT Colour FROM link WHERE Name = Name
Doesn't make a a lot of sense, isn't it?
So basically we temporary rename table in this query because we need to know which column from which table we compere whit other one, in other way database will have a problem what to select...
I hope this make a sense for you. If you have any further question fill free to ask I will do my best to try to explain it to you.
I hope i didn't make it more complicated than it is...
GL!
EDIT
Hi there again, i worked something and and i figured out that your question probably have better answer than the first i give you... Hope it's not too late!
SELECT u.Name
FROM users u
INNER JOIN link L
ON u.ID = L.Name
INNER JOIN link l2
ON L.Name = L2.Name
WHERE L.Colour = 2 AND L2.Colour = 1
Look SQL Fiddle for that...

Customer reviews and calendar entries, etc in a database

How would things like customer reviews be stored in a database? I cant imagine there would be rows for each item and columns for each review as one product may have 2 reviews and another may have 100+ - id presume they were stored in a separate file for reviews but then surely not one file per item! I dont know enough about storing data to be able to figure this one out by myself!
A similar situation is something like an online calendar - there is all the information about each appointment (time, duration, location, etc) and there can be many of these on each day, every day, for all users! A logical way would be to have a table for each user with all their appointments in, but at the same time that seems illogical because if you have 1000+ users, thats alot of tables!
Basically Id like to know what the common/best practice way is of storing this 'big dynamic data'.
Customer reviews can easily be stored by using two tables in one-to-many relationship.
Suppose you have a table containing products/articles/whatever worth reviewing. Each of them has an unique ID and other attributes.
Table "products"
+-------------------------------------+
| id | name | attribute1 | attribute2 |
+-------------------------------------+
Then you make another table, with its name indicating what it's about. It should contain at least an unique ID and a column for the IDs from the other table. Let's say it will also have an email of the user who submitted the review and (obviously) the review text itself:
Table "products_reviews"
+--------------------------------------------+
| id | product_id | user_email | review_text |
+--------------------------------------------+
So far, so good. Let's assume you're selling apples.
Table "products"
+-------------------------------+
| 1 | 'Apple' | 'green' | '30$' |
+-------------------------------+
Then, two customers come, each one buys one apple worth 30$ and likes it, so they both leave a review.
Table "products_reviews"
+-------------------------------------------------------------------------------+
| 1 | 2 | alice#mail.com | 'I really like these green apples, they are awesome' |
| 2 | 2 | bob#mail.com | 'These apples rock!' |
+-------------------------------------------------------------------------------+
So now all you have to do is to fetch all the reviews for your apples and be happy about how much your customers like them:
SELECT *
FROM products_reviews
INNER JOIN products ON products_reviews.product_id = products.id
WHERE products.name = 'Apple';
You can now display them under the shopping page for apples (just don't mention they cost 30$).
The same principle applies for things like an online calendar. You have one table with users, and many tables with other stuff - appointments, meetings, etc. which relate to that user.
Keep in mind, however, that things like meetings are better displayed in a many-to-many table, since they are shared by many people (usually). Here's a link that visualizes it very good, and here's a question here on SO with sample code for PHP. Go ahead and test it for yourself.
Cheers :)

MySQL JOIN Many tables to get a list of criteria into one table

I am trying to figure out how to use ONE table JOIN to get a list of vehicle MAKE, MODEL, YEAR, and TRIMS criteria, available for the customer to search from.
There are already master key tables, from which the admin selects from a range of vehicle options and enters these vehicle related details about that product to the PRODUCT table.
I want to now produce a list for the shopper, that reflects only the available vehicle details choices - based on what has been entered into the PRODUCTS table by the admin.
I have been looping / iterating over the MAKE MODEL TRIMS tables with PHP and searching the PRODUCTS table for the existence of the MAKE MODEL YEAR TRIM type in the table of PRODUCTS. But it is taking about 800 individual calls to the PRODUCTS table.
It is understood that this is not the best practice and could cause all sorts of problems - being way to many calls to the database and not efficient.
I am told in another question
https://stackoverflow.com/questions/13960571/sanity-check-mysql-whats-reasonable-800-calls-to-the-database-in-one-second
that this can be done with one call using JOIN and WHERE statements.
I have used table JOINS before, but do not see how this could be done with one call on these many MAKES, MODELS, YEARS, TRIMS to produce one list of available MAKES, MODELS, YEARS, TRIMS criteria for the shopper to choose from.
I would appreciate anything I can learn about this here from your examples : )
Here is an example of the admin master key selection tables for adding vehicle related details to the product entry record:
Table: MAKES
| Id | MAKE | // Admin table for selecting products related vehicle make
------------------
| 1 | FORD |
| 2 | CHEV |
| 3 | GMC |
| 4 | HONDA |
etc.
Table: FORD
| Id | MODEL | // Admin table for selecting products related vehicle model
------------------
| 1 | F150 |
| 2 | ESCAPE |
| 2 | EXPLORER |
etc.
Table: FORD_F150_YEARS_TRIMS
| Id | YEARS| TRIMS | // Admin table for selecting products related vehicle year and trim(s)
--------------------------------------------
| 1 | 1999 | 1999_SPORT+1999_SPORTRAC+1999_XLT+1999_XLS |
| 2 | 2000 | 2000_XLT+2000_XLS+2000_LTD+2000_EDDIE_BAUER |
| 3 | 2001 | 2001_SPORTRAC+2001_XLT+2001_LTD |
etc.
Here is the products table that the admin is entering the product / vehicle details:
Table: PRODUCTS
| PRODUCT_ID | MAKE | MODELS | YEARS | TRIMS |
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 123456 | FORD FORD GMC | F150 ESCAPE CANYON | 2000 2001 1999 | FORD_F150_1999_SPORT+FORD_F150_1999_SPORTRAC+GMC_CANYON_1999_LTD+GMC_CANYON_1999_LTD |
| 123457 | FORD GMC CHEV | F150 EXPLORER SILVERADO | 2000 2010 2010 | FORD_F150_2001_XLT+FORD_F150_2001_LTD+GMC_CANYON_2010_XLT+CHEV_SILVERADO_1500_2010_LTD |
etc.
What I want to do is - make a query on the PRODUCTS table where I can produce a table or list of only the vehicle types that there are products for.
So, if there is NOT a product in the PRODUCTS table that fits a 2001 FORD F150 with a SPORTRAC trim - then I do not want to give the shopper the choice of SPORTRAC with 2001 FORD F150 but I do want to give them the choice of 2001 FORD F150 with XLT + LTD
So really - I just want to eliminate choices for the shopper for products vehicle details that don't exist.
I am told that this can be done in one MySQL call to the database. I am told that instead of looping through all the makes, models and trims and making individual calls to the PRODUCTS table - I can somehow use table joins and while statements to get a list of all the potential MAKE MODEL TRIMS choices available for the customer based on what is in the PRODUCTS table only
I see how I could do this by making one call to the PRODUCTS table and then looping through and weeding out duplicates on the result with PHP. But there are thousands of products and these could gro - so I am looking for the best practice method of achieving this.
Well it seems you first and foremost problem is that you have these different tables but you are not using them in a relational manner. You should really spend some time learning about how to properly normalize your tables. As a general guideline, you should really think about how real world items/properties that you are related to one another and express that relationship through proper primary and foreign key usage.
Your products should relate to the makes, models, trims, etc. via the various primary key id's, not by duplicating the data in the products tables. You also shouldn't have a 'Ford' table for example, but rather just a table with of 'models'.
Just as a sample, I might have a schema like this
models
---------
model_id
make_id
model
makes (Make is really just a property of the model of car, and could possibly be de-normalized into models table. Here I am showing it as separate table to show a fully normalized example.)
---------
make_id
make
trims ('SPORT+XLS' unless those represent a specific trim combination. Each different trim package should have its own row)
--------
trim_id
trim
products (I am assuming that a model and year define a product, by looking at your example data)
--------
product_id
year
model_id
product_trims (many-to-many table expressing relation of products to trims - you could have multiple rows with same product_id and different trim id)
-------------
product_id
trim_id
If you really want to have a product defined as a combination of year, model, and trim, you could eliminate the product_trims table and just have a revised product table like this
product
-------------
product_id
year
model_id
trim_id
You could then query across joins to get the data you need. For example, let's say the user has specified a model and a year. The query might look like the following (showed assuming use of both products and products_trim tables)
SELECT p.product_id, p.year, ma.make, mo.model, t.trim
FROM
products AS p
INNER JOIN models AS mo ON p.model_id = mo.model_id
INNER JOIN makes AS ma ON mo.make_id = ma.make_id
INNER JOIN product_trims AS pt ON p.product_id = pt.product_id
INNER JOIN trims AS t ON pt.trim_id = t.trim_id
WHERE p.year = '?' AND p.model_id = ?
Of course, you need to properly index all the filed used for joins and for any WHERE or ORDER BY conditions.

Categories