mysql query 3 tables - mysql

SELECT favourites.FavouriteID,
favourites.User,
favourites.RecipeID,
recipes.RecipeID,
recipes.Name,
recipes.CategoryID,
recipes.RatingTotal,
recipes.ImageMed,
count(ratings.RecipeID) AS trates ,
(recipes.RatingTotal / COUNT(ratings.RecipeID)) as avg
FROM favourites
RIGHT JOIN recipes
on recipes.RecipeID = favourites.RecipeID
LEFT JOIN ratings
ON ratings.RecipeID = recipes.RecipeID
WHERE favourites.user = '$Cuser'
GROUP BY ratings.RecipeID
ORDER BY avg DESC, trates DESC
LIMIT $offset,20
hi there this query brings through a total of 3 records but they are 7 , there other 4 don't come through as they do not have a record in the ratings table, how can i adjust ?
the favourites table conatains the recipe id of a recipe which a user has added to theor favourites list , i am trying in the query to display the recipes from the favourites table orded by the one's withthe highet raring first. but the ones that do not have a rating are not showing

The error seems to be in the data. Maybe the relational integrity between favourites and recipes is violated. Show your test data.

Related

SQL (mysql) query explanation for multiple row update using group by sub query

I have 2 tables, countries and users
users
id
country_id
1
1
2
1
3
1
4
2
5
2
countries
id
monthly_count
1
0
2
0
I want to update the monthly_count column in countries table by counting rows in users table grouped by country_id in a single update query. So after updating the countries table will look like this:
countries
id
monthly_count
1
3
2
2
The query I ended up with is:
UPDATE countries c
SET c.monthly_count = (
SELECT COUNT(u.country_id) FROM users u
WHERE u.country_id = c.id
GROUP BY u.country_id
);
The query is working as expected. It is updating the monthly_count column of every row in the countries table with corresponding correct count values for each country_id group from users table.
However, I am not sure how the query is working. The main question I have is, how the result of subquery is assigned to the correct row? Is the subquery executed one time and returning all the group by count values for each country_id at once or, is the sub query being executed each time for every row in countries table?
I would write this an update join:
UPDATE countries c
INNER JOIN
(
SELECT country_id, COUNT(*) AS cnt
FROM users
GROUP BY country_id
) u
ON u.country_id = c.id
SET c.monthly_count = u.cnt;
That being said, the monthly counts are aggregate data, and you might want to consider not doing this update or storing this data. So, I am happy with the following query or view:
SELECT c.id, COUNT(u.cnt) AS monthly_count
FROM countries c
LEFT JOIN users u
ON u.country_id = c.id
GROUP BY c.id;

MySQL query to return rows ordered by averages from another table

I am building a database for a contest in which people upload photos and the jury grades them. I have two tables: photographs (id, name, user_id and section_id) and grades (id, grade, photo_id, juror_id).
What I want to achieve is a query to return all photos ordered by the average of all grades given to each photo.
For example, if we have 2 photographs with ids 1 and 2 with photo 1 having two grades (5, 6) and photo 2 also having two grades (8, 10) the first returned row will be the photo with id 2 (the average of the grades is 9 and it is greater than 5.5, the average of photo 1).
How could I achieve this?
Here is a pseudo-example of a query
SELECT * FROM photographs ORDER BY AVERAGE(SELECT grade FROM grades)
This is a job for AVG() and GROUP BY.
To get the average grade by photo from your grades table this subquery does it.
SELECT AVG(grade) avg_grade,
photo_id
FROM grades
GROUP BY photo_id
That subquery is guaranteed to return exactly one row per photo_id value. So you can LEFT JOIN it to your photographs table like so.
SELECT avg_grade.avg_grade,
photographs.*
FROM photographs
LEFT JOIN (
SELECT AVG(grade) avg_grade,
photo_id
FROM grades
GROUP BY photo_id
) avg_grade ON photographs.id = avg_grade.photo_id
ORDER BY avg_grade.avg_grade DESC
First of all you need to join your table properly, then to agreagat result, and after that to order output:
SELECT
p.id,
AVG(g.grade) AS averageGrade
FROM photographs AS p
JOIN grade AS g ON g.photo_id = p.id
GROUP BY p.Id
ORDER BY AVG(g.grade) DESC

