MYSQL Counting amount of rows (if exists) from another table - mysql

I'm sure this question makes no sense, sorry for that, best way I can explain it is visually.
My tables are:
category, comment, member and review.
I have a query which selects information from the 3 latest reviews
SELECT `reviewID` , `reviewTitle` , `reviewContent` , `reviewDate` , `gameRating` , `reviewImage` , `firstName` , `lastName` , `categoryName`
FROM member
INNER JOIN review
USING ( memberID )
INNER JOIN category
USING ( categoryID )
ORDER BY `reviewDate` DESC
LIMIT 3
result
Each review is assigned a reviewID, comments are also assigned a reviewID to determine which review the comment is for. I want to also count the amount of comments per review. Comments tables includes:
commentID reviewID memberID commentDate commentContent
I've tried
SELECT `reviewID`, `reviewTitle`, `reviewContent`, `reviewDate`, `gameRating`, `reviewImage`, `firstName`, `lastName`, `categoryName`, count(commentID) AS comments
FROM member INNER JOIN
review
USING (memberID) INNER JOIN
category
USING (categoryID) INNER JOIN
comment USING (reviewID)
ORDER BY `reviewDate` DESC
LIMIT 3
But it only gives this result
which is correct as that review has 2 comments, but the other 2 reviews have 0 comments so I assume it should just return null instead of not displaying the other reviews all together? Any help would be greatly appreciated.

You probably just need left joins:
SELECT member.*, count(commentID) AS comments
FROM member LEFT JOIN
review
USING (memberID) LEFT JOIN
category
USING (categoryID) LEFT JOIN
comment
USING (reviewID)
GROUP BY memberId
ORDER BY `reviewDate` DESC
LIMIT 3
You need a GROUP BY, but you should also remove all the non-member columns.

Related

MYSQL: Count for every customer's visit

I am having problem to figure out how to create a query for this scenario:
Here is updated version of my question.
I have 3 tables.
`customers`: `id` , `name` , `address`
`cars`: `id` , `license_nr` , `make` , `customer_id`
`services`: `id` , `car_id` , `description`
Every time a customer comes for a service a new record made in services table. I want to know counts of services for each customer. There is no direct relation between in services and customers.
EDIT: Correction of a column name in services table.
I think I will answer my own question. Maybe someone else will need this. Thank you all for your efforts.
SELECT customers.name, COUNT(*) AS visit_count
FROM services
JOIN cars ON cars.id = services.car_id
JOIN customers ON customer.id = cars.customer_id
GROUP BY customer_id
I get the result I want.
name | visit count
Amal Hopkins | 1
Dean Leach | 2
Here is the updated solution based on the updated question:
select count(s.id) as service_tickets, cust.id, cust.name, cust.address
from customers cust
left join cars c on c.customer_id = cust.id
left join services s on s.car_id = c.id
group by cust.id
I updated it so it would return 0 for customers who have no services on their cars.
SELECT customer, COUNT(*) FROM table GROUP BY customer;
UPDATE:
If visit means a row in services table, then we are OK because we simply need to count rows in services table. Foreign keys are not a problem. In fact, we can use join to see customer's name. So, the syntax should be:
SELECT s.CustomerID, c.Name, COUNT(*) FROM services s
join customer c on c.id=s.CustomerID
GROUP BY CustomerID, c.Name

join 2 mysql tables and get the first and last date

