How to select from / join 5 tables using PHP and mySQL - php

I'm trying to build a review record based on fields from 5 tables:
I've marked all the columns I need, but for the moment I'm just retrieving all of the user_rating table.
Here's what I have so far:
SELECT DISTINCT user_rating.*, whiskey.name, user_notes.overall, users.image, user_rate.rate_number
FROM user_rating
LEFT JOIN whiskey ON whiskey.id = user_rating.whiskeyid
LEFT JOIN users ON users.username = user_rating.username
LEFT JOIN user_notes ON user_notes.username = user_rating.username AND user_rating.whiskeyid = user_notes.whiskey_id
LEFT JOIN user_rate ON user_rate.whiskey_id = user_rating.whiskeyid AND user_rate.username = user_rating.username
ORDER BY user_rating.id DESC
At first I thought this was giving me the results I wanted but then I noticed I was getting multiple rows as well as too many null fields. Any help would be greatly appreciated.
Edit:
By multiple rows I mean duplicate rows. Also, I am aware that a left join produces null values on the right side of the join. What I meant to say is that I'm getting more null values than I should be as the data is within the database.
To clarify, I'm trying to create a list of recent reviews with the most recent listed first. Each review consists of a username, 11 categories (each one is an integer value), overall rating (int value), notes (string), image (URL), and whiskey name (string).

1) You can't be getting multiple SAME rows, since you use DISTINCT. (by multiple do you mean duplicate?)
2) You get null fields because you are using LEFT JOIN and your tables cannot be joined (some "ON clause" cannot be evaluated as true)

It turns out that there was nothing wrong with my query. The person whose database I'm using isn't maintaining it so there are several reviews for the same product and user where only the overall rating is different. Also, there are many reviews on products that don't even exist. I should've looked at the database closer to begin with as deleting all of the erroneous rows solved my problem. Thanks for all the input.

Related

MySQL selection / JOIN on four tables results in time-out

I need to do a selection on 4 tables. Combining table ships and table ship_history is no problem, I get the results instantly. I tried with a normal select and a LEFT JOIN, both are instant. When I try to LEFT JOIN the third table, it takes a very long time (timeouts occurs most of the time). And I would like to even join a fourth table.
All four tables are connected with the ID from table ships. For the table ship_construction I only need the records where column final equals to 1. This is my current query for 3 tables:
SELECT s.id
, s.name
, s.year
, s.built
, sh.col_1
, sh.col_2
, sh.col_3
, sc.col_1
, sc.col_2
, sc.final
FROM ships s
LEFT
JOIN ship_history sh
ON sh.ship_id = s.id
LEFT
JOIN ship_construction sc
ON sc.ship_id = s.id
AND sc.final = 1
For every record in table ships there is one record in the ship_history table. For tables 3 and 4 this can be zero or more for every table 1 record. I used a LEFT JOIN, because I need all records from table 1.
Table ships currently has 17128 records
Table ship_history currently has 17128 records
Table ship_construction currently has 41935 records
Table 4 currently has 57988 records
Of course I already read tons of Stackoverflow topics and searched (and searched and searched) on Google. I have tried many different approaches, but I think I am on the wrong track. I also read about indexes, but this is new for me so I am not sure if this is necessary in this case.
Could anyone push me in the right direction? Any help is appreciated, if additional info is needed just let me know.
Just for the record: my current query DOES work, but it takes too long.
Thanks

Multiple table select grouped query