Mysql query -- choosing highest rank/ordered subject in table (join)

Scenario:
We have 5 users. (users table)
Each user has up to 10 imgs. (image table)
These 10 images can be ordered 1 – 10. (image table)
Each img can be listed in multiple categories (say there are 5 categories – birds, bees, bunnies, brains, belugas (category table connected to img table via table that stores img_ids and category_ids)
In searching through the categories, say someone chooses bees. The search should find the images in that category that is listed CLOSEST to the #1 img for all users. So if each user has 3 images in the bees category, ordered as numbers 4, 7 & 9, the search should show the 4th as its closest to the number 1.
The results I keep getting are all over the place and almost seems like it is choosing the images via WHEN they were added to the DB.
SELECT i.img_name, i.ordered, a.user_name, c.keyword, c.cat_id
FROM images AS i JOIN artists AS a USING (user_id)
JOIN img_cat_table AS im USING ( img_id )
JOIN catkeys AS c USING (cat_id)
WHERE ( cat_id = 3) // THE BEES ID #
GROUP BY user_id ORDER BY user_name DESC
I'm also not sure if you want to show all of the relevant images in the right order, or only the top one. Assuming that it is the latter situation, you will need to join to a subquery or view that returns the min rank for each user, category:
SELECT i.img_name, i.ordered, a.user_name, c.keyword, c.cat_id
FROM images AS i JOIN artists AS a USING (user_id)
JOIN img_cat_table AS im USING ( img_id )
JOIN catkeys AS c USING (cat_id)
JOIN (
SELECT user_id, min(img_rank) img_rank
FROM images AS i
JOIN artists AS a on i.user_id = a.user_id
JOIN img_cat_table AS im on im.img_id = i.img_id
JOIN catkeys AS c on c.cat_id = i.cat_id
WHERE ( cat_id = 3) ) x on x.user_id = a.user_id and x.img_rank = img_rank
WHERE c.cat_id = 3
I'm not sure what the name of the column that holds the image ranking is. I called it img_rank. Hopefully this will give you the idea
though if you can post the table structure and data, that will be great but Here is what I haved tried
SELECT i.img_name, i.ordered, a.user_name, c.keyword, c.cat_id
from (
select img_name, ordered, img_id, user_id from
images
group by user_id
order by user_img ) as i
JOIN artists AS a USING (user_id)
JOIN img_cat_table AS im USING ( img_id )
JOIN catkeys AS c USING (cat_id)
WHERE ( cat_id = 3) // THE BEES ID #
Try removing DESC from your ORDER BY clause.

Sum Two Columns in Two Mysql Tables

I've been searching everywhere for this but no cigar. Smoke is starting to come out of my ears. please help
How do you sum two columns in two tables and group by userid?
Have two tables.
Recipe Table
recipeid userid recipe_num_views
Meals Table
mealsid userid meal_num_views
Goal is to sum the num views in both tables and group by userid
so for example
Recipe Table
1 3 4
2 4 6
Meal Table
1 3 2
2 4 5
select sum(recipe views)+sum(meal views)
WHERE recipe.userid=meals.userid GROUP BY userid
should give
userid=3 , sum=6
userid=4, sum=11
this gives a much bigger number.
SELECT recipe.userid, sum(recipe_num_views+meal_num_views)
FROM Recipe JOIN Meals ON recipe.userid=meals.userid
GROUP BY recipe.userid
EDIT:
OK, from your comments, I understand that when you have for user 3: 4 recipes & 3 meals you will get the sum of the combination of all these rows => sum(recipes)*3 + sum(meals)*4
Try this query instead:
select r.userid, (sum_recipe + sum_meal) sum_all
FROM
(select userid, sum(recipe_num_views) sum_recipe
FROM Recipe
GROUP BY userid) r
JOIN (
select userid, sum(meal_num_views) sum_meal
FROM Meals
GROUP BY userid) m ON r.userid = m.userid
If you're selecting from 2 tables you need to join them.
Otherwise MySQL will not know how to link up the two tables.
select sum(recipe_num_views + meal_num_views)
from recipe r
inner join meals m ON (r.user_id = m.user_id)
group by m.user_id
See:
http://dev.mysql.com/doc/refman/5.5/en/join.html
http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html

Mysql query in drupal database - groupwise maximum with duplicate data

I'm working on a mysql query in a Drupal database that pulls together users and two different cck content types. I know people ask for help with groupwise maximum queries all the time... I've done my best but I need help.
This is what I have so far:
# the artists
SELECT
users.uid,
users.name AS username,
n1.title AS artist_name
FROM users
LEFT JOIN users_roles ur
ON users.uid=ur.uid
INNER JOIN role r
ON ur.rid=r.rid
AND r.name='artist'
LEFT JOIN node n1
ON n1.uid = users.uid
AND n1.type = 'submission'
WHERE users.status = 1
ORDER BY users.name;
This gives me data that looks like:
uid username artist_name
1 foo Joe the Plumber
2 bar Jane Doe
3 baz The Tooth Fairy
Also, I've got this query:
# artwork
SELECT
n.nid,
n.uid,
a.field_order_value
FROM node n
LEFT JOIN content_type_artwork a
ON n.nid = a.nid
WHERE n.type = 'artwork'
ORDER BY n.uid, a.field_order_value;
Which gives me data like this:
nid uid field_order_value
1 1 1
2 1 3
3 1 2
4 2 NULL
5 3 1
6 3 1
Additional relevant info:
nid is the primary key for an Artwork
every Artist has one or more Artworks
valid data for field_order_value is NULL, 1, 2, 3, or 4
field_order_value is not necessarily unique per Artist - an Artist could have 4 Artworks all with field_order_value = 1.
What I want is the row with the minimum field_order_value from my second query joined with the artist information from the first query. In cases where the field_order_value is not valuable information (either because the Artist has used duplicate values among their Artworks or left that field NULL), I would like the row with the minimum nid from the second query.
The Solution
Using divide and conquer as a strategy and mysql views as a technique, and referencing this article about groupwise maximum queries, I solved my problem.
Create the View
# artists and artworks all in one table
CREATE VIEW artists_artwork AS
SELECT
users.uid,
users.name AS artist,
COALESCE(n1.title, 'Not Yet Entered') AS artist_name,
n2.nid,
a.field_image_fid,
COALESCE(a.field_order_value, 1) AS field_order_value
FROM users
LEFT JOIN users_roles ur
ON users.uid=ur.uid
INNER JOIN role r
ON ur.rid=r.rid
AND r.name='artist'
LEFT JOIN node n1
ON n1.uid = users.uid
AND n1.type = 'submission'
LEFT JOIN node n2
ON n2.uid = users.uid
AND n2.type = 'artwork'
LEFT JOIN content_type_artwork a ON n2.nid = a.nid
WHERE users.status = 1;
Query the View
SELECT
a2.uid,
a2.artist,
a2.artist_name,
a2.nid,
a2.field_image_fid,
a2.field_order_value
FROM (
SELECT
uid,
MIN(field_order_value) AS field_order_value
FROM artists_artwork
GROUP BY uid
) a1
JOIN artists_artwork a2
ON a2.nid = (
SELECT
nid
FROM artists_artwork a
WHERE a.uid = a1.uid
AND a.field_order_value = a1.field_order_value
ORDER BY
uid ASC, field_order_value ASC, nid ASC
LIMIT 1
)
ORDER BY artist;
A simple solution to this can be to create views in your database that can then be joined together. This is especially useful if you often want to see the intermediate data in the same way in some other place. While it is possible to mash together the one huge query, I just take the divide and conquer approach sometimes.