mysql split row to multiple columns and rows - mysql

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

Related

MySql - Join tables, count "distict" the id occurences and caluclate average

I need some help, please, with joining two queries.
I have two (or more) tables (same structure), as follows:
table_a
+-----------------+-------+
| id | date | value |
+----+------------+-------+
| 1 | 01-05-2018 | 8 |
| 1 | 03-05-2018 | 1 |
| 1 | 04-05-2018 | 1 |
| 1 | 05-05-2018 | 2 |
+----+------------+-------+
table_b
+-----------------+-------+
| id | date | value |
+----+------------+-------+
| 2 | 01-05-2018 | 10 |
| 2 | 03-05-2018 | 5 |
| 2 | 04-05-2018 | 10 |
| 2 | 05-05-2018 | 6 |
+----+------------+-------+
I'm "joining" them and calculating the AVG value row by row, date by date. This is how I DON'T WANT my results:
Result
+-----------------+--------+--------+
| cnt | id | date | average|
+----+------------+--------+--------+
| 1 | 1 | 01-05-2018 | 8 | <-- (8)
| 2 | 1 | 03-05-2018 | 4.5 | <-- (8+1=9/2)
| 3 | 1 | 04-05-2018 | 3.3 | <-- (8+1+1=10/3)
| 4 | 1 | 05-05-2018 | 3 | <-- (8+1+1+2=12/4)
| 5 | 2 | 01-05-2018 | 4.4 | <-- (8+1+1+2+10=22/5)
| 6 | 2 | 03-05-2018 | 4.5 | <-- (8+1+1+2+10+5=27/6)
| 7 | 2 | 04-05-2018 | 5.2 | <-- (8+1+1+2+10+5+10=37/7)
| 8 | 2 | 05-05-2018 | 5.3 | <-- (8+1+1+2+10+5+10+6=37/8)
+------+----+--------------+--------+
This is how it should be:
Result
+-----------------+-------+---------+
| cnt | id | date | average |
+----+------------+-------+---------+
| 1 | 1 | 01-05-2018 | 8 | <-- (8)
| 2 | 1 | 03-05-2018 | 4.5 | <-- (8+1=9/2)
| 3 | 1 | 04-05-2018 | 3.3 | <-- (8+1+1=10/3)
| 4 | 1 | 05-05-2018 | 3 | <-- (8+1+1+2=12/4)
| 1 | 2 | 01-05-2018 | 10 | <-- (10)
| 2 | 2 | 03-05-2018 | 7.5 | <-- (10+5=15/2)
| 3 | 2 | 04-05-2018 | 8.3 | <-- (10+5+10=25/3)
| 4 | 2 | 05-05-2018 | 7.7 | <-- (10+5+10+6=25/4)
+------+----+--------------+--------+
I'm playing around with this query:
select t.cnt,t.id,t.date, (average / cnt) as average
from (select t.*, (#rn := #rn + 1) as cnt, (#s := #s + value) as average
from table_a t
cross join (select #rn := 0, #s := 0) params) t
UNION ALL
select t.cnt,t.id,t.date, (average / cnt) as average
from (select t.*, (#rn := #rn + 1) as cnt, (#s := #s + value) as average
from table_b t
cross join (select #rn := 0, #s := 0) params) t
Basically, I need to join the tables, count distinct id occurences and calculate the average of the value, row by row (date) for each id. How can I adjust my query, please? Thanks in advance.
Your query seems to do the job you want. Just use different variable names for the two subqueries:
select t.cnt,t.id,t.date, (average / cnt) as average
from (select t.*, (#rn1 := #rn1 + 1) as cnt, (#s1 := #s1 + value) as average
from table_a t
cross join (select #rn1 := 0, #s1 := 0) params) t
UNION ALL
select t.cnt,t.id,t.date, (average / cnt) as average
from (select t.*, (#rn2 := #rn2 + 1) as cnt, (#s2 := #s2 + value) as average
from table_b t
cross join (select #rn2 := 0, #s2 := 0) params) t
Demo here

mysql sequence number by value coloumn (query UPDATE)

example:
I have a table with the columns
______________________
|field_id|Code|seq_num|
| 1 | a | 1 |
| 1 | a | 2 |
| 1 | a | 3 |
| 2 | a | 4 |
| 2 | a | 5 |
| 3 | a | 6 |
| 3 | a | 7 |
| 3 | a | 8 |
how to query it, so sequence number look like this
_____________________
|field_id|Code|seq_num|
| 1 | a | 1 |
| 1 | a | 2 |
| 1 | a | 3 |
| 2 | a | 1 |
| 2 | a | 2 |
| 3 | a | 1 |
| 3 | a | 2 |
| 3 | a | 3 |
please help!!
One method is to get the minimum sequence for the field:
select t.field_id, t.code,
(seq_num - min_seqnum + 1) as seqnum
from t join
(select field_id, min(seq_num) as min_seq_num
from t
group by field_id
) f
on t.field_id = f.field_id;
You can also do this using variables, if you don't trust the current sequence numbers to have no gaps:
select . . .,
(#rn := if(#f = field_id, #rn + 1,
if(#f := field_id, 1, 1)
)
) as seq_no
from (select t.*
from t
order by field_id, seq_no
) t cross join
(select #f := '', #rn := 0) params;

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

mysql, update foreach category

it is a really simple question. it is only 1 table!
i have a table of books which each book have a category and a number.
SO I WANNA TRANSFORM THIS
+--------------------------+
| book_id | category | num |
+--------------------------+
| 1 | a | 7 |
| 2 | a | 5 |
| 3 | a | 3 |
| 4 | b | 9 |
| 5 | b | 8 |
| 6 | b | 1 |
+--------------------------+
INTO THIS,
+--------------------------+
| book_id | category | num |
+--------------------------+
| 3 | a | 3 |
| 2 | a | 5 |
| 1 | a | 7 |
| 6 | b | 1 |
| 5 | b | 8 |
| 4 | b | 9 |
+--------------------------+
AND THEN THIS!
+--------------------------+
| book_id | category | num |
+--------------------------+
| 3 | a | 1 |
| 2 | a | 2 |
| 1 | a | 3 |
| 6 | b | 1 |
| 5 | b | 2 |
| 4 | b | 3 |
+--------------------------+
BUT HOW?!?!?!?!
script to create table...
drop table if exists books;
CREATE TABLE books(
id int AUTO_INCREMENT,
category varchar(30),
num int,
PRIMARY KEY (id)
);
insert into books (category,num)
values
('a',7),
('a',5),
('a',3),
('b',9),
('b',8),
('b',1);
You can use user variables to generate the sequence numbers within each category in the order of increasing id.
If you just want to query the table, use:
select
b.id,
b.category,
#rn := if(#category = category, #rn + 1, if (#category := category, 1, 1)) num
from books b, (select #category := null, #rn := 0) t2
order by b.category, b.id
If you want to update your table, use:
update books b1
join (
select
b.id,
#rn := if(#category = category, #rn + 1, if (#category := category, 1, 1)) num
from books b, (select #category := null, #rn := 0) t2
order by b.category, b.id
) b2 on b1.id = b2.id
set b1.num = b2.num;
Demo
EDIT:
As per the edited question, you can use order by b.category, b.num instead.

Re-assign id numbers in sorted table

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.