I have a csv file containing three columns, class,malecount and femalecount as an input table.
My output should contain two columns named Class and Gender.
The malecount and femalecount values indicates how many times a row should be repeated. i.e. for Class = A and malecount=2, the row (A,M) should appear twice, and for Class = C and femalecount=3, the row (C,F) should appear three times. Check the following image to see the full output.
DDL & DML for the table:
create table mytable (class text, malecount int, femalecount int);
insert into mytable (class, malecount, femalecount) values
( 'A',2,1),
('B',3,1),
('C',0,3),
('D',2,4);
CodePudding user response:
I used the LPAD function and then trimmed off the last comma from there I had a comma delimited string like M,M,M and F,F
then I used json_table to extract the M,M,M into three rows and the F,F into two rows etc.
here is the fiddle https://www.db-fiddle.com/f/jEXes6AttKvc9GKx1mKY2/1
Schema (MySQL v8.0)
create table mytable (class text, malecount int, femalecount int);
insert into mytable (class, malecount, femalecount) values
( 'A',2,1),
('B',3,1),
('C',0,3),
('D',2,4);
Query #1
with t as (select class,
LPAD(' ', malecount * 2 1, 'M,') malecount,
LPAD(' ', femalecount * 2 1, 'F,') femalecount
from mytable),
t2 as(
select class,
LEFT(malecount,length(malecount)-1) malecount,
LEFT(femalecount,length(malecount)-1) femalecount
from t)
select t2.class, j.name
from t2
join json_table(
replace(json_array(t2.malecount), ',', '","'),
'$[*]' columns (name varchar(50) path '$')
) j where j.name = 'M'
union all
select t2.class, k.name
from t2
join json_table(
replace(json_array(t2.femalecount), ',', '","'),
'$[*]' columns (name varchar(50) path '$')
) k where k.name = 'F';
| class | name |
|---|---|
| A | M |
| A | M |
| B | M |
| B | M |
| B | M |
| D | M |
| D | M |
| A | F |
| B | F |
| D | F |
| D | F |
CodePudding user response:
You can use Recursive CTE as the following:
with recursive cte as
(
select *,0 as repeats from
(select class, malecount as cnt, 'M' as Gender from Tbl
union
select class, femalecount as cnt, 'F' as Gender from Tbl
) D
union all
select class,cnt,Gender, repeats 1 from cte
where repeats<cnt-1
)
select class, gender from cte
where cnt>0
order by gender desc,class;
See a demo from db-fiddle.
The initial query of the recursive CTE rearranged the input table to be like the following:
| Class | Count | Gender |
|---|---|---|
| A | 2 | M |
| B | 3 | M |
| C | 0 | M |
| D | 2 | M |
| A | 1 | F |
| B | 1 | F |
| C | 3 | F |
| D | 4 | F |
Then the recursive query starts repeating the rows until the condition repeats<cnt-1 is met.
CodePudding user response:
WITH RECURSIVE
-- define maximal amount of rows per class per gender to be generated
cte1 AS ( SELECT MAX(GREATEST(malecount, femalecount)) max_count
FROM test),
-- generate natural numbers till max. amount found above
cte2 AS ( SELECT 1 num
UNION ALL
SELECT num 1
FROM cte1
CROSS JOIN cte2
WHERE cte2.num <= cte1.max_count)
-- generate rows for male
SELECT test.class, 'm' gender
FROM test
JOIN cte2 ON cte2.num <= test.malecount
UNION ALL
-- generate rows for female
SELECT test.class, 'f'
FROM test
JOIN cte2 ON cte2.num <= test.femalecount
-- final sorting
ORDER BY gender DESC, class
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=694dbb214e4c0cd5524800c56a02dc65
CodePudding user response:
You can use the function,the expression:
CASE input_expression WHEN when_expression THEN result_expression [...n ] [ ELSE else_result_expression

