querying multiple tables with multiple GET functions using 1 query - php

I am trying to query 6 separate tables in my mysql database, the structures are as follows;
item
itemitemid | item | description | brand | date | time | path |
actor
actoractorid | name | actorthumb | bio |
brand
brandbrandid | brandname | description | image |
movie
moviemovieid | title | genre | year | moviethumb | synopsis|
user
userid | name | surname | email | password |
request
requestid | userid | itemid | brandid | movieid | actorid | content | requestdate |
By clicking a link to a page called style.php using the get commands I can view the request and the info within it by pulling it from the joined tables. For example where the requestid=1 I can see the movie in the request, the actor in the movie, the item of clothing they were wearing and its brand. By using the following 4 querys;
Movie
$requestid = $_GET['requestid'];
$query = "SELECT * FROM movie, request WHERE movie.movieid =
request.movieid and requestid = ".$requestid;
Actor
$requestid = $_GET['requestid'];
$query = "SELECT * FROM actor, request WHERE actor.actorid =
request.actorid and requestid = ".$requestid;
Item
$requestid = $_GET['requestid'];
$query = "SELECT * FROM item, request WHERE item.itemid =
request.itemid and requestid = ".$requestid;
Brand
$requestid = $_GET['requestid'];
$query = "SELECT * FROM brand, request WHERE brand.brandid =
request.brandid and requestid = ".$requestid;
Therefore I would like to combine the 4 querys above into 1 single query that would allow me to show all the info, including querying the user and request tables to show who logged the request, please advise?

SELECT * FROM request r
INNER JOIN movie m ON m.movieid = r.requestid
INNER JOIN actor a ON a.actorid = r.requestid
INNER JOIN item i ON i.itemid = r.requestid
INNER JOIN brand b ON b.brand_id = r.requestid
WHERE r.requestid = {your request id}
Of course, if there is a possibility one of the joins will fail (e.g., a movie without a brand) then use a left join instead.
Also, isnt a bit strange that all of your primary keys are equal? You could get away with never selecting from the request table if this is truly the case:
SELECT * FROM movie m
INNER JOIN actor a ON a.actorid = m.movieid
INNER JOIN item i ON i.itemid = m.movieid
INNER JOIN brand b ON b.brand_id = m.movieid
WHERE m.movieid = {your request id}

First: if you are not using mysql_real_escape_string() on your database inputs, you are asking for a LOT of trouble.
Second: SELECT * should not be used this way... you can get duplicate column names which will make your life very difficult very quickly. It takes a bit more up-front time, but specify the columns you want to return.
Third: you can join all of these, if you want to get a lot of columns back, and a lot of rows with duplicate data:
$requestid = mysql_real_escape_string($_GET['requestid']);
$query = "select r.requestid, m.*, a.*, i.*, b.* FROM request r INNER JOIN movie m ON m.movieid = r.movieid INNER JOIN actor a ON a.actorid = r.actorid INNER JOIN item i ON i.itemid = r.itemid INNER JOIN brand b ON b.brandid = r.brandid WHERE r.requestid = $requestid";
you also might want to use LEFT OUTER JOIN if some of these rows won't join up.

Related

join 3 tables with where clause

