php mysql join 3 tables - mysql

Im looping through a feedback type comment system on a users page, finding the latest 6 posts.
To display the post how I want, I have to grab data from 3 tables.
I figure it'd be less db intensive if it was all pulled in one query, but I'm not sure how to write it, being suck at JOINs and things.
This is my existing code
$sql_result = mysql_query("SELECT * FROM feedback WHERE user='1' ORDER BY date desc LIMIT 6", $db);
while($rs = mysql_fetch_array($sql_result)) {
$sql_result2 = mysql_query("SELECT * FROM members WHERE id= '$rs[author]'", $db);
$rs2 = mysql_fetch_array($sql_result2);
if ($rs2[clan] != 0) {
$sql_result3 = mysql_query("SELECT * FROM clans WHERE id= '$rs2[clan]' LIMIT 1", $db);
$rs3 = mysql_fetch_array($sql_result3);
// write comment
Can someone give me a clue?

This should do it:
select * from feedback
left join members on feedback.author = members.id
left join clans on members.clan = clans.id
where feedback.user = 1
left join means if the table on the right has no matching row, a record with all null values is returned, so you still get the data from the table on the left.

I am no expert in Sql myself, but I have picked up a few tricks here and there :-)
A typical LEFT JOIN that works in Firebird is :
select A.*,B.*,C.*
from FEEDBACK A left join MEMBERS B
on A.USER = B.ID left join CLANS C
ON C.ID = A.USER
where A.USER=1
The logic behind the join is that All rows that now share the same value,
A.USER = B.ID = C.ID will now be visible.
The letters A B and C is just used for simplicity.
F, M and C will work the same way.
This Left Join will pick out all and every column in tables. This is done with A.*,B.*,C.*
Maybe you want only a few columns in each table.
That can be accomplished by naming the columns in the same manner.
Example:
A.USER,A.FIRSTNAME,A.SURNAME,B.COLNAME1,B.COLNAME2,C.COLNAME1,C.COLNAME2
When you need to adress the columns later, remember the Prefix of A. or B. or C. before the actual column-name you address.
Good luck and best regards.
Morten, Norway

Related

how to change this mysql query to a efficient one

my table user contains these fields
id,company_id,created_by,name,image
table valet contains
id,vid,dept_id
table cart contains
id,dept_id,map_id,purchase,time
to get the details i have written this mysql query
SELECT c.id, a.id, c.purchace, c.time
FROM user a
LEFT JOIN valet b ON a.vid = b.id
AND a.is_deleted = 0
LEFT JOIN cart c ON b.dept_id = c.dept_id
WHERE a.company_id = 18
AND a.created_by = 102
AND a.is_deleted = 0
AND c.time
IN ( SELECT MAX( time ) FROM cart WHERE dept_id = b.dept_id )
from these three table i want to select last updated raw from cart along with id from user table which is mapped in valet table
this query works fine but it takes almost 15 sec to retrieve the details .
is there any way to improve this query or may be i am doing some wrong.
any help would be appreciated
For one thing, I can see that you’re running the subquery for each row. Depending on what the optimiser does, that may have an impact. max is a pretty expensive operation (there’s nothing for it but to read every row).
If you plan to update and use this query repeatedly, perhaps you should at least index the table on cart.time. This will make it much easier to find the maximum value.
MySQL has the concept of user variables, so you can set a variable to the result of the subquery, and that might help:
SELECT c.id, a.id, c.purchace, c.time
FROM
user a
LEFT JOIN valet b ON a.vid = b.id AND a.is_deleted = '0'
LEFT JOIN cart c ON b.dept_id = c.dept_id
LEFT JOIN (SELECT dept_id,max(time) as mx FROM cart GROUP BY dept_id) m on m.dept_id=c.dept_id
WHERE
a.company_id = '18'
AND a.created_by = '102'
AND a.is_deleted = '0'
AND c.time=m.mx;
Note also:
since you’re only testing a single value (max) for c.time, you should be using = not in.
I’m not sure about is why you are using strings instead of integers. I shold have though that leaving off the quotes makes more sense.
Your JOIN includes AND a.is_deleted = '0', though you make no mention of it in your table description. In any case, why is it in the JOIN and not in the WHERE clause?

optimizing query (LEFT JOIN)

My goal is to show search results of companies both: with categories and without (not added yet). My companies table has more or less 12 000 records. Companies with categories are only more or less 200.
There are two search inputs:
$name -> name of company or category.
$id_country -> id of the country
I want to display:
1) how many results is in all database. (that's why i use: SQL_CALC_FOUND_ROWS)
2) i use LIMIT to show 10 results per page (with pagination).
My query:
SELECT SQL_CALC_FOUND_ROWS
c.*,
lc.name as langName,
lc.shortDesc,
lc.longDesc
FROM companies c
JOIN lang_companies lc USING(id_company)
LEFT JOIN categories_companies cc USING(id_company)
LEFT JOIN lang_categories lang_cat USING (id_category)
WHERE
lc.id_lang = '2' AND c.status = 1 AND c.active = 1 AND c.id_country = ".$id_country." AND
(lc.name = LCASE('".$name."') OR (lang_cat.name = LCASE('".$name."') AND lang_cat.id_lang = '2')
OR c.city = '".$name."')
GROUP BY c.id_company
ORDER BY c.id_hierarchi asc
LIMIT 0, 10
This query executes more or less 6 seconds and I want to optimize it. Could you help me?
I will be grateful for any suggestions.
Out of the FROM part of your query, you do not seem to actually use the tables which are joined with these two lines:
LEFT JOIN categories_companies cc USING(id_company)
LEFT JOIN categories cat USING (id_category)
I presume you can simply exclude them from the query, if they are not relevant through something more sublte like the join suppressing rows.

