how to combine multiple rows into one row? - mysql

My table:
id val
--------
a 1
a 2
a 3
b 7
b 8
b 9
b 10
What i want to get is:
id val1 val2 val3 val4
--------------------------
a 1 2 3 null
b 7 8 9 10
Is there any simple way for this?

If you are using MySQL 8+, then ROW_NUMBER combined with pivoting logic provides one way:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY val) rn
FROM yourTable
)
SELECT
id,
MAX(CASE WHEN rn = 1 THEN val END) AS val1,
MAX(CASE WHEN rn = 2 THEN val END) AS val2,
MAX(CASE WHEN rn = 3 THEN val END) AS val3,
MAX(CASE WHEN rn = 4 THEN val END) AS val4
FROM cte
GROUP BY
id;

Not quite the same output, but worth considering:
SELECT id, GROUP_CONCAT(val)
FROM tbl GROUP BY id;

Related

SQL : Summing the values in a column till first non zero values appears in other column?

Suppose, I have a table t1 looking like
id
value1
value2
wk_id
1
2
0
1
1
1
1
2
1
3
0
3
2
2
1
2
2
2
0
3
3
1
0
2
3
2
0
4
3
3
0
5
And I want to sum up the value1 till non-zero value appears on the value2 for first time.
End product must look like this:
id
value1
1
2
2
0
3
6
How to perform this in SQL?
If your MySQL version support window function you can try to use SUM window function with condition aggregate function be a flag to represent your logic (till non-zero value appears on the value2 for first time)
Then do condition aggregate function again.
Query #1
SELECT id,
SUM(CASE WHEN flag = 0 THEN value1 ELSE 0 END) value1
FROM (
SELECT *,
SUM(CASE WHEN value2 = 1 THEN -1 ELSE 0 END) OVER(PARTITION BY ID ORDER BY wk_id) flag
FROM T
) t1
GROUP BY id;
id
value1
1
2
2
0
3
6
View on DB Fiddle
WITH cte AS (
SELECT *,
CASE WHEN SUM(value2) OVER (partition by id ORDER BY wk_id) = 0
THEN SUM(value1) OVER (partition by id ORDER BY wk_id)
ELSE 0
END sum_value1
FROM test
ORDER BY id, wk_id
)
SELECT id, MAX(sum_value1) sum_value1
FROM cte
GROUP BY id;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=0fcdca008e4a821f952de4d608434bcf
One option is a NOT EXISTS clause, looking for the stop row (the first row with value2 = 1).
select id, sum(value1)
from mytable
where not exists
(
select null
from mytable stoprow
where stoprow.id = mytable.id
and stoprow.wk_id <= mytable.wk_id
and stoprow.value2 = 1
)
group by id
order by id;
Aggregating on a calculated rolling total of value2 can also be done via a self-join.
select id
, sum(if(roll_tot_value2=0,value1,0)) as total
from
(
select t1a.id, t1a.wk_id, t1a.value1
, sum(t1b.value2) as roll_tot_value2
from t1 as t1a
join t1 as t1b
on t1b.id = t1a.id
and t1b.wk_id <= t1a.wk_id
group by t1a.id, t1a.wk_id, t1a.value1
) q
group by id;
id
total
1
2
2
0
3
6
Test on db<>fiddle here
You can use a subquery:
select t.id, coalesce(
(select sum(t2.value1) from t1 t2 where t2.value2 = 0 and t2.id = t.id
and (not exists (select 1 from t1 t3 where t3.value2 = 1 and t3.id = t.id)
or t2.wk_id < (select min(t4.wk_id) from t1 t4 where t4.id = t.id and t4.value2 = 1))), 0)
from t1 t group by t.id

How to copy from Parent table to Child Table with 1 column dividing into 3 different column

I have a table column like following
Name
a
b
c
d
e
f
Now I want to Divide this column into 3 columns like as
Name1 | Name2 | Name3
a | c | f
b | d | e
How will the SQL Query for this?
On MySQL 8+, you could use ROW_NUMBER for this purpose:
WITH cte AS (
SELECT Name, ROW_NUMBER() OVER (ORDER BY Name) - 1 rn
FROM yourTable
)
SELECT
MAX(CASE WHEN FLOOR(rn / 2) = 0 THEN Name END) AS Name1,
MAX(CASE WHEN FLOOR(rn / 2) = 1 THEN Name END) AS Name1,
MAX(CASE WHEN FLOOR(rn / 2) = 2 THEN Name END) AS Name3
FROM cte
GROUP BY
rn % 2
ORDER BY
rn % 2;
Demo
This approach has an advantage over a union in that it can easily be extended to support more rows and columns as you need.

