Mysql count per name reset per name change - mysql

I have a table with entries names,date etc.
select name from names
order by names
for example.
I need an output like
1|paul
2|paul
1|morne
1|marone
2|marone
3|marone
i have no clue where to start to do a count like this for when i grou i cant get this right.

In MySQL, the easiest way to do this is with variables:
select n.name,
(#rn := if(#name = name, #rn + 1, 1)) as seqnum,
#name := name
from names n cross join
(select #name := '', #rn := 0) var
order by names;
EDIT:
In case anyone comes across this answer, the above sort-of works, but MySQL does not guarantee the order of evaluation of expressions. So, I now write the above as:
select n.name,
(#rn := if(#name = name, #rn + 1,
if(#name := name, 1, 1)
)
) as seqnum
from names n cross join
(select #name := '', #rn := 0) var
order by names;
Because all the variable assignments are in one statement, there is no problem with the order of evaluation of expressions in the select statement.

Related

Ranking order with having same rank repeating to the same level rank category

I am little new to sql and I need to rank my votes table based on votes assigned to each person and rank should be same for the similar votes.
My table would be like
CREATE TABLE votes ( name varchar(10), votes INT );
INSERT INTO votes VALUES
('Ann',100), ('Jones',151), ('Smith',100), ('Rose',240), ('Lee',500), ('Adhams',500);
In my display rows I need to have the rank column first and it should display the rank based on the highest number of votes. Importantly same number of votes need to have the same rank.
I have tried it several times and failed to do it...
Please help me
thanks
You can try below code. There are many links available which would be easily find your answer if you have carefully searched.
SET #rank=0;
SET #votes=0;
select x.rank as rank, x.name as name, x.votes as votes
from(
select #rank:=if(#votes=votes,#rank, #rank +1)AS rank,
#votes := votes,
v.name,
v.votes
from votes v
order by v.votes desc) as x;
To generate RANK, you first need a row number in the order of decreasing votes (variable #rn) and then based on the previous value of vote, create rank (variable #rank).
Try this:
SELECT v.*,
#rank := if((#rn := #rn + 1) is not null,
if (#votes = votes,
#rank,
if ((#votes := votes) is not null, #rn, 1)
),1
) rank
FROM votes v
CROSS JOIN (
SELECT
#votes := NULL,
#rank := 0,
#rn := 0
) t
ORDER BY v.votes DESC;
Demo
About this:
(#rn := #rn + 1) is not null
Since, the expression #rn := #rn + 1 can't be null, we use it to our advantage by not duplicating the whole logic twice.
You can use variables for this:
SELECT #rnk := IF(#v = votes, #rnk,
IF(#v := votes, #rnk + 1, #rnk + 1) AS rnk
name, votes
FROM mytable
CROSS JOIN (SELECT #rnk := 0, #v = :0) AS vars
ORDER BY votes DESC

MariaDB/MySQL RANK() implementation

I am working on migration from MS SQL Server to MariaDB 10.0. I have query which use RANK() PARTITION BY. I already created some kind of RANK() implementation on my table but it's not working properly.
The original query was:
RANK() OVER (PARTITION BY visits.id_partner ORDER BY visits.updated_at DESC) AS rank
My implementation for MariaDB/MySQL:
SELECT
...,
(
CASE visits.id_partner
WHEN #currId THEN
#curRow := #curRow + 1
ELSE
#curRow := 1 AND #currId := visits.id_partner
END
) AS rank
FROM
records rec
JOIN visits ON visits.id = rec.id_visit,
(
SELECT
#curRank := 0,
#currId := NULL
) r
WHERE
...
ORDER BY visits.id_partner ASC, visits.updated_at DESC
I want to select row ranked by id_partner order by updated_at field. When id_partner is same as on row before RANK should increase by 1. When is different than before, it should reset to 1.
But my query is not working at all. I have still rank 1 on all rows. Can you help me find mistake?
Thank you for help!
It is tricky to use variables in MySQL/MariaDB. A variable should only be used and assigned in one statement (as you do correctly). However, AND can short-circuit variable assignment.
I use a construct like this for ROW_NUMBER(). RANK() is actually a bit of a pain . . . DENSE_RANK() and ROW_NUMBER() are simpler. However, this seems to be the code that you are aiming for:
SELECT ...,
(#rn := if(#currId = visits.id_partner, #rn + 1,
if(#currId := visits.id_partner, 1, 1)
)
) as rank
FROM records rec JOIN
visits
ON visits.id = rec.id_visit CROSS JOIN
(SELECT #rn := 0, #currId := NULL) params
WHERE
...
ORDER BY visits.id_partner ASC, visits.updated_at DESC;
EDIT:
In MySQL (and presumably in MariaDB), sometimes variables don't work quite right unless you use a subquery. So, try this:
SELECT . . .,
(#rn := if(#currId = visits.id_partner, #rn + 1,
if(#currId := visits.id_partner, 1, 1)
)
) as rank
FROM (SELECT ...
FROM records rec JOIN
visits
ON visits.id = rec.id_visit
WHERE
...
ORDER BY visits.id_partner ASC, visits.updated_at DESC
) t CROSS JOIN
(SELECT #rn := 0, #currId := NULL) params;

Resetting a variable within subquery

If I can increment a variable within a query to append a rank column as such:
SET #i = 0;
SELECT *, #i:=#i+1 AS rank FROM table WHERE column="value" ORDER BY time;
How can I perform this as a sub-query for all unique column values? I believe the real issue is resetting the variable.
If you want to an incremental number for each column (in the fashion of row_number() in most other databases), you can still use variables:
SELECT t.*,
(#i := if(#c = column, #i + 1,
if(#c := column, 1, 1)
)
) as rank
FROM table t CROSS JOIN
(SELECT #i := 0, #c := '') params
ORDER BY column, time;

Getting the rank of a record using two where clauses

I am trying to get the rank of specified record, and I have some success with this code:
SELECT `rank`
FROM
(
select #rownum:=#rownum+1 `rank`, p.*
from TableName p, (SELECT #rownum:=0) r
order by point DESC
) s
WHERE names = 'house'
(See the schema here.)
This SQL query works, but if I want to get the result according to city_id and name, I must use two where clauses, and then the code doesn't work.
I want to get rank of house only for its city. How can I do this?
I want to get rank of "house" only for its city
You can do this by introducing another variable to keep track of the city:
SELECT `rank`
FROM (select p.*,
(#rn := if(#c = city, #rn + 1,
if(#c := city, 1, 1)
)
) as rank
from TableName p CROSS JOIN
(SELECT #rn := 0, #c := -1) params
order by city_id, point DESC
) s
WHERE names = 'house' ;
You can also use your original query, with a tweak, if you know that "house" only appears once in the data:
SELECT `rank`
FROM (select p.*, (#rn := #rn + 1) as rank
from TableName p CROSS JOIN
(SELECT #rn := 0) params
where city_id = (select city_id from TableName t2 where t2.names = 'house')
order by point DESC
) s
WHERE names = 'house' ;

Updating Incremental Values in a Column for a Related Column in MySQL

I'm working on fixing our (forum) database as it seems that several posts in certain threads are showing up with the same post number (#2). It seems that they all hold a position of "1" within each respective forum thread.
I've managed to find a query that will set these position values to the proper number via the query below:
select #i := -1; update `xf_post` set position = (select #i := #i + 1) where thread_id=1;
Unfortunately, I've only been doing this update query through the MySQL command line where I'm constantly selecting the Up Arrow key, incrementing the 'thread_id' value by 1, and hitting the Return key. Is there a faster way to do this through a loop or cursor? I'm not very familiar with the other parts of the SQL syntax and I only get by with the basics.
You can use the following query to get the numbers that you want for each thread:
select thread_id,
(case when #prev = thread_id then #rn := 1 else #rn := #rn + 1 end) as rn,
#prev = #threadid
from xf_post p cross join
(select #rn := 0, #thread_id = -1) const
order by thread_id, position
You can test this out to be sure that it produces the right values. Next you can do an update with a join:
update xf_post join
(select thread_id, post_id,
(case when #prev = thread_id then #rn := 1 else #rn := #rn + 1 end) as rn,
#prev = #threadid
from xf_post p cross join
(select #rn := 0, #thread_id = -1) const
order by thread_id, post_id
) toupdate
on xf_post.post_id = toupdate.post_id
set xf_post.position = toupdate.rn;