MySQL Counting occurrences of an ID - php

I have the following query which returns event details and a rank based on the number of votes.
SELECT e.guid, e.name, e.desc, e.location, e.votes,
#curRank := #curRank + 1 AS rank
FROM event e, (SELECT #curRank := 0) r
ORDER BY votes DESC
This gives me the required output. However because I want to store more information about who has voted (to determine if a user can vote - as 1 vote per person is allowed). I created a new table called event_votes which looks like:
event_vote_id | event_guid | user_guid
1 abc1 def6
2 ghi4 def6
3 abc1 lmn2
How can I get the first query to work again replacing e.votes (a field which increments) with the number of occurrences of event_guid in event_votes
Expected Result
guid: abc1
name: testevent
desc: example
location: London
votes: 2
rank: 1

I did not test it, but hopefully, it works.
SELECT e.guid, e.name, e.desc, e.location,
(SELECT COUNT(ev.id) FROM event_votes ev WHERE ev.event_guid = e.guid) AS votes,
#curRank := #curRank + 1 AS rank
FROM event e, (SELECT #curRank := 0) r
ORDER BY votes DESC

Related

Get position of an ID based on MySQL COUNT result

I am not even sure if this has been answered because I don't even know how to coin the problem. But here is what am trying to do.
I am using COUNT() to create a tabular representation of a data from top to bottom for a 30 day period.
SELECT id FROM table WHERE col = '123' AND date >= DATE_SUB(CURRENT_DATE, INTERVAL DAYOFMONTH(CURRENT_DATE)-1 DAY) AND date <= LAST_DAY(CURRENT_DATE) GROUP BY id ORDER BY COUNT(id) DESC
And I get the result with the most at the top
id | col
==========
id3 | 123
id5 | 123
id2 | 123
id4 | 123
id8 | 123
id5 | 123
id1 | 123
id9 | 123
id7 | 123
This works fine for a tabular view and I can use ol to create a numbering system from 1 - 10. My issue is, I want to be able to tell the position of any given id. Eg. if I want to get the position of id9 in this count result i.e. 8, how do I do that?
If you are using MySQL v8.0 or higher you can use the RANK function:
SELECT COUNT(*), RANK() OVER (ORDER BY COUNT(id) DESC) AS r FROM table GROUP BY id ORDER BY COUNT(id) DESC;
For previous version of mysql, you need to create the variable your self:
SELECT COUNT(*), #rank := #rank + 1 AS r FROM table, (SELECT #rank := 0) temp ORDER BY COUNT(id) DESC;
Note SELECT #rank := 0 initiate the variable.
Updated:
To select a specific id and it's rank, you can use:
SELECT * FROM (
SELECT id, COUNT(*), RANK() OVER (ORDER BY COUNT(id) DESC) AS r FROM table GROUP BY id ORDER BY COUNT(id) DESC
) ranked WHERE id = ?;

A sort query in SQL by special criteria

I have a table products, and a table product-languages.
products:
prd_id|prd_name
product-languages:
prd_id|language_id|prd_name
1 |1 |Product_German_name
1 |2 |Product_English_name
1 |4 |Product_French_name
I want to join product-languages on prd_id and then sort it by my priority list of language_id (for example: 2,1,4) - first I want the result of lang_id=2, if this is not available I want to have lang_id=1 as the first result.
Is this possible in SQL? I think my personal order list is the problem, because I would have to check if that lang_id is even available...
Subquery maybe?
Thanks
You can do this in standard SQL via case with something like:
select
*
from
products p,
product_languages l
where
p.prd_id = l.prd_id
order by
(case language_id
when 2 then 1
when 1 then 2
when 4 then 3
end) asc
This is a bit of a pain in MySQL, but you can do it. One method uses variables:
select t.*
from (select t.*,
(#rn := if(#prd_id = prd_id, #rn + 1,
if(#prd_id := prd_id, 1, 1)
)
) as rn
from producct_languages t join
(select #prd_id := -1, #rn := 0) params
order by prd_id, field(language_id, 2, 1, 4)
) t
where rn = 1;

Calculating score based on rank position

I have a table jackpot with columns uid for user ID and nright for number of right answers.
I manage to SELECT and rank users by right answers, but what next?
SELECT
a1.uid,
a1.nright,
COUNT(a2.nright) AS rank
FROM
jackpot a1,
jackpot a2
WHERE
a1.nright < a2.nright
OR (
a1.nright = a2.nright
AND a1.uid = a2.uid
)
GROUP BY
a1.uid,
a1.nright
ORDER BY
a1.nright DESC,
a1.uid DESC
I need to calculate the amount of points to give to each user depending on his position.
Only users with top 3 MAX nright receive points.
The total amount of points = the number of users*20.
First position gets 70% of the total, 2nd - 20%, 3rd - 10%.
In case of equal right answers between users, the points are split evenly (50/50, 33/33/33...).
SQL Fiddle
You need to decompose what you want.
1st step : You want the top 3 scores.
SELECT nright
FROM jackpot
ORDER BY nright DESC
LIMIT 3
2nd step : The user id who gets this 3 first scores
SELECT j.uid
FROM jackpot j
INNER JOIN (
SELECT nright
FROM jackpot
ORDER BY nright DESC
LIMIT 3 ) AS t ON t.nright = j.nright
3rd step: the total amount of point
SELECT COUNT(uid)*20 AS lot FROM jackpot
4th step: the rank and the number of person
Here we need to use a variable, as you are in php, you can't use set #var:= X; , so the trick is to do a Select #var:= X , this variable will not work because of the aggregate functions. So you need to do this :
SELECT #rank := #rank+1 as rank,T1.nright,T1.nb,T1.lot
FROM(
SELECT nright,
COUNT(uid) as nb,
(SELECT COUNT(uid)*20 FROM jackpot) as lot
FROM jackpot
GROUP BY nright
ORDER BY nright DESC
LIMIT 3
)T1, (SELECT #rank:= 0) r
5th step: The lots distribution
SELECT j.uid,
CASE
WHEN t.rank = 1 THEN (t.lot*0.7)/t.nb
WHEN t.rank = 2 THEN (t.lot*0.2)/t.nb
WHEN t.rank = 3 THEN (t.lot*0.1)/t.nb
END as lot
FROM jackpot j
INNER JOIN
(SELECT #rank := #rank+1 as rank,T1.nright,T1.nb,T1.lot
FROM(
SELECT nright,
COUNT(uid) as nb,
(SELECT COUNT(uid)*20 FROM jackpot) as lot
FROM jackpot
GROUP BY nright
ORDER BY nright DESC
LIMIT 3
)T1, (SELECT #rank:= 0) r) t ON t.nright = j.nright

concating renaming duplicate rows in mysql

I have a table like following
ID student_name dept email
1 Mary Wise Eng mary-wise#xxx.cc
2 John Walter Sc john-walter#xxx.cc
3 Sophia Jacob Politics sophia-jacob#xxx.cc
4 Ava William Eng ava-william#xxx.cc
5 Mary Wise Politics mary-wise#xxx.cc
6 John Walter Eng john-walter#xxx.cc
7 John Walter Politics john-walter#xxx.cc
8 Sophia Eng sophia#xxx.cc
9 Emma Eng emma#xxx.cc
10 Sherlock Eng sherlock#xxx.cc
The email ids col is generated by firstname-lastname#xxx.cc
The problem is when the name is same the email id is also same.
I want the email id to be appended with 1, 2, 3 when same name exists.
For example in table above
the mary-wise on 5th row should be mary-wise1#xxx.cc,
6th row should be, john-walter1#xxx.cc,
7th row should be, john-walter2#xxx.cc
How can I update my email column with mysql query as fast as possible.
I tried with php with mysql it takes too long when the table contains million rows.
Thanks
I believe it's better for you to make email column unique and to use ON DUPLICATE KEY UPDATE syntax (more here).
You still need to keep track of a number you want to append to the new value. For this purpose you can create a separate table with auto increment field and just get the new value from there.
The following SQL will enumerate the duplicates:
select t.*,
#rn := if(#StudentName = StudentName, 1, #rn + 1) as seqnum,
#StudentName := StudentName
from table t cross join
(select #rn := 0, #StudentName := '') const
order by StudentName;
You can put this in an update using join:
update t join
(select t.*,
#rn := if(#StudentName = StudentName, 1, #rn + 1) as seqnum,
#StudentName := StudentName
from table t cross join
(select #rn := 0, #StudentName := '') const
order by StudentName
) toupdate
on t.name = toupdate.name and toupdate.seqnum > 1
set email = concat(replace(t.StudentName, ' ', '-'), toupdate.seqnum - 1, '#xxx.cc);
It would be easy to achieve if you had CTE (maybe switch to postgres 9 if you can):
SELECT
id
, student_name
, concat(
replace(lower(student_name), ' ', '-')
, case
when cnt > 1 then numb
end
,'#xxx.cc'
) as newmail
FROM (
SELECT
count(*) over (partition BY student_name) as cnt
, count(*) over (partition BY student_name order by id) as numb
, id
, student_name
FROM tab1
order by id
) subq
sqlFiddle demo

php mysql order by priority and ranking

I have the following table :
Properties
id agency_id refno
1 1 AA101
2 3 AA201
3 2 AA501
4 1 AA762
5 3 AA555
agency
agency_id agency_name priority
1 A 30
2 B 10
3 C 20
I have defined the priority of each agency in the agency table:
Now I want to extract the rows from properties table based on the ranking and priority. I want to extract 1st row from 1st agency, 1st row from 2nd agency, 1st row from 3rd agency and so on.
Then 2nd row from 1st agency, 2nd row from 2nd agency, 2nd row from 3rd agency and so on.
Then I want to sort the whole result based on the priority of each agency. I am using the following clauses but its not giving the desired result
select properties.id,
properties.agency_id,
IF(#prev <> properties.agency_id, #cnt := 1, #cnt := #cnt + 1) AS rank, #prev := properties.agency_id,
properties.refno
where properties.agency_id = agency.agency_id
order by agency.priority, rank
i have put the join, and its working fine there is no error. but i need the results as follow:
i have defined the priority of each agency in the agency table. the query is working fine with join. i need the results as follow:
agency2 row1
agency3 row1
agency1 row1
agency2 row2
agency3 row2
agency1 row2
agency2 row3
agency3 row3
agency1 row3
according to the priority defined in the agency table and rank.
Please go through the concpet of a JOIN
The query must join the two tables.
select
properties.id,
properties.agency_id,
IF(#prev <> properties.agency_id, #cnt := 1, #cnt := #cnt + 1) AS rank,
#prev := properties.agency_id,
properties.refno
FROM properties
INNER JOIN agency ON properties.agency_id = agency.agency_id
order by agency.priority, rank

Categories