How to get count of each value against unique id in Mysql

I Have below mentioned table:
Where Val column has 3 distinct value a,b & c.
ID Val
1 a
1 a
1 b
2 b
2 c
2 c
3 c
I want to get count of unique ids and count of ids for respective Val value (i.e a,b & c).
I am using query like this but it helps me to identify count for a single Val value at a time.
SELECT ID,COUNT(*)
FROM table1
WHERE Val='c' GROUP BY ID;
Required output:
ID count a b c
1 3 2 1 0
2 3 0 1 2
3 1 0 0 1
You can use group by and sum the count when val is equal to a,b or c. See below:
select id,
count(*) as `count`,
sum(case when val = 'a' then 1 else 0 end) as a,
sum(case when val = 'b' then 1 else 0 end) as b,
sum(case when val = 'c' then 1 else 0 end) as c
from yourTable
group by id;
Just use conditional aggregation:
select id, count(*), sum(val = 'a') as a, sum(val = 'b') as b, sum(val = 'c') as c
from table1
group by id;

How to group repeated row values in a column

t_no name value
1 a 45
1 b 23
1 c 5
1 a 12
1 b 99
1 c 6
I need to show my above table as
no name value1 value2
1 a 45 12
1 b 23 99
1 c 5 6
You can't create dynamic columns in mysql alone, either in scripting language, or you can use group_concat to have them in one column:
SELECT to_no, name, GROUP_CONCAT(value)
FROM table GROUP BY to_no, name
result:
no name value
1 a 45,12
1 b 23,99
1 c 5,6
MySQL does not have a pivot function, but you can use an aggregate function with a CASE expression. Since you have multiple values for each t_no and name, then you could use user defined variables to assign a row number to each group of values:
select t_no, name,
max(case when rn=1 then value end) value1,
max(case when rn=2 then value end) value2
from
(
select t_no, name, value,
#rn:=case when #prev=t_no and #c=name then #rn else 0 end +1 rn,
#prev:=t_no,
#c:=name
from yourtable
cross join (select #rn:=0, #prev:=0, #c:=null) c
order by t_no, name
) d
group by t_no, name
order by t_no, name;
See SQL Fiddle with Demo

Minimum values from the table

I need the minimum value from 3 coloumn and corresponding name for the min value,
like this..
Name val1 val2 val3
a 12 5 4
b 10 9 1
c 7 11 5
d 13 8 2
output:
Name MIN
b 1
I wrote query to find minimum value :
select MIN(less)
from (
select case
when val1<=val2 and val1<=val3 then val1
when val2<=val1 and val2<=val3 then val2
when val3<=val1 and val3<=val2 then val3 end as less from table) as low
I used alises,i want to display the corresponding name from the table...plz tell me the query...
You can do it using the UNION operator to convert the 3 column table into a single table with 1 column.
SELECT TOP 1 Name, Val AS Min
FROM (
SELECT Name, val1 AS Val
FROM table
UNION
SELECT Name, val2 AS Val
FROM table
UNION
SELECT Name, val3 AS Val
FROM table
) AS sub_query
ORDER BY Val ASC
This solution has the added advantage that it is easier to maintain if the number of columns increases.
Most Concise
SELECT top 1 Name,col,val
FROM T
UNPIVOT ( val for col in (val1,val2,val3)) unpvt
ORDER BY val
Most Efficient (assuming these columns are indexed)
;WITH cte(Name, col, val) AS
(
SELECT TOP 1 Name, 'val1', val1
FROM T
ORDER BY val1
UNION ALL
SELECT TOP 1 Name, 'val2', val2
FROM T
ORDER BY val2
UNION ALL
SELECT TOP 1 Name, 'val3', val3
FROM T
ORDER BY val3
)
SELECT TOP 1 Name, col, val
FROM cte
ORDER BY val