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.
Related
I read many threads about getting only the first row of a left join, but, for some reason, this does not work for me.
Here is my structure (simplified of course)
Feeds
id | title | content
----------------------
1 | Feed 1 | ...
Artists
artist_id | artist_name
-----------------------
1 | Artist 1
2 | Artist 2
feeds_artists
rel_id | artist_id | feed_id
----------------------------
1 | 1 | 1
2 | 2 | 1
...
Now i want to get the articles and join only the first Artist and I thought of something like this:
SELECT *
FROM feeds
LEFT JOIN feeds_artists ON wp_feeds.id = (
SELECT feeds_artists.feed_id FROM feeds_artists
WHERE feeds_artists.feed_id = feeds.id
LIMIT 1
)
WHERE feeds.id = '13815'
just to get only the first row of the feeds_artists, but already this does not work.
I can not use TOP because of my database and I can't group the results by feeds_artists.artist_id as i need to sort them by date (I got results by grouping them this way, but the results where not the newest)
Tried something with OUTER APPLY as well - no success as well.
To be honest i can not really imagine whats going on in those rows - probably the biggest reason why i cant get this to work.
SOLUTION:
SELECT *
FROM feeds f
LEFT JOIN artists a ON a.artist_id = (
SELECT artist_id
FROM feeds_artists fa
WHERE fa.feed_id = f.id
LIMIT 1
)
WHERE f.id = '13815'
If you can assume that artist IDs increment over time, then the MIN(artist_id) will be the earliest.
So try something like this (untested...)
SELECT *
FROM feeds f
LEFT JOIN artists a ON a.artist_id = (
SELECT
MIN(fa.artist_id) a_id
FROM feeds_artists fa
WHERE fa.feed_id = f.feed_id
) a
Version without subselect:
SELECT f.title,
f.content,
MIN(a.artist_name) artist_name
FROM feeds f
LEFT JOIN feeds_artists fa ON fa.feed_id = f.id
LEFT JOIN artists a ON fa.artist_id = a.artist_id
GROUP BY f.id
#Matt Dodges answer put me on the right track. Thanks again for all the answers, which helped a lot of guys in the mean time. Got it working like this:
SELECT *
FROM feeds f
LEFT JOIN artists a ON a.artist_id = (
SELECT artist_id
FROM feeds_artists fa
WHERE fa.feed_id = f.id
LIMIT 1
)
WHERE f.id = '13815'
based on several answers here, i found something that worked for me and i wanted to generalize and explain what's going on.
convert:
LEFT JOIN table2 t2 ON (t2.thing = t1.thing)
to:
LEFT JOIN table2 t2 ON (t2.p_key = (SELECT MIN(t2_.p_key)
FROM table2 t2_ WHERE (t2_.thing = t1.thing) LIMIT 1))
the condition that connects t1 and t2 is moved from the ON and into the inner query WHERE. the MIN(primary key) or LIMIT 1 makes sure that only 1 row is returned by the inner query.
after selecting one specific row we need to tell the ON which row it is. that's why the ON is comparing the primary key of the joined tabled.
you can play with the inner query (i.e. order+limit) but it must return one primary key of the desired row that will tell the ON the exact row to join.
Update - for MySQL 5.7+
another option relevant to MySQL 5.7+ is to use ANY_VALUE+GROUP BY. it will select an artist name that is not necessarily the first one.
SELECT feeds.*,ANY_VALUE(feeds_artists.name) artist_name
FROM feeds
LEFT JOIN feeds_artists ON feeds.id = feeds_artists.feed_id
GROUP BY feeds.id
more info about ANY_VALUE: https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
I've used something else (I think better...) and want to share it:
I created a VIEW that has a "group" clause
CREATE VIEW vCountries AS SELECT * PROVINCES GROUP BY country_code
SELECT * FROM client INNER JOIN vCountries on client_province = province_id
I want to say yet, that I think that we need to do this solution BECAUSE WE DID SOMETHING WRONG IN THE ANALYSIS... at least in my case... but sometimes it's cheaper to do this that to redesign everything...
I hope it helps!
Here is my answer using the group by clause.
SELECT *
FROM feeds f
LEFT JOIN
(
SELECT artist_id, feed_id
FROM feeds_artists
GROUP BY artist_id, feed_id
) fa ON fa.feed_id = f.id
LEFT JOIN artists a ON a.artist_id = fa.artist_id
I want to give a more generalized answer. One that will handle any case when you want to select only the first item in a LEFT JOIN.
You can use a subquery that GROUP_CONCATS what you want (sorted, too!), then just split the GROUP_CONCAT'd result and take only its first item, like so...
LEFT JOIN Person ON Person.id = (
SELECT SUBSTRING_INDEX(
GROUP_CONCAT(FirstName ORDER BY FirstName DESC SEPARATOR "_" ), '_', 1)
) FROM Person
);
Since we have DESC as our ORDER BY option, this will return a Person id for someone like "Zack". If we wanted someone with the name like "Andy", we would change ORDER BY FirstName DESC to ORDER BY FirstName ASC.
This is nimble, as this places the power of ordering totally within your hands. But, after much testing, it will not scale well in a situation with lots of users and lots of data.
It is, however, useful in running data-intensive reports for admin.
For some database like DB2 and PostgreSQL, you have to use the key word LATERAL for specifying a sub query in the LEFT JOIN : (here, it's for DB2)
SELECT f.*, a.*
FROM feeds f
LEFT JOIN LATERAL
(
SELECT artist_id, feed_id
FROM feeds_artists sfa
WHERE sfa.feed_id = f.id
fetch first 1 rows only
) fa ON fa.feed_id = f.id
LEFT JOIN artists a ON a.artist_id = fa.artist_id
I know this is not a direct solution but as I've faced this and it's always a huge problem for me, and also using left join select etc. sometimes lead to a heavy process cost in database and server, I prefer doing this kind of left joins using array in php like this:
First get the data in range from second table and while you need just one row from second table, just save them with left join in-common column as key in result array.
SQL1:
$sql = SELECT artist_id FROM feeds_artists fa WHERE fa.feed_id {...RANGE...}
$res = $mysqli->query($sql);
if ($res->num_rows > 0) {
while ($row = $res->fetch_assoc()) {
$join_data[...$KEY...] = $row['artist_id'];
}
Then, get the base data and add detail of left join table from previous array while fetch them like this:
SQL2:
$sql = SELECT * FROM feeds f WHERE f.id {...RANGE...};
$res = $mysqli->query($sql);
if ($res->num_rows > 0) {
while ($row = $res->fetch_assoc()) {
$key = $row[in_common_col_value];
$row['EXTRA_DATA'] = $join_data[$key];
$final_data[] = $row;
}
Now, you'll have a $final_data array with desire extra data from $join_data array. this usually works good for date range data and like this.
Quite simply, I need an MySQL statement that selects all the rows from 2 different tables where userId = 1. Here's the statement I have but it doesn't work. It returns results from table 1 (The left table):
$transactionsQ = $db->query("select e.sender, e.amount, e.timestamp, s.sender, s.recipient, s.amount, s.timestamp from ethTransactions as e, sofTransactions as s where e.userId = ? or s.userId = ?", [$currentUser->id, $currentUser->id]);
table1 (ethTransactions) is like:
|id|userId|sender|amount|timestamp|
table2 (sofTransactions) is like:
|id|userId|sender|recipient|amount|timestamp|
some data on ethTransactions:
1|12|ajdoaidjoiwjdaq|0.03222|2017-11-08 03:09:11
some data on sofTransactions:
1|12|opiyptropyirpyi|dqwuebhdnwq|1.02223|2017-10-08 04:09:11
What I want to return since both have the same userId:
|id|userId|sender |recipient |amount |timestamp |
|1 |12 |ajdoaidjoiwjdaq| |0.03222|2017-11-08 03:09:11|
|1 |12 |opiyptropyirpyi|dqwuebhdnwq|1.02223|2017-10-08 04:09:11|
You should use LEFT JOIN to do that.
SELECT
e.sender as e_sender,
e.amount as e_amount,
e.timestamp as e_timestamp,
s.sender as s_sender,
s.recipient as s_recipient,
s.amount as s_amount,
s.timestamp as as_timestamp
FROM
ethTransactions e
LEFT JOIN
sofTransactions s ON s.userId = e.userId
WHERE
e.userId = ?
SELECT column_names(s) FROM table1 AS t1 **INNER JOIN** table2 AS t2
ON t1.userId = t2.userId WHERE t1.userId=1;
There is something strange about the structure of your database. A JOIN on userid seems natural, but it potentially joins rows from one table with rows from the other table that have different sender columns. This would imply that you are joining data items that do not belong together.
My answer to your question is: redesign your table structure because you are going to break one of the main rules of relational databases - most likely, duplicating data.
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
I have 3 table: user , company and deal.
One user may own several companies. Deal is made between the 2 companies. I need a list of deals, which involved my company.
Deals must contain the following fields: partner_company_id,my_company_id,partner_photo,partner_name,deal_about.
Language code: PHP.
Database: Mysql.
1.List of my company I can get by user ID.
user_id = 22;
companyList = query('SELECT company_id FROM company WHERE user_id = ?', user_id);
2. Then i get deal list where my_company_id is company_first_id
list1 = query('SELECT u.name AS partner_name, u.photo AS partner_photo, d.first_company_id AS
my_company_id , d.second_company_id AS partner_company_id,d.about AS deal_about FROM deal AS d
INNER JOIN company AS c ON c.company_id = d.second_company_id
INNER JOIN user AS u ON u.user_ud = c.user_id
WHERE d.company_first_id IN (?)', companyList);
3. Then i get deal list where my_company_id is company_second_id
list2 = query('SELECT u.name AS partner_name, u.photo AS partner_photo, d.first_company_id AS
partner_company_id , d.second_company_id AS my_company_id,d.about AS deal_about FROM deal AS d
INNER JOIN company AS c ON c.company_id = d.first_company_id
INNER JOIN user AS u ON u.user_ud = c.user_id
WHERE d.company_second_id IN (?)', companyList);
4. then i marge to array and set limit list
list = array_marge(list1,list2);
result = array_slice (list ,0 , 10);
HELP please optimize this queries.
THANKS.
DATABASE SCHEME
user | company | deal |
--------------------------------------------------
user_d | company_id | deal_id
photo | user_id |first_company_id
name | about |second_company_id
| |description
Are your queries so slow? They don't look slow (provided you have indexes on all IDs of course).
However, you can save one database access by combining the two deal queries. Either you simply select query1 UNION ALL query1 or you do it in one pass:
select
u.name AS partner_name,
u.photo AS partner_photo,
d.my_company_id,
d.partner_company_id,
d.about AS deal_about
from
(
select
about,
case when company_first_id in (?) then
company_first_id
else
company_second_id
end as my_company_id,
case when company_first_id in (?) then
company_second_id
else
company_first_id
end as partner_company_id
from deal
where company_first_id in (?) OR d.company_second_id in (?)
) as d
inner join company as c on c.company_id = d.partner_company_id
inner join user as u on u.user_ud = c.user_id
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.