I am trying to display information on a website using PHP and MYSQL that shows all the locations an event can take place, along with the facilities each location includes. For example, a park (location1) may contain toilets (facility1), swings (facility3) and a slide (facility4).
Location1 Location2 Location3 Location4
Facility1 x x
Facility2 x x
Facility3 x x
Facility4 x x
Firstly, I am unsure of the best way to display these as tables in MySQL and then how I would display this clearly using PHP calls onto a webpage.
Any help would be appreciated
Database schema
I would like to recommend you to create 3 tables in your database:
locations
facilities
location_facility
Locations table
+----+------------+
| id | name |
+----+------------+
| 1 | location_1 |
| 2 | location_2 |
+----+------------+
Facilities table
+----+------------+
| id | name |
+----+------------+
| 1 | facility_1 |
| 2 | facility_2 |
| 3 | facility_3 |
+----+------------+
Pivot table (location_facility)
+-------------+-------------+
| location_id | facility_id |
+-------------+-------------+
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 3 |
+-------------+-------------+
So, in pivot table you can store required information.
PHP application meta code
To get the data from your database in pure PHP - you can use PDO extension.
$sql = 'SELECT locations.name as loc_name,
facilities.name as facility_name
FROM location_facility
INNER JOIN locations ON locations.id = location_facility.location_id
INNER JOIN facilities ON facilities.id = location_facility.facility_id';
foreach ($conn->query($sql) as $row) {
print $row['loc_name'] . "\t";
print $row['facility_name'] . "\n";
}
In the database it is only one additional table, holding both PK from the related tables.
For display you'd choose a "master-detail" view: seleting one item from either table (master), showing all related records from the other (detail).
As others had commented, the tables required a third pivot table to connect the facilities and the location tables so many thanks for that. However, the next issue that arose was using these tables and connecting them to allow searches by facilities.
Hence an SQL query that grouped the facilities into one column within a view alongside all information from the location table.
CREATE VIEW locations AS
SELECT location.*, group_concat(facilities.FacilityName separator ',') AS facility_name
FROM location_facility
INNER JOIN location
ON location.LocationID = location_facility.LocationID
INNER JOIN facilities
ON facilities.FacilitiesID = location_facility.FacilitiesID
GROUP BY location.LocationName
ORDER BY location.LocationID ASC
This table can be queried using
SELECT *
FROM locations
WHERE facility_name LIKE %Toilet% AND facility_name LIKE %Parking%
This solved my issues and allowed the data to be displayed on a webpage exactly how I had desired.
Thanks again for the comments and help all!
Related
purpose: I have been tasked with exporting a complex dataset from a PHP counseling appointment webapp, and convert it into an excel file containing student data sorted by their STUDENT_ID.
I have 3 MySQL tables containing data. They all have a STUDENT_ID field.
I need to make a query which retrieves all the data from the 4 tables, grouping into a single row based on STUDENT_ID.
Some of the tables contain multiple entries for the same STUDENT_ID. If possible I'd like these multiple entries combined into a single row (so that each unique STUDENT_ID is on one line).
This is what I have so far but it doesn't seem to work how I expect it to.
SELECT *
from ssp_student t1
INNER JOIN ssp_student_quarterly t2
ON t1.STUDENT_ID = t2.STUDENT_ID
INNER JOIN ssp_weekly_progress t3
ON t2.STUDENT_ID = t3.STUDENT_ID
GROUP BY t1.STUDENT_ID
Table Schema:
Table 1:
| STUDENT_ID | PEER_COACH_ID | ACTIVE | COHORT | WEEKLY_MEETING_TIME | FYE_ID | RC | AGREEMENT_SIGNED | RELEASE_SIGNED | NOTES | FACULTY_ADVISOR |
Table 2:
| STUDENT_ID | QUARTER | COUNSELLING_OFFICE | WRITING_CENTER | CASE_MANAGEMENT | SSP_SOCIAL_EVENTS | SSP_SUCCESS_SEMINAR | HOME_SUPPORT | ACCOMODATION_USED | DISCOVERY_PATHWAYS | PEER_COACHING |
Table 3:
| STUDENT_ID | QUARTER | WEEK | EMAIL_INTERACTION | PHONE_INTERACTION | TEXT_INTERACTION | INPERSON_INTERACTION | SOCIAL_INTERACTION | NUMBER_OF_SOCIAL_INTERACTIONS | CASE_MANAGEMENT_INTERACTIONS | NUMBER_OF_CASE_mANAGEMENT_INTERACTIONS | SUCCESS_SEMINAR_INTERACTION | NUMBER_OF_SUCCESS_SEMINAR_INTERACTIONS | OTHER_INTERACTION | THEMES | SURVEY_ID | NOTES |
what I need: I want 1 row for each STUDENT_ID, which contains columns for all the data associated with that STUDENT_ID in tables 1, 2 and 3.
if you use SELECT * and you say that some of the tables contain more than one row for the same student, you will never get only one row. Try to select the fields related to the student id that you want to display.
If any of the fields that you want to display is one of the multiple-entry, then it will not work, it will display one row per entry.
If you really want to concatenate the data for each row into one field, your SELECT statement you could do something like the following:
SELECT t1.STUDENT_ID, GROUP_CONCAT(t2.Field1 SEPARATOR ', ') AS t2Field1Concat,
GROUP_CONCAT(t2.Field2 SEPARATOR ', ') AS t2Field2Concat,
GROUP_CONCAT(t3.Field1 SEPARATOR ', ') AS t3Field1Concat,
GROUP_CONCAT(t3.Field2 SEPARATOR ', ') AS t3Field2Concat
In the above example you would have to do this for each field other than t1.STUDENT_ID.
You seem to be after 4 separate groups of data that have virtually nothing in common other than the student ID. You should perform a single query for each and then combine the data into a relevant format in PHP.
Joining all 4 tables together like this is going to end up with a potentially MASSIVE result set full of duplicate data.
I have run into a problem that I'm sure is easy to achieve. I have a table for some merchandise. It holds all the information including the id for the manufacturer. The information about the manufacturer is in a separate table. When users are searching they have filter options. The one I'm having trouble with is filtering by manufacturer.
Products Table: cs_products
id | name | manufacturer_id
---------------------------
1 | mic | 3
2 | cable | 2
3 | speaker | 1
Manufacturer Table: cs_manufacturer
id | name
------------------
1 | JBL
2 | Rapco
3 | Shure
When the query is ran I need to ORDER BY cs_manufacturer.name:
mysql_query("SELECT * FROM cs_products ORDER BY cs_manufacturer.name")
What is the proper syntax for this?
SELECT * FROM cs_products JOIN cs_manufacturer
ON cs_product.manufacturer_id = cs_manufacturer.id
ORDER BY cs_manufacturer.name
You are missing your join.
SELECT * FROM cs_products
JOIN cs_manufacturer on cs_products.manufacturer_id = cs_manufacturer.id
ORDER BY cs_manufacturer.name
I have currently got a PHP generated calendar displaying some holidays for users. This information is stored in a database, I.e holidays and users. I want a user to be able to select a department and then AJAX will load the holidays for users only in that department.
Here are two made up tables with the same fundamental structure:
Table users
+------------------------------------+
| User | Department |
|------------+-----------------------|
| Brian | Sales |
| Tony | Marketing |
| Carol | Marketing |
| Dave | Warehouse |
| Chris | Warehouse |
+------------------------------------+
Table holiday
+------------------------------------+
| ID | User |
|------------+-----------------------|
| 1 | Dave |
| 2 | Tony |
| 3 | Tony |
| 4 | Chris |
| 5 | Carol |
+------------------------------------+
My current query:
$getAllHols = $con->query("SELECT * FROM `holiday`");
So of course, this just gets all holiday. I'm knowledgable enough on PHP to get a list of users in a specific department and then use that in another query to get holidays for those users. But I don't want to do this. I'm thinking there MUST be a pure-SQL solution. So I need the query to get all records from holiday where the user is in the selected department, using the two tables.
I.E:
If I chose the department "Marketing", records 2, 3 and 5 would be returned. (Tony and Carol are in Marketing).
Very easy problem for an advanced SQL user, I'm sure, but not to me. Can anyone help? Thanks.
Try this.
SELECT * FROM users
LEFT JOIN holiday ON users.user = holiday.user
WHERE holiday.department = 'marketing'
As far as I got...
select user
from users inner join holiday
on users.user = holiday.user
where department = 'Marketing'
This would provide a distinct list of records from the Holiday table if there are any matching records from the Users table. This improves upon the option of joining the tables, as you would not have to worry about de-duping the resulting data.
select distinct h.id, h.user
from holiday h
where h.user in (select u.user
from user u
where u.department = 'Marketing')
;
I am new to the world of mysql and I'm having some trouble getting the data I need from a database.
The 2 tables I have are...
Results
ID | TITLE | LOTS OF OTHER DATA |
1 | res1 | |
2 | res2 | |
3 | res3 | |
4 | res4 | |
5 | res5 | |
Categories
ID | RESULT_ID | CATEGORY NAME |
1 | 1 | purchase |
2 | 1 | single_family |
3 | 1 | conventional |
4 | 2 | usda |
5 | 3 | somecategory |
I'm trying to create a query that will select results that belong to all of the categories provided in the query. For example a query for purchase & single_family & conventional in this example would return the first result in the results table.
Does that make sense? Is there a query that will do this or is this more of a problem with my database structure?
Thanks a lot!
Try something like this:
SELECT * FROM Results r
INNER JOIN Categories c on r.ID = c.RESULT_ID
WHERE c.name in ('purchase', 'single_family', 'conventional')
GROUP BY r.ID
HAVING COUNT(c.ID) = 3
The basic select with join will get you three rows only for result 1.
Edit: To make sure your code won't break if you change your database you should always select the fields you want explicitly: SELECT r.ID, .. FROM ..
So you're basically doing a simple join with all the category table for all categories where the category name is one of the names in the list. Try to run the 3 first lines manually to see the result you get.
Next you group by the result id. This means that you are aggregating all the rows sharing the same result id into one row. The last line means that we are filtering the aggregated columns that are aggregated by 3 rows. That means that you will only return results that have 3 matching categories.
So the only problem with this approach is if you have duplicate result_id, categoryname in your Categories table.
i have a form that has a multiple select drop down. a user can select more than one options in the select. the name of the select is array[]; using php I call implode(",",$array)
in mysql db, it stores the field as a text in this format "places"= "new york, toronto, london" when i want to display these fields i explode the commas.
I am trying to run a report to display the places. here is my select:
"select * from mytable where db.places .. userSelectedPlaces"
how can i check toronto in lists of "places" that user selected? note "places" in the db might be either just "toronto" or it might be comma separated lists of places like "ny, toronto, london, paris, etc".
If it is possible, you would be much better off using another table to hold the places that the user has selected. Call it SelectedPlaces with columns:
mytable_id - To join back to the table in your query
place - EG: "Toronto"
Then you can run a simple query to figure out if Toronto has been selected:
SELECT *
FROM mytable m
INNER JOIN SelectedPlaces sp ON sp.mytable_id = m.id
WHERE sp.place = 'Toronto'
If I understand you correctly, your database design is just wrong. Try reading about it more. Generally, in good design you should not have lists of values as one field in database and you should introduce new table for it.
But if you want to do it this way, you can use strcmp function.
If i understood correctly, this should work:
WHERE DB.PLACES LIKE '%TORONTO%'
but as other users said, its not a nice thing to have denormalized tables.
To directly answer your question, your query needs to look something like this
SELECT *
FROM mytable
WHERE places LIKE( '%toronto%' )
But, be aware, that LIKE() is slow.
To indirectly answer your question, your database schema is all wrong. That is not the right way to do a M:N (many-to-many) relationship.
Imagine instead you had this
mytable place mytable_place
+------------+ +----------+----------+ +------------+----------+
| mytable_id | | place_id | name | | mytable_id | place_id |
+------------+ +----------+----------+ +------------+----------+
| 1 | | 1 | new york | | 1 | 1 |
| 2 | | 2 | toronto | | 1 | 2 |
| 3 | | 3 | london | | 1 | 3 |
+------------+ +----------+----------+ | 2 | 2 |
| 3 | 1 |
| 3 | 3 |
+------------+----------+
The table mytable_places is what's called a lookup table (or, xref/cross-reference table, or correlation table). Its only job is to keep track of which mytable records have which place records, and vice versa.
From this example we can see that The 1st mytable record has all 3 places, the 2nd has only toronto, and the 3rd has new york and london.
This opens you up too all sorts of queries that would be difficult, expensive, or impossible with your current design.
Want to know how many mytable records have toronto? No problem
SELECT COUNT(*)
FROM mytable_place x
LEFT JOIN place p
ON p.place_id = x.place_id
WHERE p.name = 'toronto';
How about the number of mytable records per place, sorted?
SELECT p.name
, COUNT(*) as `count`
FROM mytable_place x
LEFT JOIN place p
ON p.place_id = x.place_id
GROUP BY p.place_id
ORDER BY `count` DESC, p.name ASC
And these are going to be much faster than any query using LIKE since they can use indexes on columns such as place.name.