I have 2 mysql tables, one with the users details and the second with all the pages that the users saw (1:N)
TABLE "users"
id int(10) auto_increment primay
ip varchar(15)
lang char(2)
...
TABLE "pages"
id int(10) auto_increment primay
uid int(10) index
datetime datetime
url varchar(255)
I know is possibile to join the 2 tables, but i'm a little confused how to get the first and last datetime, and the first url from the "pages" table...
SELECT * FROM users, pages WHERE users.id = pages.uid
I think with GROUP BY / MIN(pages.datetime), MAX(pages.datetime) but I have no idea where to use it, and how I can get the first pages.url
As you mentioned you need to use Group by with MIN & MAX aggregate function to find the first and last datetime per user.
Also don't use comma separated join syntax which is quite old and not much readable use proper INNER JOIN syntax
SELECT U.ID,
MIN(pages.datetime) as First_date,
MAX(pages.datetime) as Last_date
FROM users U
INNER JOIN pages P
ON U.id = P.uid
Group by U.ID
If you want to see the other information like first visited url,etc.. Then you can join above result to the main table to get the related information.
select A.uid,A.url First_URL,C.url as Last_url,First_date,Last_date
from pages A
INNER JOIN
(
SELECT U.ID,
MIN(pages.datetime) as First_date,
MAX(pages.datetime) as Last_date
FROM users U
INNER JOIN pages P
ON U.id = P.uid
Group by U.ID
) B
ON A.ID =B.ID
and A.datetime = B.First_date
INNER JOIN pages C
on C.ID =B.ID
and C.datetime = B.Last_date

Get the row with the latest date in a group?

I have two tables:
items:
| item_id | title |
comments:
| comment_id | item_id | posted_at | author_id | text |
Where posted_at is the time a comment was posted.
How can I get a list of all items, with the time each of them was last commented on and the author_id of that last comment?
For this, you don't necessarily need the 'items' table if all you want are 'item_id'.
Start by writing a query that gets the latest comment time for each item_id like this:
SELECT item_id, MAX(posted_at) AS latestComment
FROM comments
GROUP BY item_id;
Now, you can join that with your comments table on the condition that the item_id and latestComment columns match to get the latest comment author for each item:
SELECT c.item_id, c.author_id, c.posted_at
FROM comments c
JOIN(
SELECT item_id, MAX(posted_at) AS latestComment
FROM comments
GROUP BY item_id) temp ON temp.item_id = c.item_id AND temp.latestComment = c.posted_at;
If you do need any information form the items table, you can just join the above query to the items table using the item_id column to get what you need.
EDIT
If you want to add requirements for items you can join the above table, and put them in either the WHERE clause or even the ON statement of your join, like this:
SELECT c.item_id, c.author_id, c.posted_at
FROM comments c
JOIN items i ON i.item_id = c.item_id AND i.title LIKE '%Apple%'
JOIN(
SELECT item_id, MAX(posted_at) AS latestComment
FROM comments
GROUP BY item_id) temp ON temp.item_id = c.item_id AND temp.latestComment = c.posted_at;
I just made up an example requirement. This query should pull the latest comment for all items that have a title containing the word 'Apple'. Note that this is an inner join, so you will only see items that do have comments. If you want to see all items, I recommend an outer join.
You need the most recent comment for each item. There are three parts to that.
First: most recent
SELECT MAX(comment_id) FROM comments GROUP BY item_id
Second: most recent comment
SELECT comments.author_id, comments.posted_at
FROM comments
WHERE comments.comment_id IN
(SELECT MAX(comment_id) FROM comments GROUP BY item_id)
Third. Most recent comment for each item.
SELECT items.item_id, items.title, comments.author_id, comments.posted_at
FROM items
LEFT JOIN comments
ON items.item_id = comments.item_id
AND comments.comment_id IN
(SELECT MAX(comment_id) FROM comments GROUP BY item_id)
The trick here is to find the single most recent comment for each item, and then use it. The left join operation preserves those items that have no comments. This query uses comment_id as a proxy to search for the latest posted_at. It assumes comment_id is an autoincrement column, and that later comments have higher comment_id values than earlier comments.
A compound index on the comments table on (item_id, comment_id) will help performance here, by accelerating the GROUP BY subquery.
You can try using max(posted_at) group by item_id and join it with you comments table on these 2 columns.
What about;
Select title,author_id,MAX(posted_at) as LastTime From items i
join comments c
on c.item_id = i.item_id
group by title,author_id
This should give you what you are looking for if the same post exists multiple times. If not, you could even remove the MAX and add other columns.

SQL query inner joins and limit to max 3 most recent