This query performs three JOIN operations with 3 tables. But is not ok i see..i'm trying to output all the rows in echo, but i have bad luck.
Mysql table columns:
tours
------
titlu_slider | desc_slider | poza_slider | poza_articol | pret
tours_review
----------
name | time_added | review_text
tours_overview
------------
descriere | titlu_box1 | desc_box1 | titlu_box2 | desc_box2 | titlu_box3 | desc_box3 | titlu_box4 | desc_box4
Php code:
<?php
$db = mysqli_connect("localhost", "root", "fidodido", "antonytravel");
$q = mysqli_query($db,"SELECT * FROM tours INNER JOIN tours_review INNER JOIN tours_overview WHERE id = ".$_GET['id']."");
while ($row = mysqli_fetch_assoc($q)) {
$titlu_slider=$row['titlu_slider'];
$desc_slider=$row['desc_slider'];
$poza_slider=$row['poza_slider'];
$poza_articol=$row['poza_articol'];
$pret=$row['pret'];
## Review table
$name_review=$row['name'];
$time_added=$row['time_added'];
$review_text=$row['review_text'];
## Overview table
$descriere=$row['descriere'];
$titlu_box1=$row['titlu_box1'];
$desc_box1=$row['desc_box1'];
$titlu_box2=$row['titlu_box2'];
$desc_box2=$row['desc_box2'];
$titlu_box3=$row['titlu_box3'];
$desc_box3=$row['desc_box3'];
$titlu_box4=$row['titlu_box4'];
$desc_box4=$row['desc_box4'];
echo '<section class="parallax_window_in" data-parallax="scroll" data-image-src="'.$poza_slider.'" data-natural-width="1400" data-natural-height="470">
<div id="sub_content_in">
<div id="animate_intro">
<h1>'.$titlu_slider.'</h1>
<p>"'.$desc_slider.'"</p>
</div>
</div>';
Some help needed..thanx.
You need to specify how how the tables relate to each other which might look something like the on conditions shown below (which are just guesses)
SELECT *
FROM tours t
INNER JOIN tours_review trev ON t.id = trev.tour_id
INNER JOIN tours_overview tovr ON = t.id = tovr.tour_id
WHERE t.id = $whatever
You then face the issue of what type of join because if you have a tour with no reviews then you probably still want to list it. For that type of relationship you need an "outer join".
SELECT *
FROM tours t
LEFT OUTER JOIN tours_review trev ON t.id = trev.tour_id
INNER JOIN tours_overview tovr ON = t.id = tovr.tour_id
WHERE t.id = $whatever
If every every tour has an "overview" then that can remain an "inner join"
EDIT: Please note that you need to prefix EVERY column reference with a table name or table alias (I have used table aliases to make the query shorter). If you don't do this your query may fail, e.g. if every table has a column id and you just ask for where id = 123 the query will not know which table to use and the query would error.
INNER join shows the records if there are matching record. Use OUTER join to show all records if it does not exists on other tables.
You are missing a few things in your query. Specifically related to the fields that link the tables. To do these joins the best practice is to name each table and then use that name to in an ON statement to JOIN the tables
So
SELECT * FROM tours
INNER JOIN tours_review
INNER JOIN tours_overview
WHERE id = ".$_GET['id'].""
Should be:
SELECT * FROM tours AS t
INNER JOIN tours_review AS r ON r.somefield = t.somefield
INNER JOIN tours_overview AS o ON o.somefield = t.somefield
WHERE id = ".$_GET['id'].""
MySQL can't join tables if it doesn't know what is connecting them.

INNER JOIN mysql from one table to another where its based on multiples of same id

I have an table called product which lets say looks like this:
product
product_id | cults_id1 | cults_id2 | cults_id3
-----------------------------------------------------
1 | 5 | 4 | 2
And the also a table thats based on this called cultivar:
cultivar
cults_id | cults_name |
-------------------------
1 | berries |
2 | fruit |
3 | choc |
4 | wood |
5 | mysql! |
How would i create an JOIN query to get each name from cultivar table where the product id in product table is the same as cults_id in the cultivar table?
OUTPUT
My Product Cults :
berries, Mysql!, wood, fruit
Dont think an INNER JOIN is the way to go but i would have tried something like this:
$query = "SELECT cultivars.cults_name
FROM product
INNER JOIN wine_cultivar ON wine_cultivar.cults_id = product.cultivar_1_id
INNER JOIN wine_cultivar ON wine_cultivar.cults_id = product.cultivar_2_id
INNER JOIN wine_cultivar ON wine_cultivar.cults_id = product.cultivar_3_id
INNER JOIN wine_cultivar ON wine_cultivar.cults_id = product.cultivar_4_id
";
i tried a inner join multiple times targeting all the ids but dont think this is the way to go. Also this is just a part of my sql query.
Simply assign table aliases to each self join and then reference corresponding fields in SELECT.
Right now you join to same table but do not provide aliases to distinguish between the four which MySQL should have raised its Error #1066 for this attempt.
SELECT p.product_image_path, p.product_id, p.brand_name, p.product_name, b.botttle_size, v.vintage,
t.wine_type_blend, p.price, p.quantity, p.time_created, p.reference_number, p.shipping_cost,
c1.cultivar_type as cultivar_type1, c2.cultivar_type as cultivar_type2,
c3.cultivar_type as cultivar_type3, c4.cultivar_type as cultivar_type4
FROM product p
INNER JOIN wine_bottle b ON b.bottle_id = p.bottle_id
INNER JOIN wine_vintage v ON v.vintage_id = p.vintage_id
INNER JOIN wine_type t ON t.type_id = p.type_id
INNER JOIN wine_cultivar c1 ON c1.cultivar_id = p.cultivar_1_id
INNER JOIN wine_cultivar c2 ON c2.cultivar_id = p.cultivar_2_id
INNER JOIN wine_cultivar c3 ON c3.cultivar_id = p.cultivar_3_id
INNER JOIN wine_cultivar c4 ON c4.cultivar_id = p.cultivar_4_id

MYSQL joining three tables

I have a simple multiple school management system and I am trying to get total number of teachers, and total number of students for a specific school. My table structures are as follows:
teachers
--------------------------
id | schoolid | Name | etc...
--------------------------
1 | 1 | Bob |
2 | 1 | Sarah|
3 | 2 | John |
students
--------------------------
id | schoolid | Name | etc...
--------------------------
1 | 1 | Jack |
2 | 1 | David|
3 | 2 | Adam |
schools
--------------------------
id | Name | etc...
---------------------------
1 | River Park High |
2 | Stirling High |
I can count just all teachers with the following query:
SELECT COUNT(a.id) AS `totalteachers`
FROM teachers a
LEFT JOIN schools b ON a.schoolid = b.id WHERE b.id = '1'
and similarly I can count the number of teachers with the following query:
SELECT COUNT(a.id) AS `totalstudents`
FROM students a
LEFT JOIN schools b ON a.schoolid = b.id WHERE b.id = '1'
I am however struggling with trying to combine these two queries to get a simple result like this:
totalstudents | totalteachers
--------------------------------
2 | 2
I have tried the following:
SELECT COUNT(a.id) as `totalteachers`, COUNT(c.id) as `totalstudents`
FROM teachers a
LEFT JOIN schools b ON a.schoolid = b.id
LEFT JOIN students c ON c.schoolid=b.id WHERE b.id = '5'
You can do something like this
SELECT
id, name, s.total AS totalstudents, t.total AS totalteachers
FROM schools
JOIN (SELECT schoolid, COUNT(id) AS total FROM teachers GROUP BY schoolid)
AS t ON t.schoolid = id
JOIN (SELECT schoolid, COUNT(id) AS total FROM students GROUP BY schoolid)
AS s ON s.schoolid = id
then you can add where id = 2 or whatever to limit the school.
The problem with the multiple left joins is it generates additional records for each teacher to each student; artifically inflating your counts
There's four ways to solve this: (best imo is what Andrew bone did)
Simply select inline without the joins so the counts are not inflated. (most desirable in my mind as it's easy to maintain)
SELECT (SELECT COUNT(a.id) AS `totalteachers`
FROM teachers a
WHERE A.SchoolID = '1') as TotalTeachers
, (SELECT COUNT(a.id) AS `totalstudents`
FROM students a
WHERE a.SchoolID = '1') as TotalStudents
Use subqueries to get the counts first before the joins, then join. Since count will always be 1 a cross join works.
SELECT totalTeachers, totalStudents
FROM (SELECT COUNT(a.id) AS `totalteachers`
FROM teachers a
LEFT JOIN schools b
ON a.schoolid = b.id
WHERE b.id = '1')
CROSS JOIN (SELECT COUNT(a.id) AS `totalstudents`
FROM students a
LEFT JOIN schools b ON a.schoolid = b.id
WHERE b.id = '1')
Use key word distinct within the count so as not to replicate the counts and negate the artificial inflation (least desirable in my mind as this hides the artifical count increase)
SELECT COUNT(distinct a.id) as `totalteachers`, COUNT(distinct c.id) as `totalstudents`
FROM teachers a
LEFT JOIN schools b ON a.schoolid = b.id
LEFT JOIN students c ON c.schoolid=b.id WHERE b.id = '5'
Another way would be to use a window functions, however these are not available in mySQL.
SELECT COUNT(t.id) AS TotalTeachers, COUNT(st.id) AS TotalStudents
FROM schools s
INNER JOIN teachers t
ON s.id = t.schoolid
INNER JOIN students st
ON s.id = st.schoolid
Try this SQL. I havn't try it but it should work.

MySQL Many to Many select

I'm trying to create a MySQL Many to Many select query. I have three tables:
Profiles
Skills
Profile_skills (Profile ID and Skills ID)
I want to be able to search for a skill (PHP for example) and all profiles with that skill show up in a list, but including all their other skills. Like most freelance sites, so I can also see that they know MySQL etc.
I haven't found or figured out the correct way to get all info about a profile including all their skills. This is my best result so far:
SELECT * FROM profiles INNER JOIN profile_skills ON
profile_skills.profil_id = profiles.profil_id INNER JOIN skills ON
skills.skill_id = profile_skills.skill_id WHERE skill = 'PHP'
But this only gives me the profile with that one skill and not the rest.
Result:
http://imgur.com/E9PEiaU
Expected:
To have the id, Skill "PHP", and the rest of skills, for example "C#" if user id 1 possesses that skill.
http://imgur.com/5bCG4qo
So like this when I search for a profile with a skill, it also shows the rest of that profiles acquired skills.
You can re-join the profile_skills and skills table to get the result you want.
SELECT p.*, s2.*
FROM skills s1
INNER JOIN profile_skills ps1 ON s.skill_id = ps1.skill_id
INNER JOIN profiles p ON ps1.profil_id = p.profil_id
INNER JOIN profile_skills ps2 ON p.profil_id = ps2.profil_id
INNER JOIN skills s2 ON ps2.skill_id = s2.skill_id
WHERE s1.skill = 'PHP'
This will get you a result like this:
| p.id | p.name | s.id | s.skill |
---------------------------------------------
| 1 | rasmus | 1 | PHP |
| 1 | rasmus | 2 | Linux |
| 2 | thomas | 1 | PHP |
| 2 | thomas | 3 | Eating Sandwiches |
There are various different ways to get each profile in one row with a list of skills. One way is with GROUP_CONCAT in MySQL.
SELECT p.profil_id, p.profile_name, GROUP_CONCAT(s2.skill) AS skills
FROM skills s1
INNER JOIN profile_skills ps1 ON s.skill_id = ps1.skill_id
INNER JOIN profiles p ON ps1.profil_id = p.profil_id
INNER JOIN profile_skills ps2 ON p.profil_id = ps2.profil_id
INNER JOIN skills s2 ON ps2.skill_id = s2.skill_id
WHERE s1.skill = 'PHP'
GROUP BY p.profil_id
I added the profile_name column for example, since I don't know what your columns actually are, and you can add other ones, or even still use p.*. Technically, the other columns in profile aren't defined with GROUP BY p.profil_id, and you generally shouldn't select columns that aren't either included in the grouping or some aggregate function, but MySQL will take care of that for you in this case, since they'll all have the same values for each row with the same p.profil_id.
Another way is to just use the first query and do the grouping in PHP:
$previous_id = null;
while ($row = some_fetch_method()) {
if ($row['profil_id'] != $previous_id) {
echo "<h3>$row[profile_name]</h3>";
}
echo "<div>$row[skill]</div>";
}
obviously the HTML won't be quite what you need, but it should be enough to show the general idea.
You probably want a sub query to identify the accounts, and then load details about them with the super query (and GROUP_CONCAT the skills if you want). Something like:
SELECT profiles.*, GROUP_CONCAT(skills.skill SEPARATOR ', ') AS the_skillz
FROM profiles INNER JOIN profile_skills (...) INNER JOIN skills (...)
WHERE profiles.profile_id IN (
SELECT DISTINCT profile_id
FROM profile_skills INNER JOIN skills (...)
WHERE skills.skill = 'PHP'
)
GROUP BY profiles.profile_id;

Save selected in variable and then use that variable for next select

I have multiple tables in my database. Let's say the table users looks like this:
Users:
|id|name|gender|access|id_ext|
|1 | a | m | 1 | 32 |
|3 | b | m | 3 | 33 |
|4 | c | m | 1 | 34 |
|5 | d | f | 1 | 35 |
I would like to select the user with for example id_ext = 32 and then run another select statement using that selected users fields.
I can solve this by first getting the user with a query and then create another query with users info, but there must be a way to do this in the same query?
This is the query i use now:
SELECT * FROM users NATURAL JOIN
(SELECT id FROM ages WHERE age BETWEEN
(SELECT limit_age_l FROM users WHERE id=17)
AND (SELECT limit_age_h FROM users WHERE id=17)) as a
WHERE NOT id = 17
AND locale = 'en_US'
AND limit_gender = 1
AND visible = 0
AND NOT EXISTS (SELECT view_id FROM matches WHERE user_id = 17 AND view_id = a.id)
LIMIT 1
Problem is that the values id=17, limit_gender=1 and locale = 'en_US' in the query are not known. These are taken from the user with id_ext = '32'.
SELECT * FROM Users WHERE id in (SELECT id FROM Users WHERE id_ext='32');
Yes - assuming your subsequnt query is of the form:
select field1, field2, ...
from Table1
join Table2 on ...
where ...
and Table1.id = N /* previously selected id from users */
Then either by using the first query as a subquery:
select field1, field2, ...
from Table1
join Table2 on ...
where ...
and Table1.id = (select id from users where id_ext ='32')
/* replace = with IN if more than one id will be returned */
Or by joining to the results of the first query as part of the subsequent query:
select field1, field2, ...
from users
join Table1 on Table1.id = users.id
join Table2 on ...
where ...
and users.id_ext ='32'
(Note that both of these forms assume that users is not already being joined in the existing query - if it is, just add the users.id_ext ='32' condition to the existing query.)
EDIT: If I have understood the requirements correctly, the required query could be written as:
SELECT u.*
FROM users u
join ages a on u.id = a.id and
u.age between limit_age_l and limit_age_h
join users ul on ul.id = 17 and
ul.id <> u.id and
ul.locale = u.locale and
ul.limit_gender = u.limit_gender and
ul.visible = u.visible
AND NOT EXISTS (SELECT NULL
FROM matches m
WHERE m.user_id = ul.user_id AND m.view_id = a.id)
LIMIT 1
SELECT * FROM users WHERE id = (SELECT id FROM users WHERE id_ext = '32');
Select * from users as user inner join userinfo as usinfo on usinfo.id=user.id_ext where user.id_ext='32'

Categories