Replacing Subqueries with Joins in MySQL

I have the following query:
SELECT PKID, QuestionText, Type
FROM Questions
WHERE PKID IN (
SELECT FirstQuestion
FROM Batch
WHERE BatchNumber IN (
SELECT BatchNumber
FROM User
WHERE RandomString = '$key'
)
)
I've heard that sub-queries are inefficient and that joins are preferred. I can't find anything explaining how to convert a 3+ tier sub-query to join notation, however, and can't get my head around it.
Can anyone explain how to do it?
SELECT DISTINCT a.*
FROM Questions a
INNER JOIN Batch b
ON a.PKID = b.FirstQuestion
INNER JOIN User c
ON b.BatchNumber = c.BatchNumber
WHERE c.RandomString = '$key'
The reason why DISTINCT was specified is because there might be rows that matches to multiple rows on the other tables causing duplicate record on the result. But since you are only interested on records on table Questions, a DISTINCT keyword will suffice.
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
Try :
SELECT q.PKID, q.QuestionText, q.Type
FROM Questions q
INNER JOIN Batch b ON q.PKID = b.FirstQuestion
INNER JOIN User u ON u.BatchNumber = q.BatchNumber
WHERE u.RandomString = '$key'
select
q.pkid,
q.questiontext,
q.type
from user u
join batch b
on u.batchnumber = b.batchnumber
join questions q
on b.firstquestion = q.pkid
where u.randomstring = '$key'
Since your WHERE clause filters on the USER table, start with that in the FROM clause. Next, apply your joins backwards.
In order to do this correctly, you need distinct in the subquery. Otherwise, you might multiply rows in the join version:
SELECT q.PKID, q.QuestionText, q.Type
FROM Questions q join
(select distinct FirstQuestion
from Batch b join user u
on b.batchnumber = u.batchnumber and
u.RandomString = '$key'
) fq
on q.pkid = fq.FirstQuestion
As to whether the in or join version is better . . . that depends. In some cases, particularly if the fields are indexed, the in version might be fine.