I have the following query:
SELECT * FROM `product` INNER JOIN `shop`
ON `product`.shop_id= `shop`.id;
I wanted to get all of the products from all the shops I have, but I wanted to get 3 products max from each shop. Is there a way to specify MAX on each joins?
Here's my product table:
Here's my shop table:
Try this:
SELECT *
FROM (SELECT *
FROM (SELECT *, IF(#shop = (#shop:=p.shop_id), #id:=#id + 1, #id := 1) temp
FROM `product` p, (SELECT #shop:=0, #id:=1) AS A
ORDER BY p.shop_id, p.updated DESC) AS B
WHERE temp <= 3) AS C
INNER JOIN `shop` s ON C.shop_id= s.id;
Query:
SELECT *
FROM `product` p
INNER JOIN `shop` s
ON `p`.shop_id= `s`.id
WHERE p.id IN (SELECT p2.id
FROM `product` p2
WHERE p2.shop_id = s.id
ORDER BY p2.updated DESC
LIMIT 3)
OR maybe:
SELECT *
FROM `product` p
INNER JOIN `shop` s
ON `p`.shop_id= `s`.id
WHERE EXISTS (SELECT p2.id
FROM `product` p2
WHERE p2.shop_id = s.id
ORDER BY p2.updated DESC
LIMIT 3)
Specifying limits within a subquery is a bit challenging in MySQL (not impossible, but a bit complicated).
If you just want the three most recent product ids for each shop, and you can live with them on one row, then you can use group_concat(). The query is much simpler:
SELECT shop.*,
substring_index(group_concat(product.id order by product.updated desc), ',', 3) as ThreeProducts
FROM `product` INNER JOIN
`shop`
ON `product`.shop_id= `shop`.id
group by shop.id;
The results will place the product ids in a single field like this: '1,2,3'.
It is important to know the tables definitions in terms of primary keys, foreign keys, etc to come up with a SQL to solve the problem. From the images it is not clear if product.id is unique or not. I suspect there is possibly a data model definition issue here.
If the tables are not normalized to a necessary extent, it will be very difficult (sometime not possible) to read appropriate data back.
A reasonably normalized tables should look like.
Product(id primary key, ....)
Shop(id primary key,....)
and a relation table say.
Shop_Product (shop_id references Shop(id), prod_id references Product(id), ...)
It will be helpful to help you out if you could send table definitions.
try to use limit in your code. It may work

SQL query sum multiplied 2 times what it should be

When I run this query, the votes sum is 2 times what it should be (sum=6 instead of 3). Can someone figure out the fix for this?
SELECT sum(votes.vote) AS sum
, my_votes.vote IS NOT NULL AS did_i_vote
, votes.parent_id, subject
, review_date
, item_id
, review_summary
, review, full_name
, reputation
, profile_picture
, accounts.acct_id
FROM votes
RIGHT JOIN items_purchased
on votes.parent_id=items_purchased.purchase_id
JOIN accounts
ON items_purchased.purchaser_account_id=accounts.acct_id
JOIN items
on items_purchased.item_id=items.folder_id
LEFT JOIN votes AS my_votes
ON my_votes.parent_id=items_purchased.purchase_id
AND my_votes.acct_id='3'
AND my_votes.column_name='purchase_id'
WHERE purchase_id='2'
AND deleted_p!=1 and pub_priv_p!=1
GROUP BY items_purchased.purchase_id
I'm pretty sure it has to do with the JOINs because if I get rid of JOIN items on items_purchased.item_id=items.folder_id then the sum=3. However, I need that JOIN in there somehow.
Thoughts?
Without a schema we can't tell, but this is a guess:
Check all of your join conditions - you're likely missing a condition causing that set of results to be 'duplicated'.
For example, if I have a table
`Foo` with columns `A` `B` and `C` - A and B are the PK;
`Bar` with columns `A` `B` and `Z` - A and B are the PK;
`Biz` with columns `Z` `GOAL`
And I wanted to count the number of GOALS per A, if I joined the Foo to Bar just using A and not B as well, I would likely get an erroneous count.
The easiest way to see this is to do a SELECT * and remove the group by