I have 3 tables: person, image and comment. Person has fields id and name. Images are for a specific person so it has id, person_id, image_name. And comment is kind of a hybrid table because a comment can be either directly for a person or for an imaga - so it has fields id, person_id, image_id and comment.
The same table was used for both comments because the comment plugin is identical for both cases and i also need to show all comments in a live feed so it seemed easier to keep them in one table.
My problem now is tho how can i write a query that gives me all the relevant data reardless if comment is for person or for image.
Select should return a row for each comment with additional data:
comment
image_name (if comment is tied to image_id)
person_name (regardless if comment is tied directly to person or to an image)
The problem im facing is I don't really know how to select person through image if image_id is present and otherwise select person directly through person_id. Also its kind of hard to search for this kind of a solution because its hard to put it in words.
Edit, added sqlfiddle:
http://sqlfiddle.com/#!9/7fa06a/1
The thing that is currently missing is the person data for second row. That data should be available because image table has person_id but i dont know how to select it.
Solution seemed to be to join person table with both person and image using OR and depending which one is present it gets joined:
SELECT *
FROM comment
LEFT JOIN image ON image.id = comment.image_id
LEFT JOIN person ON person.id = image.person_id OR
person.id = comment.person_id
You need to make comment table as main table and then left join person and image tables.
Select * from comment c left join person p on p.id=c.person_id left join image i on i.image_id=i.id and i.person_id=c person_id
You could do that with COALESCE(). It returns the first argument that is not NULL.
SELECT comment.comment, image.name, COALESCE(person.name, image_person.name)
FROM comment
LEFT JOIN person on person.id = comment.person_id
LEFT JOIN image ON image.id = comment.image_id
LEFT JOIN person image_person ON image_person.id = image.person_id
The answer of user1985273 should more efficient, though.
Related
Lets guess I have 3 tables:
Table a where I have a name and email
Table b where I have a text and user (as a reference to email from table a)
Table c where I have follower and following (both references to email in table a)
Im trying to develop a simple html/php/sql web that allows me to register many users and let them post different texts while also having the chance to follow or be followed by other users (already done) and I want to give an user the possibility to display the texts from table b that he himself posted and those from the users he is following
Im seriously struggling with how to extract this information
SELECT b.text
FROM tableB as b
LEFT JOIN tableC as c
ON b.user = c.follower
WHERE b.user = "currentuser"
This is as far as I got, which only shows the texts posted by the user himself (something I can do way more simple) but I cant seem to understand how to get those from the users he is following
I hope its understandable without any photo
You first want to find all following users in table c rows where the current user is the follower. Then you want to add the current user (or alternatively always have all users follow themselves). Then you want to find all texts for those users.
So:
select b.text
from (
select following as user
from tableC
where follower="current user"
union
select "current user"
) show_users
join tableB as b on b.user=show_users.user
or if you have a tableC row where follower=following for all users, just:
select b.text
from tableC as c
join tableB as b on b.user=c.following
where c.follower="current user"
I have four tables (in [] are columns):
users [id]
products [id]
productRatings [id,value,user,product]
comments [id,product,user]
I would like to select/and ultimately delete productRatings where there are no associated comment by the same user for that product. That is, if user has rated product but did not comment, that rating should be deleted.
I believe I could achieve that by using two queries, first:
SELECT user, product FROM productRatings
and then for each row:
SELECT COUNT(*) FROM comments WHERE product=productRatings.product AND user=productRatings.user
and then something like
if $queryAbove==0 : DELETE FROM productRatings WHERE id=productRatings.id
I would like to solve this via JOIN and learn more by example rather than dig through JOIN tutorials.
You only need the productratings and comments table - the following works:
delete pr
from productratings pr
left join comments c
on pr.userid = c.userid
and pr.productid = c.productid
where c.productid is null
And there's a demo here: http://sqlfiddle.com/#!9/89575/1
DELETE FROM `productRatings` WHERE productRatings.id NOT IN (
SELECT productRatings.id FROM `productRatings` JOIN `comments` ON productRatings.user = comments.user AND productRatings.product = comments.product )
I'd make copies of the tables in question and test that the above works on the test tables before using this on your production tables.
Basically, the nested select will return all productRatings id's that the user who wrote the rating also made a comment on. Using NOT IN, it will delete all ratings that the user who made the rating didn't also comment.
As pala_ highlighted in the comments below, because this method uses nested sql, it will perform worse than a method that only uses joins on larger tables.
You should be able to just join the fields in the query and then check if the comment is empty, like so...
DELETE FROM `productRatings`
JOIN `comments` ON (`productRatings`.`product` = `comments`.`product`)
WHERE `comments`.`comment_field` IS NULL
AND `productRatings`.`user_id` = ?;
The IS NULL may need to be replaced with = '' depending on the database engine you use.
Remember to test on a testing instance of the DB first!
DELETE FROM productRatings WHERE id IN (SELECT pr.id FROM productRatings pr
LEFT JOIN comments c on c.product = pr.product
WHERE c.user = pr.user
AND pr.comment IS NULL)
Here's what the table look like:
I'm trying to do a subquery that will pull each image name out for each product. The subquery I got is only pulling the first one out. It may be that I've been looking at it too long or whatever, either way, can someone tell me what I'm doing wrong?
Select c.field_id_33 AS email, o.order_id,c.field_id_76 AS pics, Group_concat(DISTINCT o.entry_id) AS Products,group_concat(DISTINCT t.title),(SELECT field_id_76 FROM finn_channel_data WHERE entry_id = o.entry_id), group_concat(DISTINCT t.url_title) from finn_cartthrob_order_items o
LEFT JOIN finn_channel_data c
ON c.entry_id=o.order_id
LEFT JOIN finn_channel_titles t
ON o.entry_id=t.entry_id
GROUP BY email
I'm having trouble with a join query, my issue is as follows.
Table: battles
Fields: id,attacker_id,defender_id
Table: users
Fields: id,profile_image
I would like to do a query to retrieve a battle and get the profile images as well from the other table.
Is there a way to do this in a single or do I have to do more than one?
Thanks in advance.
I wanted to wait a while to see if you had any attempt or if you will answer my first question to know if I understood the problem. But maybe you don't have a starting point. Try something like:
SELECT
a.profile_image as attacker_profile_image,
d.profile_image as defender_profile_image
FROM
`battles` b
LEFT JOIN
`users` a
ON
b.`attacker_id` = a.`id`
LEFT JOIN
`users` d
ON
b.`defender_id` = d.`id`
the problem here is the fact that you need to join with the users table twice, so you will need to create aliases for the columns you plan to use
This query will fetch the two images only, you will need to add the extra fields
I am writing an application that helps book exchange between users.
I am using PHP and MySQL, and I am pretty new to them both.
I have 5 tables, 3 data tables and 2 service tables:
user: with user attributes (user_id, name, birth... etc).
book: with book attributes (book_id, name, author, publisher... etc).
copy: represents actual copies of a books (copy_id, condition, comments... etc).
user_copy: describes which user holds which copy, composed out of userID and copyID.
copy_book: represents the connection of copy and book, composed out of copyID and bookID
My question is:
what is the easiest and most efficient statement for getting the
book attributes and copy attributes for each copy that a user holds?
You need to inner join all the tables that you are interested in: book, copy, user_copy, and copy_book. The SELECT statement that returns attributes on all copies held by a user may look like this:
SELECT B.bookID
, B.name
, B.author
, B.publisher
, C.condition
, C.comments
-- you may get other fields that you are interested in here..
FROM book B
INNER JOIN copy_book CB ON B.bookID = CB.bookID
INNER JOIN user_copy UC ON UC.copyID = CB.copyID
INNER JOIN copy C ON C.copyID = UC.copyID
WHERE UC.userID = <the user Id that you want>
I hope it's pretty clear what the statement does but if you have any questions, please ask.