Re-assign id numbers in sorted table - mysql

i'm looking for solution to my problem.
I need to reassign id's in that order in which that table is sorted.
To be more clear here is the how table look:
| id | name | new_id |
| 1 | C | 1 |
| 2 | A | 2 |
| 3 | B | 3 |
Now we sort it by name in ASC mode:
| id | name | new_id |
| 2 | A | 2 |
| 3 | B | 3 |
| 1 | C | 1 |
Now we reassign id's in that order:
| id | name | new_id |
| 1 | A | 2 |
| 2 | B | 3 |
| 3 | C | 1 |
I use this code:
set #row_num = 0; SELECT #row_num := #row_num + 1 as `row_number`,`id`,`name`,`new_id` FROM `test` ORDER BY `name`;
it add new row row_number and add numbers in order that i need for id to be. How to do this.

You can do this using update:
set #rn := 0;
update t
set new_id = (#rn := #rn + 1)
order by name;
You don't really need to use new_id. If you want to re-set id, just set that instead.

Related

MySQL SET rank over First Column and Second Column

I'm trying to make a query setting rank column by First and Second column. Like Rank over Partition which doesn't exist MySQL
For example,
From
+----+-------+--------+------+
| id | First | Second | Rank |
+----+-------+--------+------+
| 1 | a | 10 | |
| 2 | a | 9 | |
| 3 | b | 10 | |
| 4 | b | 7 | |
| 5 | a | 1 | |
| 6 | b | 1 | |
+----+-------+--------+------+
To
+----+-------+--------+------+
| id | First | Second | Rank |
+----+-------+--------+------+
| 1 | a | 10 | 3 |
| 2 | a | 9 | 2 |
| 3 | b | 10 | 3 |
| 4 | b | 7 | 2 |
| 5 | a | 1 | 1 |
| 6 | b | 1 | 1 |
+----+-------+--------+------+
The Rank doesn't continue. It starts from 1 again when it reaches the last value of 'a' of 'First' column.
And it's gotta be SET not SELECT.
I wouldn't mind using SELECT but my point is I'm not trying to retrieve data from Database but setting values.
Cheers in advance mates.
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
,first CHAR(1) NOT NULL
,second INT NOT NULL
);
INSERT INTO my_table VALUES
(1,'a',10),
(2,'a',9),
(3,'b',10),
(4,'b',7),
(5,'a',1),
(6,'b',1);
SELECT id
, first
, second
, rank
FROM
( SELECT x.*
, CASE WHEN #prev = first THEN #i:=#i+1 ELSE #i:=1 END rank
, #prev:=first
FROM my_table x
, (SELECT #prev:=null,#i:=0) vars
ORDER
BY first
, second
, id
) a
ORDER
BY id;
+----+-------+--------+------+
| id | first | second | rank |
+----+-------+--------+------+
| 1 | a | 10 | 3 |
| 2 | a | 9 | 2 |
| 3 | b | 10 | 3 |
| 4 | b | 7 | 2 |
| 5 | a | 1 | 1 |
| 6 | b | 1 | 1 |
+----+-------+--------+------+
6 rows in set (0.00 sec)
Came up with a solution which I was looking for.
I'm not sure if these queries are completely safe but so far no harms.
SET #rank = 0, #First = ''
UPDATE 'Table' SET
rank = IF(#First = First, #rank:= #rank +1, #rank := 1 AND #First := First)
ORDER BY First ASC, Second;
One method is a correlated subquery. For rank() you can do:
select t.*,
(select count(*) + 1
from t t2
where t2.first = t.first and t2.second < t.second
) as rank
from t;
Ranks are tricky to handle with variables (dense_rank() and row_number() are simpler).
EDIT:
This is easy to turn into an update:
update t join
(select t.*,
(select count(*) + 1
from t t2
where t2.first = t.first and t2.second < t.second
) as new_rank
from t
) tt
on t.id = tt.id
set t.rank = tt.new_rank;

Counting and limiting number of rows per field value not working

I'm trying to limit the number of rows per field value of a given query. I've found this answered question:
here
As in the first answer of the link, I've created the following table:
create table mytab (
id int not null auto_increment primary key,
first_column int,
second_column int
) engine = myisam;
Inserted this data:
insert into mytab (first_column,second_column) values
(1,1),
(1,4),
(2,10),
(3,4),
(1,4),
(2,5),
(1,6);
And finally run this query
select
id,
first_column,
second_column,
row_num
from
(select
*,
#num := if(#first_column = first_column, #num + 1, 1) as row_num,
#first_column:=first_column as c
from mytab
order by first_column,id) as t,
(select #first_column:='',#num:=0) as r;
But instead of getting this result, where the row_num increases whenever first_column is repeated,
+----+--------------+---------------+---------+
| id | first_column | second_column | row_num |
+----+--------------+---------------+---------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 4 | 2 |
| 5 | 1 | 4 | 3 |
| 7 | 1 | 6 | 4 |
| 3 | 2 | 10 | 1 |
| 6 | 2 | 5 | 2 |
| 4 | 3 | 4 | 1 |
+----+--------------+---------------+---------+
I get this result:
+----+--------------+---------------+---------+
| id | first_column | second_column | row_num |
+----+--------------+---------------+---------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 4 | 1 |
| 5 | 1 | 4 | 1 |
| 7 | 1 | 6 | 1 |
| 3 | 2 | 10 | 1 |
| 6 | 2 | 5 | 1 |
| 4 | 3 | 4 | 1 |
+----+--------------+---------------+---------+
I literally copied the code from the link. I checked in SQL Fiddle and code works fine. I'm using XAMPP. Could that be the reason? If it is, is there any workaround to get something like the above working?
I'd really appreciate some help. Thanks in advance.
The variable assignment has to be in the sub-query.
select
id,
first_column,
second_column,
row_num
from
(select
m.*,
#num := if(#first_column = first_column, #num + 1, 1) as row_num,
#first_column:=first_column as c
from mytab m
cross join (select #first_column:='',#num:=0) r --this was in the outer query previously
order by first_column,id
) t

How to do such a mysql query?

I will ask for help from yours.
Example table:
| ID | NAME |POINT|
| 1 | alex | 2 |
| 2 | alex | 2 |
| 3 | jenn | 4 |
| 4 | shama| 3 |
| 5 | jenn | 4 |
| 6 | Mike | 1 |
I want to find repetitive name and change name value and sum repetitive value.
Like
| ID | NAME |POINT|
| 1 | alexander| 4 |
| 2 | jennifer | 8 |
Is it possible mysql query?
Thanks.
try this
select id,
case when name = 'alex' then replace(NAME,'alex','alexander')
when name = 'jenn' then replace(NAME,'jenn','jennifer')
end as d,sum(point)
from name group by d having d is not null;
Is this what you want?
select (#rn := #rn + 1) as id, name, sum(point) as point
from t cross join
(select #rn := 0) params
group by name
having count(*) >= 2;

Is there a way in MySQL to do a “round robin” ORDER BY on a particular field in variable universe?

My list is a infinite universe, as an example, I would like to take a table such as this one:
+-------+------+
| group | name |
+-------+------+
| 1 | A |
| 1 | B |
| 1 | C |
| 1 | D |
| 1 | E |
| 1 | F |
| 1 | G |
| 1 | H |
| 1 | I |
| 2 | J |
| 2 | L |
| 2 | M |
| 3 | N |
| 4 | O |
| 4 | P |
| 4 | Q |
| 4 | R |
| 4 | S |
| 5 | U |
| 6 | V |
+-------+------+
And run a query that produces results in this order:
+-------+------+
| group | name |
+-------+------+
| 1 | A |
| 2 | J |
| 3 | N |
| 4 | O |
| 5 | U |
| 6 | V |
| 1 | B |
| 2 | L |
| 4 | P |
| 1 | C |
| 2 | M |
| 4 | Q |
| 1 | D |
| 4 | R |
| 1 | E |
| 4 | S |
| 1 | F |
| 1 | G |
| 1 | H |
| 1 | I |
+-------+------+
select `group`, name from (
select
t.*,
#rn := if(`group` != #ng, 1, #rn + 1) as ng,
#ng := `group`
from t
, (select #rn:=0, #ng:=null) v
order by `group`, name
) sq
order by ng, `group`, name
see it working live in an sqlfiddle
To explain it a little...
, (select #rn:=0, #ng:=null) v
This line is just a fancy way to initialize the variables on the fly. It's the same as omitting this line but having SET #rn := 0; SET #ng := NULL; before the SELECT.
Then the ORDER BY in the subquery is very important. In a relational database there is no order unless you specify it.
Here
#rn := if(`group` != #ng, 1, #rn + 1) as ng,
#ng := `group`
the first line is a simple check, if the value of group in the current row is different from the value of #ng. If yes, assign 1 to #rn, if not, increment #rn.
The order of the columns in the SELECT clause is very important. MySQL processes them one by one. In the second line, we assign the value of group of the current row to #ng. When the next row of the table is processed by the query, in the first line of the two above, #ng will therefore hold the value of the previous row.
The outer select is just cosmetics, to hide unnecessary columns. Feel free to ask if anything is still unclear. Oh, and here you can read more about user defined variables in MySQL.
Note though, that needing variables is rather the exception. They often result in full table scans. Whatever you want to achieve with variables in select statements is often better done on application level, rather than database level.

mysql split row to multiple columns and rows

I have a table with the following structure and these values in column assoc.
| id | assoc |
| 1 | |3|-1|107|-4|146|-6| |
| 2 | |19|-3|107|-5| |
| 3 | |42|-1| |
You can see it here
This is a wrong mysql table structure. So I think that the right structure it must be:
| id | assoc | attrib | order |
| 1 | 3 | 1 | 1 |
| 1 | 107 | 4 | 2 |
| 1 | 146 | 6 | 3 |
| 2 | 19 | 3 | 1 |
| 2 | 107 | 5 | 2 |
| 3 | 42 | 1 | 1 |
Is possible to do with a mysql script on phpmyadmin?
SET #prev := null;
SET #cnt := 0;
SELECT id,blah,mah,IF(#prev <> id, #cnt := 1, #cnt := #cnt + 1) AS rank, #prev := id
FROM(
SELECT id,REPLACE(SUBSTRING_INDEX(assoc,'|',2),'|','')*1 as blah,
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(assoc,'-0'),'|',3),'-',-1)as mah FROM table1
UNION ALL
SELECT id,
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(assoc,'|0'),'|',4),'|',-1)*1 as blah,
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(assoc,'-0'),'|',5),'-',-1)as mah FROM table1
UNION ALL
SELECT id,
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(assoc,'|0'),'|',6),'|',-1)*1 as blah,
SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(assoc,'-0'),'|',7),'-',-1)as mah FROM table1
)x
WHERE x.mah !='0'
ORDER BY x.id ,x.blah
FIDDLE