We need to grab the last and newest 20 entries from different tables. However, the GROUP BY statement skips records because we are working with LEFT JOIN on tables.
All these records are linked to unique persons in another table. We store these person's id's in an array for more queries later.
We have a few tables (in which all those person id's are stored) and we want to get them sorted and grouped.
The tables are like this:
SELECT lastRecord+personID FROM t1
SELECT lastRecord+personID FROM t2
SELECT lastRecord+personID FROM t3
SELECT lastRecord+personID FROM t4
WHERE t5.Essential_Column_Name = '1'
GROUP BY personID
ORDER BY 'all the latest entries'
LIMIT 20
With that, the relevance of all the latest entries should be equal.
We do have a timestamp column as well. Perhaps that might work better.
Any input is highly appreciated!
For people looking for an answer on this; this is the right post, answer and update to this Q:
UNION mysql gives weird numbered results
With thanks to all for the ideas and providing the paths to the right solution.

Include NULL as 0 in COUNT SQL Query

I know for a fact this has been asked a few times before, but none of the answered questions relating to this seem to work or are far too confusing for me..
I should probably explain.
I'm trying to create an AJAX script to run to order some results by the number of 'Likes' it has.
My current code is this:
SELECT COUNT(*) AS total, likes.palette_id, palette.*
FROM likes LEFT JOIN palette ON likes.palette_id = palette.palette_id
GROUP BY likes.palette_id
ORDER BY total DESC
Which works fine, however it doesn't list the results with 0 likes for obvious reasons, they don't exist in the table.
I've attached images of the current tables:
Likes table:
http://imgur.com/EGeR3On
Palette table:
http://imgur.com/fKZmSve
There are no results in the likes table until the user clicks 'Like'. It is then that the database gets updated and the palette_id and user_id are inserted.
I'm trying to count how many times *palette_id* occurs in the likes table but also display 0 for all palettes that don't appear in the likes table.
Is this possible? If so, can someone help me out at all?
Thank you
It might not be the exact MySQL syntax (I'm used to SQL Server), but should be pretty straight forward to translate if needed.
SELECT p.*, IFNULL(l.total, 0) AS total
FROM palette p
LEFT JOIN (
SELECT palette_id, COUNT(*) AS total
FROM likes
GROUP BY palette_id
) l
ON l.palette_id = p.palette_id
ORDER BY total
Try this:
SELECT COUNT(likes.palette_id) AS total, palette.palette_id, palette.*
FROM palette LEFT JOIN likes ON likes.palette_id = palette.palette_id
GROUP BY palette.palette_id
ORDER BY total DESC
EDIT:
In regards to the discussion about listing columns that are not in the GROUP BY, there's a good explanation in this MySql documentation page.
MySQL extends the use of GROUP BY so that the select list can refer
to nonaggregated columns not named in the GROUP BY clause. This means
that the preceding query is legal in MySQL. You can use this feature
to get better performance by avoiding unnecessary column sorting and
grouping. However, this is useful primarily when all values in each
nonaggregated column not named in the GROUP BY are the same for each
group. The server is free to choose any value from each group, so
unless they are the same, the values chosen are indeterminate.
In this example, the palette information not added to the GROUP BY will be the same for each group because we are grouping by palette_id so there won't be any issue using palette.*
Your join is written backwards. It should be palette LEFT JOIN likes, because you want all rows in palette and rows in likes, if they exist. The "all rows in palette" will get you a palette_id for the entries there without any matching "likes."

Getting SQL result as nested array in PHP

I've a ('courses') table that has a HABTM relationship with ('instructors') table through another table...
I want to get the data of an instructor with all related courses in one query..
Currently, I have the following SQL:
SELECT *
FROM `instructors` AS `instructor`
LEFT JOIN `courses` AS `course`
ON `course`.`id` IN (
SELECT `course_id`
FROM `course_instructors`
WHERE `course_instructors`.`instructor_id` = `instructor`.`id`
)
WHERE `instructor`.`id` = 1
This SQL does what it should be doing, the only "problem" I have is that I get multiple rows for each joined rows.
My question is:
Can I get the result I want in one query? Or do I have to manipulate the data in PHP?
I'm using PHP and MySQL.
Each record of a query result set has the same format: same number of fields, same fields, same order of fields. You cannot change that.
SELECT *
FROM instructors AS instructor
LEFT JOIN
course_instructors
ON
instructor.id= course_instructors.instructor_id
LEFT JOIN
courses
ON
course_instructors.course_id = course.id
WHERE instructor.id = 1
This assumes the PK of course_instructors is (instructor_id,course_id)
Explanation of query:
First join + WHERE make sure you get the relevant instructor
Second join matches ALL the entries from the course_instructor table that belongs to this instructor. If none found, will return one row with NULL in all fields
Last join matches all relevant courses from the entries found from course_instructor If none would will return one record with NULL in all fields.
Again: important to use the right constraints to avoid duplicate data.
That's the nature of relational databases. You need to get the instructor first and then get the related courses. That's how I would do it and that's how I've been doing it. I'm not sure if there is a "hack" to it.

SQL Query to get rows where values in a column do not exist in another table

I have a products table with a column that contains a space separated list of ids (like: "23 42 365"), the column is called "categories". The numbers refer to rows ids in another table (categories).
I need to extract all product rows where all of the ids in the space separated list point to rows on the categories table that no longer exist.
I know this is not the best database design by a long way, however I have been presented with this task on an older system. I am not even sure it can be done entirely with an SQL statement, but because of the sheer number of records on the product table, it would be slower to use PHP logic to determine the rows to return. However, if thats the only way, thats what i'll do!
SELECT m.*
FROM mytable m
LEFT JOIN
categories c
ON FIND_IN_SET(c.id, REPLACE(m.categories, ' ', ','))
WHERE c.id IS NULL
You can use an outer join to get the missing rows, searching for where the category is null.
http://dev.mysql.com/doc/refman/5.0/en/join.html

Categories