Recount UserID column - mysql

I'm working on my website and I noticed all the users have ID's like 1.337.134.060
I want to recount this so it will start from UserID 1 again.
How can I do this without harming the existing user accounts?

If you want to have an additional column as row count then,
select tbl.*,
#r := #r + 1 as new_userID
from tbl,
(select #r := 0) r
If you want to update the user id like 1, 2 , 3 etc then,
update tbl t
join (
select tbl.id,
#r := #r + 1 as new_userID
from tbl,
(select #r := 0) r
) x
on x.id = t.id
set t.id = x.new_userID
Assuming User id is all unique.

Related

mysql / sql: how to delete all rows except the Nth last per user?

I have a message (id, userid, message) table that grows rapidly.
I would like to delete all messages per user except his last 30
ex:
if user1 has 100 messages, we will delete the first 70,
if user2 has 40 messages, we will delete the first 10,
if userN has 10 messages, no action is taken
Is there a way to do it with a single SQL ?
My idea for now is to make a LOOP with PHP and lake N sql, which is very long for N users.
MySQL (pre 8.0) doesn't have a really convenient way to do this. One method uses variables to enumerate the values:
select m.*,
(#rn := if(#u = userid, #rn + 1,
if(#u := userid, 1, 1)
)
) as seqnum
from (select m.*
from messages m
order by userid, id desc
) m cross join
(select #u := -1, #rn := 0) params;
You can turn this into a delete using join:
delete m
from messages m join
(select m.*,
(#rn := if(#u = userid, #rn + 1,
if(#u := userid, 1, 1)
)
) as seqnum
from (select m.*
from messages m
order by userid, id desc
) m cross join
(select #u := -1, #rn := 0) params
) mm
on m.id = mm.id
where seqnum > 30;
As I say in a comment, I don't think this is a good solution for a real-world problem. The history of messages is useful and there are probably other ways to achieve the performance you want. The difference between 30 messages for a user and 70 messages for a user should not have that much of an effect on performance, in a tuned system.
SET #row_number = 0;
DELETE FROM MESSAGE
WHERE ID IN
( SELECT ID FROM
(SELECT ID,
#row_number:=CASE
WHEN #userid = userid THEN
#row_number + 1
ELSE 1
END AS num,
#userid:=userid as userid
FROM MESSAGE) A
WHERE NUM > 70 )

MySQL join table to itself based on row number returns no data

I've got a logs table with an ID column in it, and I want to do the following:
Select the ID and row number
Join the table to itself based on the row number
My objective is to get a specific row as well as the row before it. The SQL query below actually returns nothing. It's like it forgets the row number entirely. Joining on ID returns just fine.
Is there something that needs to be done in MySQL to support this kind of operation?
select * from
(select id, #rownum := #rownum + 1 as 'row'
from logs, (select #rownum := 0) r order by id) a
join
(select id, #rownum := #rownum + 1 as 'row'
from logs, (select #rownum := 0) r order by id) b
on a.row = b.row;
Change your variable name in second query, using same variable in both queries can produce unexpected results
select * from
(select id, #rownum := #rownum + 1 as 'row'
from logs, (select #rownum := 0) r order by id) a
join
(select id, #rownum1 := #rownum1 + 1 as 'row1'
from logs, (select #rownum1 := 0) r order by id) b
on a.row = b.row1;

Mysql join with limits on joined table

I am trying to return a limited of number of products per brand. The tables are
brands:
id, name
products:
id, brand_id, name
What I am trying to achieve is a query that will output brands.name and products_name 10 times for each brand.
I have tried joining the two tables but when it comes to applying the limit I can't see the next step. Is this possible or will I have to opt to do the brand query first and then query again on a foreach this being more processor intensive?
Get 10 records per product from the second table by the following query:
SELECT *
FROM(
SELECT id, brand_id, name, #n := IF(#r = brand_id, #n + 1, 1) AS rownum,
#r := brand_id
FROM product, (SELECT #r := 0, #n := 0) a
ORDER BY brand_id, id
) a
WHERE a.rownum <= 10;
And join it with brand table, e.g.:
SELECT *
FROM brand b
JOIN (SELECT *
FROM(
SELECT id, brand_id, name, #n := IF(#r = brand_id, #n + 1, 1) AS rownum,
#r := brand_id
FROM product, (SELECT #r := 0, #n := 0) a
ORDER BY brand_id, id
) a
WHERE a.rownum <= 10
) p on b.id = p.brand_id;
Here's the SQL Fiddle.

Updating a column based on its position in the results

I have a query that loops through each result and updates a column:
SET #counter = 0;
UPDATE users SET rank_level = #counter := #counter + 1 ORDER BY level DESC;
SELECT rank_level, level FROM users ORDER BY rank_level ASC;
Which outputs:
But what I am trying to do is only increment the variable if the level value changes. So where the two rows that have the same level are, they would have the same rank of 8 too.
Any ideas? Thanks.
rank() is a bit tricky in MySQL. One way is with a correlated subquery:
select u.*,
(select count(*) + 1
from users u2
where u2.level < u.level
) as rank
from users u;
This is tricky to put into an update. Assuming you have a userId column, you can use join:
update users u join
(select u.*,
(select count(*) + 1
from users u2
where u2.level < u.level
) as rank
from users u
) ur
on u.userId = ur.userId
set rank_level = rank;
Doing a rank with variables is rather tricky (row_number() and dense_rank() are easier), because it requires three variables. Here is the select version:
select u.*,
(#r := if(#l = level,
if(#rn := #rn + 1, #r, #r)
if(#l := level,
#rn := #rn + 1, #rn := #rn + 1
)
)
) as ranking
from users u cross join
(select #l := -1, #rn : = 0, #r := 0) params
order by level;
So in the end I went with this:
SET #prev_value = NULL;
SET #rank_count = 0;
UPDATE users SET rank_level = CASE
WHEN #prev_value = level THEN #rank_count
WHEN #prev_value := level THEN #rank_count := #rank_count + 1
END
ORDER BY level DESC;
Based on this answer: Rank function in MySQL

Mysql query to get the row position in a table

I have table with id (store user id) and score in different match. I want what is the position of a user.
So for i try this sql fiddle;
in this I am getting all the row but I need only user having id 3 and it position in the table.
like this:
Score Postion
26 3
Even i try to do like this but no success
MySql: Find row number of specific record
With MySQL, how can I generate a column containing the record index in a table?
I got the answer: http://sqlfiddle.com/#!2/b787a/2
select * from (
select T.*,(#rownum := #rownum + 1) as rownum from (
select sum(score) as S,id from mytable group by id order by S desc ) as T
JOIN (SELECT #rownum := 0) r
) as w where id = 3
Updated sqlfiddle and above query. Now it is working perfectly.
I think this should do the trick:
SELECT totalScore, rownum FROM (
SELECT id,sum(score) AS totalScore,(#rownum := #rownum + 1) AS rownum
FROM mytable
JOIN (SELECT #rownum := 0) r
group by id) result
WHERE result.ID = 3;
just add a where clause
select x.id,x.sum,x.rownum
from(
select id,sum(score) as sum,(#rownum := #rownum + 1) as rownum
from mytable
JOIN (SELECT #rownum := 0) r
group by id
) x
where id =3