MySQL query with sub query GROUP BY and MAX - mysql

( updated the question to be more clear what to expect)
Tables
Main table
table on left join
The query
SELECT m.id AS id,
m.receiverId AS receiverId,
m.creationDate AS creationDate,
m.status AS status,
m.tokens AS tokens,
mm.carrier AS carrier,
mm.fromNumber AS fromNumber,
mm.keyword AS keyword,
mm.ref AS ref,
mm.message AS message
FROM ctb_smsMessenger AS m
LEFT JOIN ctb_smsMessengerMessage AS mm ON m.id = mm.smsMessengerId
WHERE m.status IN ("new")
Result
Desired result
Get records with the IDS 2, 11, 14 and 19 with the correct columns from both tables.
Query so far
SELECT *
FROM (SELECT m.id AS id,
m.receiverId AS receiverId,
m.creationDate AS creationDate,
m.status AS status,
m.tokens AS tokens,
mm.carrier AS carrier,
mm.fromNumber AS fromNumber,
mm.toNumber AS toNumber,
mm.keyword AS keyword,
mm.ref AS ref,
mm.message AS message
FROM ctb_smsMessenger AS m
LEFT JOIN ctb_smsMessengerMessage AS mm ON m.id = mm.smsMessengerId
WHERE m.status IN ("new")
GROUP BY m.receiverId, mm.fromNumber) as m
ORDER BY m.id DESC
LIMIT 0, 20
Result so far
Problem
Only the ID column is displaying the correct data (ID's). The other columns are data which do not match.
What to expect
Each receiverID can have different and multiple numberFrom numbers.
Get all the records with the last inserted record based on the receiverId and numberFrom. ( IDS 2, 11, 14 and 19 )

The solution is to get all records that have the highest ID value, grouped by m.receiverId and mm.fromNumber and use IN at the WHERE IN clause.
SELECT m.id AS id,
m.receiverId AS receiverId,
m.creationDate AS creationDate,
m.status AS status,
m.tokens AS tokens,
mm.carrier AS carrier,
mm.fromNumber AS fromNumber,
mm.toNumber AS toNumber,
mm.keyword AS keyword,
mm.ref AS ref,
mm.message AS message
FROM ctb_smsMessenger AS m
LEFT JOIN ctb_smsMessengerMessage AS mm ON m.id = mm.smsMessengerId
WHERE m.status IN ("new")
AND m.id IN (SELECT MAX(m.id) AS id
FROM ctb_smsMessenger AS m
LEFT JOIN ctb_smsMessengerMessage AS mm ON m.id = mm.smsMessengerId
WHERE m.status IN ("new")
GROUP BY m.receiverId, mm.fromNumber)
GROUP BY m.receiverId, mm.fromNumber
ORDER BY m.id ASC

Related

SQL count and sum some row

I am getting a calculation error in my code
SELECT dep_id,
dept_info.name AS dept_name,
count(dep_id) AS totalInovators,
count(user_id) AS totalIdea,
sum(POINT) AS totalpoint
FROM user_info
JOIN dept_info ON user_info.dep_id =dept_info.id
JOIN user_idea ON user_info.id=user_idea.user_id
GROUP BY dep_id
ORDER BY dep_id DESC
My output result:
Expected result:
With my table user_info :
My user_idea :
My dept_info :
Below the query that solve your problem:
select
user_info.dep_id,
dept_info.name,
count(*) as totalInovators,
sum(ideas_count) as totalIdea,
sum(point) as totalpoint
from
-- first we aggregate table user_idea
(select user_id, count(*) ideas_count from user_idea group by user_id) ideas
-- and after join rest of required tables
join user_info on ideas.user_id = user_info.id
join dept_info on dept_info.id = user_info.dep_id
group by user_info.dep_id, dept_info.name;
Working code here: SQLize.online
I suspect that you are joining along different dimensions. If so, a quick-and-easy solution uses count(distinct):
select d.id, d.name as dept_name, count(distinct u.id) as totalInovators,
count(*) as totalIdea, sum(i.point) as totalpoint
from user_info u join
dept_info d
on u.dep_id = d.id join
user_idea i
on u.id = i.user_id
group by d.id
order by d.id desc

Select highest value per group and associated row from another table, ordered by highest value

I'm trying to get these values from two tables, joining on member id. In the table with the points values, there are running total rows for each sale by each member. I need the member's point total associated with their row in the members table, sorted by value descending. This is my current query, it returns unique values unless a member has two identical entries.
SELECT m.id
, m.fname
, m.lname
, p.points_total
FROM
( SELECT s.member_id
, MAX(s.points_total) points_total
FROM sale_sale s
GROUP
BY s.member_id
) p
JOIN sale_sale x
ON x.member_id = p.member_id
AND x.points_total = p.points_total
JOIN member_member m
ON m.id = p.member_id
WHERE x.site_id = 1
AND m.fname != "Sales"
ORDER
BY p.points_total DESC;
A simple JOIN and GROUP BY would likely do what you're asking for:
SELECT
m.id,
m.fname,
m.lname,
COALESCE(MAX(s.points_total), 0) AS points_total
FROM member_member AS m
LEFT JOIN sale_sale AS s
ON m.id = s.member_id
AND s.site_id = 1
WHERE m.fname != "Sales"
GROUP BY m.id
ORDER BY points_total DESC;
EDIT: Made it a LEFT JOIN with COALESCE(points_total, 0) to allow for members who have no sales totals to show in the results. If you don't want this, you could change LEFT JOIN to INNER JOIN and eliminate the COALESCE function.

MySQL UNION query return duplicate values even using GROUP BY

I have the following query:
SELECT *
FROM (
SELECT
m.id AS id,
reference_id,
title,
created_by,
publish_up,
state
FROM z_news_master m
LEFT JOIN z_news_english c ON m.id = c.reference_id
WHERE c.created_by = 17152
ORDER by c.id DESC
) AS A
UNION
SELECT * FROM (
SELECT
m.id AS id,
reference_id,
title,
created_by,
publish_up,
state
FROM z_news_master m
LEFT JOIN z_news_spanish c ON m.id = c.reference_id
WHERE c.created_by = 17152
ORDER by c.id DESC
) AS B
GROUP BY id
Basically, I have 3 tables (z_news_master, z_news_english, z_news_spanish), to store News in Spanish or English languages. The z_news_master table contains the generic news information, the z_news_english and z_news_spanish contain the news in its respective language.
I need to get a list of the news, if the news is in both language tables it should return only one (not duplicated), the code above does the work, but if there is a new in English and Spanish, the record gets duplicated.
I'd also like to know why the GROUP BY id and the GROUP BY reference_id don't work?
Use a NOT EXISTS subquery to remove a fallback language row if a corresponding row for the prefered language exists. Assuming the prefered language is "english", the query would be:
SELECT
m.id AS id,
reference_id,
title,
created_by,
publish_up,
state
FROM z_news_master m
JOIN z_news_english c ON m.id = c.reference_id
WHERE c.created_by = 17152
UNION ALL
SELECT
m.id AS id,
reference_id,
title,
created_by,
publish_up,
state
FROM z_news_master m
JOIN z_news_spanish c ON m.id = c.reference_id
WHERE c.created_by = 17152
AND NOT EXISTS (
SELECT *
FROM z_news_english e
WHERE e.reference_id = m.id
AND e.created_by = c.created_by
)
ORDER by id DESC
Note that there is no need for GROUP BY. And a LEFT JOIN doesn't make sense because you have a WHERE condition on a column from the right table (which would convert the LEFT JOIN to INNER JOIN).
You can do this without using a union. The statement below gets all rows from the master table, and join any existing rows from both the spanish and english tables.
If a row exists in the spanish table, it uses the values from that table. If a row exists in the english table, and not the spanish table, it uses the values from that table.
If no matching row exists in either the english or spanish table, it returns columns from the master table.
You can alter the priorities by changing the order of the WHEN's.
SELECT
CASE
WHEN NOT s.id IS NULL THEN s.id
WHEN NOT e.id IS NULL THEN e.id
ELSE m.id AS `id`,
CASE
WHEN NOT s.reference_id IS NULL THEN s.reference_id
WHEN NOT e.reference_id IS NULL THEN e.reference_id
ELSE m.reference_id AS `reference_id`,
CASE
WHEN NOT s.title IS NULL THEN s.title
WHEN NOT e.title IS NULL THEN e.title
ELSE m.title AS `title`,
CASE
WHEN NOT s.created_by IS NULL THEN s.created_by
WHEN NOT e.created_by IS NULL THEN e.created_by
ELSE m.created_by AS `created_by`,
CASE
WHEN NOT s.publish_up IS NULL THEN s.publish_up
WHEN NOT e.publish_up IS NULL THEN e.publish_up
ELSE m.publish_up AS `publish_up`,
CASE
WHEN NOT s.state IS NULL THEN s.state
WHEN NOT e.state IS NULL THEN e.state
ELSE m.state AS `state`
FROM z_news_master m
LEFT JOIN z_news_spanish s ON m.id = s.reference_id
LEFT JOIN z_news_english e ON m.id = e.reference_id
WHERE m.created_by = 17152
ORDER by m.id DESC
GROUP BY m.id
EDIT
Per Paul Spiegel's comment here's an even shorter version:
SELECT
COALESCE(s.id, e.id, m.id) AS `id`,
COALESCE(s.reference_id, e.reference_id, m.reference_id) AS `reference_id`,
COALESCE(s.title, e.title, m.title) AS `title`,
COALESCE(s.created_by, e.created_by, m.created_by) AS `created_by`,
COALESCE(s.publish_up, e.publish_up, m.publish_up) AS `publish_up`,
COALESCE(s.state, e.state, m.state) AS `state`
FROM z_news_master m
LEFT JOIN z_news_spanish s ON m.id = s.reference_id
LEFT JOIN z_news_english e ON m.id = e.reference_id
WHERE m.created_by = 17152
ORDER by m.id DESC
GROUP BY m.id

Query for multiple count values

SELECT cm.commenter_id,
cm.comment,
m.id,
(
SELECT COUNT(*) AS r_count
FROM comments
GROUP BY comments.commenter_id
) AS count,
m.display_name
FROM comments cm
INNER JOIN members m
ON cm.commenter_id = m.id
From this query I want to get the display_name for the person with the highest count of comments. Any guidance is appreciated.
SELECT m.id, m.display_name, COUNT(*) totalComments
FROM comments cm
INNER JOIN members m
ON cm.commenter_id = m.id
GROUP BY m.id, m.display_name
HAVING COUNT(*) =
(
SELECT COUNT(*) totalCount
FROM Comments
GROUP BY commenter_id
ORDER BY totalCount DESC
LIMIT 1
)
SQLFiddle Demo
SQLFiddle Demo (with duplicates)
I think the simplest way is just to sort your query and take the first row:
SELECT cm.commenter_id,
cm.comment,
m.id,
(
SELECT COUNT(*) AS r_count
FROM comments
GROUP BY comments.commenter_id
) AS count,
m.display_name
FROM comments cm
INNER JOIN members m
ON cm.commenter_id = m.id
order by count desc
limit 1

SQL Query with Joins Counting multiple Results Per Record Ordering By Count

I have a table called Request.
Other tables are linked to the Request table through a request id.
There is a TwitterTweet table and a FacebookPost table.
So a single request can have 50 TwitterTweets and/or 20 FacebookPosts or any amount of Tweets/Posts
We can add them together for a total count of 70.
I'm trying to create a query that could tell me what is the request with the highest total count.
I know this is wrong:
(I attempted to just order them by the counts within the TwitterTweet, but it would not let me do an OUTER JOIN which I thought
would bring back the Count.count column. It forced me to do a Left Join for it to compile. My Logic was to do a join so
that the results were calculated for each row by the requestid)
SELECT r1.`id` AS requestid, r1 . *
FROM `Request` AS r1
LEFT JOIN
(SELECT COUNT( * ) AS count, rid
FROM
((SELECT `TwitterTweet`.`id` AS `smid` , `TwitterTweet`.`requestid` AS rid
FROM `TwitterTweet`
WHERE `TwitterTweet`.`requestid` = requestid
AND `TwitterTweet`.`active` =1) AS talias
)) AS Count ON ( Count.rid = requestid )
ORDER BY Count.count
*When I tried to add in the Facebook side it would not compile any more
(The concept is that the results are added from TwitterTweet with the results from FacebookPost
that are attached to the specific requestid which would give us a count. The entire result
set should be ordered by that count)
SELECT r1.`id` AS requestid, r1 . *
FROM `Request` AS r1
LEFT JOIN
(SELECT COUNT( * ) AS count, rid
FROM
((SELECT `TwitterTweet`.`id` AS `smid` , `TwitterTweet`.`requestid` AS rid
FROM `TwitterTweet`
WHERE `TwitterTweet`.`requestid` = requestid
AND `TwitterTweet`.`active` =1 ) AS talias
UNION All
(SELECT `FacebookPost`.`id` AS `smid`, `FacebookPost`.`requestid` AS rid
FROM `FacebookPost`
WHERE `FacebookPost`.`requestid` = requestid
AND `FacebookPost`.`active` = 1) as falias
)) AS Count ON ( Count.rid = requestid )
ORDER BY Count.count
I updated the Query with an attempt to add an alias:
SELECT rid, SUM(count) total_count
FROM
(
(SELECT COUNT(*) AS count, r.rid
FROM request r
JOIN TwitterTweet tt
ON r.id = tt.requestid
WHERE tt.active = 1
GROUP BY r.rid) AS twitter
UNION ALL
(SELECT COUNT(*) AS count, r.rid
FROM request r
JOIN FacebookPost fp
ON r.id = fp.requestid
WHERE fp.active = 1
GROUP BY r.rid ) AS fbook
)
GROUP BY rid
ORDER BY SUM(count) DESC
I made another adjustment to give the middle subquery an alias, but now I only get one row returned with a zero in the rid column and 5686 in the total_count column...the 5686 might be all of the results.
SELECT counts.rid, SUM(count) total_count
FROM
(
SELECT COUNT(*) AS count, r.requestid AS rid
FROM request r
JOIN TwitterTweet tt
ON r.id = tt.requestid
WHERE tt.active = 1
GROUP BY r.requestid
UNION ALL
SELECT COUNT(*) AS count, r.requestid AS rid
FROM request r
JOIN FacebookPost fp
ON r.id = fp.requestid
WHERE fp.active = 1
GROUP BY r.requestid
) AS counts
GROUP BY counts.rid
ORDER BY SUM(count) DESC
Got it!!!
Thanks for your help guys, I had to remove those joins on the request:
SELECT counts.rid, SUM(count) total_count
FROM
(
SELECT COUNT(*) AS count, tt.requestid AS rid
FROM TwitterTweet tt
WHERE tt.active = 1
GROUP BY tt.requestid
UNION ALL
SELECT COUNT(*) AS count, fp.requestid AS rid
FROM FacebookPost fp
WHERE fp.active = 1
GROUP BY fp.requestid
) AS counts
GROUP BY counts.rid
ORDER BY SUM(count) DESC
SELECT id, SUM(count) total_count
FROM
(
SELECT COUNT(*) AS count, r.id
FROM request r
JOIN TwitterTweet tt
ON r.id = tt.requestid
WHERE tt.active = 1
GROUP BY r.id
UNION ALL
SELECT COUNT(*) AS count, r.id
FROM request r
JOIN FacebookPost fp
ON r.id = fp.requestid
WHERE fp.active = 1
GROUP BY r.id
) sub
GROUP BY id
ORDER BY SUM(count) DESC
;