Optimizing a where statement MYSQL

Im writing this complex query to return a large dataset, which is about 100,000 records. The query runs fine until i add in this OR statement to the WHERE clause:
AND (responses.StrategyFk = strategies.Id Or responses.StrategyFk IS
Null)
Now i understand that by putting the or statement in there it adds a lot of overhead.
Without that statement and just:
AND responses.StrategyFk = strategies.Id
The query runs within 15 seconds, but doesn't return any records that didn't have a fk linking a strategie.
Although i would like these records as well. Is there an easier way to find both records with a simple where statement? I can't just add another AND statement for null records because that will break the previous statement. Kind of unsure of where to go from here.
Heres the lower half of my query.
FROM
responses, subtestinstances, students, schools, items,
strategies, subtests
WHERE
subtestinstances.Id = responses.SubtestInstanceFk
AND subtestinstances.StudentFk = students.Id
AND students.SchoolFk = schools.Id
AND responses.ItemFk = items.Id
AND (responses.StrategyFk = strategies.Id Or responses.StrategyFk IS Null)
AND subtests.Id = subtestinstances.SubtestFk
try:
SELECT ... FROM
responses
JOIN subtestinstances ON subtestinstances.Id = responses.SubtestInstanceFk
JOIN students ON subtestinstances.StudentFk = students.Id
JOIN schools ON students.SchoolFk = schools.Id
JOIN items ON responses.ItemFk = items.Id
JOIN subtests ON subtests.Id = subtestinstances.SubtestFk
LEFT JOIN strategies ON responses.StrategyFk = strategies.Id
That's it. No OR condition is really needed, because that's what a LEFT JOIN does in this case. Anywhere responses.StrategyFk IS NULL will result in no match to the strategies table, and it wil return a row for that.
See this link for a simple explanation of joins: http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html
After that, if you're still having performance issues then you can start looking at the EXPLAIN SELECT ... ; output and looking for indexes that may need to be added. Optimizing Queries With Explain -- MySQL Manual
Try using explicit JOINs:
...
FROM responses a
INNER JOIN subtestinstances b
ON b.id = a.subtestinstancefk
INNER JOIN students c
ON c.id = b.studentfk
INNER JOIN schools d
ON d.id = c.schoolfk
INNER JOIN items e
ON e.id = a.itemfk
INNER JOIN subtests f
ON f.id = b.subtestfk
LEFT JOIN strategies g
ON g.id = a.strategyfk

Mysql - db-select with several joins and tablestructure

I am using the following mysql select-query with several joins. I am wondering if this is how a somewhat good select-statement should look like:
SELECT *
FROM table_news AS a
INNER JOIN table_cat AS b ON a.cat_id = b.id
INNER JOIN table_countries AS c ON a.country_id = c.id
INNER JOIN table_addresses AS d ON a.id = d.news_id
WHERE a.deleted = 0
AND a.hidden = 0
AND a.cat_id = ".$search_cat."
AND a.country_id = ".$search_country."
AND a.title LIKE '%".$search_string."%'
OR a.deleted = 0
AND a.hidden = 0
AND a.cat_id = ".$search_cat."
AND a.country_id = ".$search_country."
AND a.subtitle LIKE '%".$search_string."%'"
It seems to be a lot of joins. Even though table b and table c contain only 3 or 4 fields, I wonder if the number of joins would clearly slow down the search on the starting-page?
Would it be better to put the fields from table d (street, city and so on) back into the main-table, as they should be needed most of the time this query is executed?
Thanx in advance,
Jayden
I don't think there is necessarily anything wrong with having three joins. There are a couple of things you can do to make sure the query is optimised.
Firstly, you should never do SELECT * - instead explicitly state what fields you want to return from the database.
Also, I would create indexes on all the fields you have in the where clause, and all of the fields you are joining. This can be a little bit of a trade off - for example if you are doing a lot of write operations then there is a hit because you need to write to the index everytime.