select last three commenter for each post (Greatest n per group) - mysql

MySQL
SELECT DISTINCT comments.commenter_id FROM comments WHERE ((oid IN (421,425)
AND otype = 'post') (oid IN (331) AND otype = 'photo')) ORDER BY
post_id,type,comment_id LIMIT 3
What i wanted to do is select last three distinct commenters for each individual post or photo with respective ids.
i.e max 3 commenters for each o_id and o_type combinations
But the above instead of yielding me last three distinct commenters yields me total three.
Where i am going wrong ? can anyone help me out ?
IF LIMIT IS 2
ID | oid | otype | commenter_id
1 1 post 1
2 1 post 1
3 1 post 2
4 1 post 3
5 2 post 1
6 1 photo 2
7 2 post 3
OUTPUT SHOULD BE
commenter_id| o_type | o_id
3 post 1
2 post 1
3 post 2
1 post 2
2 photo 1

SOLVED - GREATESET N PER GROUP
That was easy though! :P
This question helped me lot.
SELECT DISTINCT t.commenter_id,t.o_id,t.otype
from
(
SELECT c.*,
#row_number:=if(#post_id = oid, #row_number + 1, 1) AS row_number,
#oid:=oid AS varval
FROM comments c
join (select #row_number := 0, #oid:= NULL) as var
ON
((oid IN (425) AND otype = 'post') OR (oid IN (331) AND otype = 'photo'))
order by comment_id DESC
) t
where t.row_number <=2

Related

MySQL query help - 'count' as variable not working as expected

I have the following (fairly complex) query:
SELECT
#idx :=
CASE
WHEN #prev_paper = paper_id
THEN #idx +1
ELSE 1
END AS idx,
#prev_paper := t1.paper_id AS paper_id,
#cnt := (SELECT COUNT(DISTINCT(organization)) as dcnt from authors A INNER JOIN authors__papers AP on AP.author_id = A.author_id where AP.is_contact_author < 1 AND paper_id = #prev_paper GROUP BY paper_id) as org_count,
IF(#cnt > 1, GROUP_CONCAT('{', #idx, '}', first_name, last_name), GROUP_CONCAT(first_name, last_name)) AS names
FROM (
SELECT
AP.paper_id as paper_id, A.organization, A.first_name, A.last_name, A.country
FROM authors__papers AP
INNER JOIN authors A ON A.author_id = AP.author_id
WHERE AP.is_contact_author <1
) AS t1, (
SELECT #prev_paper := '', #idx :=0
) AS t2
GROUP BY paper_id, organization
ORDER BY paper_id, organization
And it outputs results as follows:
idx paper_id org_count names
1 5002 2 MarioIannazzo,EduardAlarcon
2 5002 2 {2}VikramPassi,{2}HimadriPandey,{2}MaxLemme
1 5003 1 {1}JiaSun
1 5004 1 Juan A.Leñero-Bardallo,AngelRodríguez-Vázquez,RicardoCarmona-Galán
1 5005 3 AlexandreVernhet,JeanCoignus
2 5005 3 {2}GerardGhibaudo
3 5005 3 {3}Jean-LucOgier,{3}GiulioTorrente,{3}DavidRoy
1 5006 1 {1}JerodMason,{1}PaulDicarlo,{1}HanchingFuh,{1}DavidWhitefield,{1}FlorinelBalteanu
1 5007 3 SivkhengKor,DavidSchwartz,JanosVeres,PingMei
2 5007 3 {2}ChristerKarlsson,{2}PerBroms
3 5007 3 {3}Tse NgaNg
...
As you can see, 'org_count' (#cnt) is not working as expected. '#idx' is not appended to the names sometimes when it should be because it's > 1 (like 5002) and is sometimes when it is not expected to be because it is = 1 (like 5003, 5006 ...). This should look like:
idx paper_id org_count names
1 5002 2 {1}MarioIannazzo,{1}EduardAlarcon
2 5002 2 {2}VikramPassi,{2}HimadriPandey,{2}MaxLemme
1 5003 1 JiaSun
1 5004 1 Juan A.Leñero-Bardallo,AngelRodríguez-Vázquez,RicardoCarmona-Galán
1 5005 3 {1}AlexandreVernhet,{1}JeanCoignus
2 5005 3 {2}GerardGhibaudo
3 5005 3 {3}Jean-LucOgier,{3}GiulioTorrente,{3}DavidRoy
1 5006 1 JerodMason,PaulDicarlo,HanchingFuh,DavidWhitefield,FlorinelBalteanu
1 5007 3 {1}SivkhengKor,{1}DavidSchwartz,{1}JanosVeres,{1}PingMei
2 5007 3 {2}ChristerKarlsson,{2}PerBroms
3 5007 3 {3}Tse NgaNg
...
It's like something seems off by 1, but I cannot for the life of me figure out what or why. Any help is appreciated!
Marking as answered. #Drew provided the link to Required Reading in his comment will hopefully lead to the solution.
I can't really tell what you want the query to do, but I think I know the problem. MySQL does not guarantee the order of evaluations of expressions in a select clause. So, variables are being assigned in some expressions and then used in others -- but the order of evaluation is unclear.
My problem in understand the query is based on things like the first column of the query is #prev_paper, but the first column of the results is labeled id.
The trick to using variables correctly is to put all the logic in a single expression.

Sum values in mysql table where userid is identical

I have read the different answers here on SO, but I am stuck on this question. Please help.
I have this mysql view named "activeuser":
userid COUNT(*) ACRONYM
1 23 admin
2 2 doe
3 4 tompa
12 4 Marre
13 1 Mia
1 2 admin
3 1 tompa
12 1 Marre
13 1 Mia
2 1 doe
3 1 tompa
12 1 Marre
How can I sum the COUNT column so that I get the following wanted result?
userid COUNT(*) ACRONYM
1 25 admin
2 3 doe
3 6 tompa
12 6 Marre
13 1 Mia
EDITED:
I used this query to create the view:
CREATE VIEW activeuser AS
(SELECT boats_comments.userid, COUNT(boats_comments.userid), boats_user.acronym, boats_user.email
FROM boats_comments
INNER JOIN boats_user
ON boats_comments.userid = boats_user.id
GROUP BY boats_comments.userid
ORDER BY COUNT(boats_comments.userid) DESC)
UNION ALL
(SELECT boats_answers.userid, COUNT(boats_answers.userid), boats_user.acronym, boats_user.email
FROM boats_answers
INNER JOIN boats_user
ON boats_answers.userid = boats_user.id
GROUP BY boats_answers.userid
ORDER BY COUNT(boats_answers.userid) DESC)
UNION ALL
(SELECT boats_questions.userid, COUNT(boats_questions.userid), boats_user.acronym, boats_user.email
FROM boats_questions
INNER JOIN boats_user
ON boats_questions.userid = boats_user.id
GROUP BY boats_questions.userid
ORDER BY COUNT(boats_questions.userid) DESC)
My goal is to see which users are the most active by checking the number of comments, questions and answers... but I got stuck...
As the results in your view has duplicates I guess the underlying code for the view is grouping on something it maybe shouldn't be grouping on.
You can get the results you want by applying SUM to it:
select userid, sum("whatever column2 is named") as "Count", Acronym
from activeuser group by userid, Acronym;
select userid, count(*) from activeuser group by userid;

How to get rank in MySQL from 2 tables?

I have 2 different tables in my database by the name of: rank, settings.
Here is how each table looks like with a few records in them:
Table #rank:
id points userid
-- ----- ------
1 500 1
2 300 2
3 900 3
4 1500 4
5 100 5
6 700 6
7 230 7
8 350 8
9 850 9
10 150 10
Table #settings:
userid active
------ ------
1 0
2 1
3 1
4 1
5 1
6 0
7 1
8 1
9 0
10 1
I want to get the rank of a specific user by user_id from the rank table ordering by their points. Also I would Only want to include the users in the ranking results, if they have active = 1 set in the settings table.
I have a simple ranking query, but it is not really effective, because it does include everyone even if the user is not active:
SELECT * FROM
(SELECT #sort:=#sort+1 AS sort, points, userid
FROM rank,
(SELECT #sort := 0) s
ORDER BY points DESC) t
WHERE userid= 8
Any idea, how could I achieve my goals here?
Few sub queries. First gets all the users who are active in the right order. That is used as a source for another query to add the rank. Then this is used as the source for the points and rank for the userid you are actually interested in
SELECT sort, points
FROM
(
SELECT #sort:=#sort + 1 AS sort, points, userid
FROM
(
SELECT rank.points, rank.userid
FROM rank
INNER JOIN settings
ON rank.userid = settings.userid
WHERE settings.active = 1
ORDER BY points DESC
) sub0
CROSS JOIN (SELECT #sort:=0) sub2
) sub1
WHERE sub1.userid = 8
Borrowing the idea from: https://stackoverflow.com/a/4474389/92063
SELECT
#rn:=#rn+1 AS RANK
,USER_ID
,POINTS
FROM (
SELECT
R.userid AS USER_ID
,R.points AS POINTS
FROM
rank R
INNER JOIN
settings S
ON R.userid = S.userid
WHERE
S.active = 1
ORDER BY
R.points DESC
) t1, (SELECT #rn:=0) t2;

mysql extra count field for each row

I have a query here, anyone can help me to count the total duplicated fields?
SELECT *
FROM item
INNER JOIN itemgroup on item.itemgroupid = itemgroup.itemgroupid
INNER JOIN status on status.statusid = item.status
INNER JOIN owner on owner.ownerid = item.owner
INNER JOIN
(
SELECT code //, (SELECT count(*) FROM item WHERE ....) as 'total_duplicateds'
FROM item
GROUP BY code
HAVING count(code) > 1
) dup ON item.code = dup.code
Total items: 500
Total items with duplicated codes: 149
Now I get a total of 149 fields returned, how can I add this as a new field to each row?
After the slash is how I learnt to do it but this is a little higher level for me..
Can someone help me out?
To be even more specific
What I'd like to get returned is like:
itemid | code| itemname | itemgroup | owner | total_duplicateds
1 1000 X 1 1 3
2 1000 X 2 2 3
3 1001 A 1 1 3
4 1000 B 3 1 3
5 1002 U 2 1 3
Add COUNT aggregation and GROUP BY all columns that are interesting you.

mysql queries in order -> limit,sort,group. How?

oh, that's driving me crazy. I have messages table, simplified example:
id[int] - sender[int] - receiver[int] - conv_id[bigint] - received[int] - stamp[int]
1 2 1 5 1 timestamp+1
2 2 1 5 1 timestamp+2
3 3 1 6 1 timestamp+3
4 4 1 7 1 timestamp+4
5 5 1 8 1 timestamp+5
6 5 1 8 1 timestamp+6
now I'm interesting a results grouped by receiver, limited to 3 senders and sorted by stamp DESC. How to do that?
I already have this, but it's taking all messages and i believe that's not the best way to not loose performance, even though I'm really not the guru of mysql:
SELECT id, sender, receiver, conv_id FROM
(SELECT m.id, m.sender, m.receiver,m.conv_id
FROM messages AS m WHERE m.receiver = 1 AND m.received = 1
ORDER BY m.stamp DESC) as messages_tmp
WHERE receiver = 1 GROUP BY conv_id ORDER BY NULL LIMIT 0,3
This should return these results in that order:
id = 6, id = 4, id = 3
The thing is I'm already doing to queries of this, for m.received = 0 and than if not enough of the results, for m.received = 1. So far my database isn't too big, but if it's gets bigger I'm afraid it can be slow. I'm thinking about possibility to limit results of the subquery, but have no idea how to that and be sure I'll get enough results after GROUP.
Thanks.
SELECT id, sender, receiver,conv_id
FROM messages WHERE receiver = 1 AND received = 1
GROUP BY conv_id
ORDER BY id DESC LIMIT 3