mysql query with grouping and concatenate rows into one row - mysql

I have the table in mysql with records:
I've written the sql query:
SELECT COUNT(*) AS number_of_contacts, channel_id, direction
FROM cic_case_contacts
WHERE case_id = 328678
GROUP BY channel_id, direction
and the result looks like:
I would like to obtain something like below(based on above data):
I was trying to obtaining that with sql query by using my_sql_function GROUP_CONCAT but it dosen't work:
SELECT COUNT(*) AS number_of_contacts, channel_id, GROUP_CONCAT(direction SEPARATOR ', ') AS directions
FROM cic_case_contacts
WHERE case_id = 328678 AND id IN(149196, 149195, 149194, 149193, 149192) AND `office_id` = 10
GROUP BY channel_id
ORDER BY channel_id
I would be greateful for help.

You can use GROUP_CONCAT on a sub query as follows:
SELECT channelid, GROUP_CONCAT(
CONCAT(direction, ': ', c)
ORDER BY direction
SEPARATOR ', '
) AS summary
FROM (
SELECT channelid, direction, COUNT(*) AS c
FROM t
GROUP BY channelid, direction
) x
GROUP BY channelid
Or simply use conditional aggregation:
SELECT channelid, CONCAT_WS(', ',
CONCAT('in: ', COUNT(CASE WHEN direction = 'in' THEN 1 END)),
CONCAT('out: ', COUNT(CASE WHEN direction = 'out' THEN 1 END))
) AS summary
FROM t
GROUP BY channelid

You can use Concat in MySQL
drop table if exists Demo;
CREATE TABLE Demo
(
ID INT AUTO_INCREMENT PRIMARY KEY,
channelid int,
Name VARCHAR(20)
);
INSERT INTO Demo(channelid, Name)VALUES
(1,'in'),(1,'out'),(1,'in'),(1,'out'),(2,'in'),(2,'out'),(1,'in'),(1,'out'),(1,'in'),(2,'out'),(2,'in'),(2,'out'),(2,'in'),(1,'in'),(1,'in');
Query
SELECT SQL_CALC_FOUND_ROWS
channelid,
group_concat ( concat(name,':',channelid) )
FROM Demo
group by channelid;
SELECT FOUND_ROWS();
See the results the the fiddle

Please find below working code as per your requirement :
select tb.channelid, group_concat
(
concat(tb.name,':',tb.MyCol2Count)
) as v1
from
(Select tbl.channelid,tbl.name,(LENGTH(tbl.val) - LENGTH(REPLACE(tbl.val,",","")) + 1) AS MyCol2Count
from
(SELECT channelid, group_concat
(
concat(name,':',channelid)
) as val,name
FROM Demo
group by channelid,Name) as tbl) as tb group by tb.channelid
You can check on below screenshot : http://springinfosoft.com/code/Groupby_code.png

Related

how to convert json data to specific alias and with comma seperated values in mysql

i have one table of product_attributes that is below:-
id attr_details
1 {"Manufacturer":"Lennovo","Warranty":"6 months"}
2 {"Manufacturer":"HP","Warranty":"6 months"}
3 {"Manufacturer":"DEll","Warranty":"12 months","Type":"DDR"}
4 {"Size":"36","Color":"Red","Material":"Fabric"}
My attr_details column data stored in json. My expected Output is like below:-
label values
Manufacturer Lennovo,HP,DEll
Warranty 6 months,12 months
Type DDR
Size 36
Color Red
Material Fabric
The attr_details json is not predefined it can be any userdefined input json. So can anyone help me how to achieve this output.
Try this:
SET #sql = NULL;
SELECT GROUP_CONCAT(CONCAT("SELECT '",colname,":' AS 'Label', GROUP_CONCAT(val)
FROM (SELECT JSON_UNQUOTE(JSON_EXTRACT(attr_details,'$.", colname,"')) AS 'val'
FROM mytable /*you can add the WHERE condition in here*/ GROUP BY val) A
GROUP BY Label") SEPARATOR " UNION ")
INTO #sql
FROM
(WITH RECURSIVE data AS (
SELECT attr_details,JSON_VALUE(JSON_KEYS(attr_details), '$[0]') AS colname, 0 AS idx FROM mytable
UNION
SELECT attr_details,JSON_VALUE(JSON_KEYS(attr_details), CONCAT('$[', d.idx + 1, ']'))
AS colname, d.idx + 1 AS idx FROM data AS d
WHERE d.idx < JSON_LENGTH(JSON_KEYS(attr_details)) - 1
) SELECT colname
FROM data
GROUP BY colname) V;
PREPARE stmt FROM #sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
This is the closest I can get. The WITH RECURSIVE .. part I use to list out all the keys as single row value each. That one I was referring to a query from the comment section in the MariaDB documentation. Then I construct the query using combination of CONCAT + GROUP_CONCAT. Lastly, I used prepared statement to execute the query. Here is the final output of #sql:
SELECT 'Color:' AS 'Label', GROUP_CONCAT(val)
FROM (
SELECT JSON_UNQUOTE(JSON_EXTRACT(attr_details,'$.Color')) AS 'val'
FROM mytable GROUP BY val) A
GROUP BY Label UNION
SELECT 'Manufacturer:' AS 'Label', GROUP_CONCAT(val)
FROM (
SELECT JSON_UNQUOTE(JSON_EXTRACT(attr_details,'$.Manufacturer')) AS 'val'
FROM mytable GROUP BY val) A
GROUP BY Label UNION
SELECT 'Material:' AS 'Label', GROUP_CONCAT(val)
FROM (
SELECT JSON_UNQUOTE(JSON_EXTRACT(attr_details,'$.Material')) AS 'val'
FROM mytable GROUP BY val) A
GROUP BY Label UNION
SELECT 'Size:' AS 'Label', GROUP_CONCAT(val)
FROM (
SELECT JSON_UNQUOTE(JSON_EXTRACT(attr_details,'$.Size')) AS 'val'
FROM mytable GROUP BY val) A
GROUP BY Label UNION
SELECT 'Type:' AS 'Label', GROUP_CONCAT(val)
FROM (
SELECT JSON_UNQUOTE(JSON_EXTRACT(attr_details,'$.Type')) AS 'val'
FROM mytable GROUP BY val) A
GROUP BY Label UNION
SELECT 'Warranty:' AS 'Label', GROUP_CONCAT(val)
FROM (
SELECT JSON_UNQUOTE(JSON_EXTRACT(attr_details,'$.Warranty')) AS 'val'
FROM mytable GROUP BY val) A
GROUP BY Label
Demo fiddle
WITH cte AS (
SELECT DISTINCT jsontable.label
FROM test
CROSS JOIN JSON_TABLE( JSON_KEYS(test.attr_details),
'$[*]' COLUMNS ( label VARCHAR(255) PATH '$' )) jsontable
)
SELECT cte.label, GROUP_CONCAT(DISTINCT JSON_EXTRACT(test.attr_details, CONCAT('$.', cte.label))) `values`
FROM cte
CROSS JOIN test
GROUP BY label;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=ab92deb1dc20eef0f090f841ce2c6cd0

Can I concatenate multiple MySQL Column into One Column?

Good day i would like to ask if this is possible in MySQL
SELECT id,label,name,age,sex FROM table LIMIT 3
Output
[row1] id,label,name,age,sex
[row2] id,label,name,age,sex
[row3] id,label,name,age,sex
My Output Needed
[row1] id
[row2] label
[row3] name
[row4] age
[row5] sex
[row6] id
[row7] label
[row8] name
[row9] age
[row10] sex
[row11] id
[row12] label
[row13] name
[row14] age
[row15] sex
You can do something like this:
SELECT * FROM
((SELECT id AS id1, 1 AS rownum, 'id' AS colname, id AS Data_value FROM mytable LIMIT 3)
UNION ALL
(SELECT id, 2, 'label', label FROM mytable LIMIT 3)
UNION ALL
(SELECT id, 3, 'name', name FROM mytable LIMIT 3)
UNION ALL
(SELECT id, 4, 'age', age FROM mytable LIMIT 3)
UNION ALL
(SELECT id, 5, 'sex', sex FROM mytable LIMIT 3)) A
ORDER BY id1, rownum
Here's a fiddle: https://www.db-fiddle.com/f/dvg6x1vBg6H5bDNp9VZxQa/4
I've added 3 additional column id AS id1, rownum and colname. The first two additional column is used for ORDER BY at the outer query. If you don't want to see the additional column, you can just type SELECT Data_value FROM ... at the outer query.
You can use group_concat() to aggregate rows by string concatenation. For the LIMIT to work you then need to use a derived table. But you should be careful with a LIMIT without an ORDER BY. As the order of a query result can be random unless an explicit ORDER BY is issued, you may get different results each time you run the query.
SELECT group_concat(id,
'\n',
label,
'\n',
name,
'\n',
age,
'\n',
sex
SEPARATOR '\n')
FROM (SELECT id,
label,
name,
age,
sex
FROM elbat
LIMIT 3) x;
If you just want to concatenate the columns but keep the rows just use concat().
SELECT concat(id,
'\n',
label,
'\n',
name,
'\n',
age,
'\n',
sex)
FROM elbat
LIMIT 3;
yes,you can use union all like below :
SELECT id FROM table LIMIT 3
union all
SELECT label FROM table LIMIT 3
union all
SELECT name FROM table LIMIT 3
union all
SELECT age FROM table LIMIT 3
union all
SELECT sex FROM table LIMIT 3
That what you looking is to Unpivot data. For more info about pivot and unpivot you can check here.
http://archive.oreilly.com/oreillyschool/courses/dba1/dba110.html
Unfortunately there is no easy way to unpivot in mysql.
The below script will work for MySQL 8.0
set #rowNum :=0;
set #string :=(
select group_concat(id,',',label,',',name,',',age,',',sex separator ',')
from (
select id, label, name, age, sex from mytable limit 3
) x
);
with recursive
R1 as ( select #string as items),
R2 as ( select 1 as n
union
select n + 1 from R2, R1
where n <= length(items) - length(replace(items, ',', '')))
select distinct #rowNum := #rowNum+1 as rowNum, substring_index(substring_index(items, ',', n), ',', -1) output from R2, R1;

Mysql how to search the result of a select statement

I have the following query.
SELECT
horse_name AS Horse_Name,
GROUP_CONCAT(
placing_numerical
ORDER BY
race_date
DESC SEPARATOR
', '
) Place
FROM
results
GROUP BY
Horse_Name
I would then like to search the results of Place with a LIKE '%xyz%' query. Is there a way to do this in the same query?
Thanks for lokking.
One way is with a subquery
select *
from (
SELECT horse_name AS Horse_Name,
GROUP_CONCAT( placing_numerical ORDER BY race_date DESC SEPARATOR ', ' ) Place
) tbl
Where tbl.Place like '%xyz%'
SELECT
*
FROM
(
SELECT
horse_name AS Horse_Name,
GROUP_CONCAT(
placing_numerical
ORDER BY
race_date
DESC SEPARATOR
', '
) Place
FROM
results
GROUP BY
Horse_Name
) tbl
WHERE
tbl.Place LIKE '%xyz%'
Thanks to Jacob, this works a treat and I now understand more about subqueries.

How many different ways are there to get the second row in a SQL search?

Let's say I was looking for the second most highest record.
Sample Table:
CREATE TABLE `my_table` (
`id` int(2) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`value` int(10),
PRIMARY KEY (`id`)
);
INSERT INTO `my_table` (`id`, `name`, `value`) VALUES (NULL, 'foo', '200'), (NULL, 'bar', '100'), (NULL, 'baz', '0'), (NULL, 'quux', '300');
The second highest value is foo. How many ways can you get this result?
The obvious example is:
SELECT name FROM my_table ORDER BY value DESC LIMIT 1 OFFSET 1;
Can you think of other examples?
I was trying this one, but LIMIT & IN/ALL/ANY/SOME subquery is not supported.
SELECT name FROM my_table WHERE value IN (
SELECT MIN(value) FROM my_table ORDER BY value DESC LIMIT 1
) LIMIT 1;
Eduardo's solution in standard SQL
select *
from (
select id,
name,
value,
row_number() over (order by value) as rn
from my_table t
) t
where rn = 1 -- can pick any row using this
This works on any modern DBMS except MySQL. This solution is usually faster than solutions using sub-selects. It also can easily return the 2nd, 3rd, ... row (again this is achievable with Eduardo's solution as well).
It can also be adjusted to count by groups (adding a partition by) so the "greatest-n-per-group" problem can be solved with the same pattern.
Here is a SQLFiddle to play around with: http://sqlfiddle.com/#!12/286d0/1
This only works for exactly the second highest:
SELECT * FROM my_table two
WHERE EXISTS (
SELECT * FROM my_table one
WHERE one.value > two.value
AND NOT EXISTS (
SELECT * FROM my_table zero
WHERE zero.value > one.value
)
)
LIMIT 1
;
This one emulates a window function rank() for platforms that don't have them. It can also be adapted for ranks <> 2 by altering one constant:
SELECT one.*
-- , 1+COALESCE(agg.rnk,0) AS rnk
FROM my_table one
LEFT JOIN (
SELECT one.id , COUNT(*) AS rnk
FROM my_table one
JOIN my_table cnt ON cnt.value > one.value
GROUP BY one.id
) agg ON agg.id = one.id
WHERE agg.rnk=1 -- the aggregate starts counting at zero
;
Both solutions need functional self-joins (I don't know if mysql allows them, IIRC it only disallows them if the table is the target for updates or deletes)
The below one does not need window functions, but uses a recursive query to enumerate the rankings:
WITH RECURSIVE agg AS (
SELECT one.id
, one.value
, 1 AS rnk
FROM my_table one
WHERE NOT EXISTS (
SELECT * FROM my_table zero
WHERE zero.value > one.value
)
UNION ALL
SELECT two.id
, two.value
, agg.rnk+1 AS rnk
FROM my_table two
JOIN agg ON two.value < agg.value
WHERE NOT EXISTS (
SELECT * FROM my_table nx
WHERE nx.value > two.value
AND nx.value < agg.value
)
)
SELECT * FROM agg
WHERE rnk = 2
;
(the recursive query will not work in mysql, obviously)
You can use inline initialization like this:
select * from (
select id,
name,
value,
#curRank := #curRank + 1 AS rank
from my_table t, (SELECT #curRank := 0) r
order by value desc
) tb
where tb.rank = 2
SELECT name
FROM my_table
WHERE value < (SELECT max(value) FROM my_table)
ORDER BY value DESC
LIMIT 1
SELECT name
FROM my_table
WHERE value = (
SELECT min(r.value)
FROM (
SELECT name, value
FROM my_table
ORDER BY value DESC
LIMIT 2
) r
)
LIMIT 1

Mysql group_concat with sums also inside

I have a table of different attributes I want to sum, and then group concatenate them into a JSON string to make it easier to send over network. Here's a simplified table:
t1
type amount
'atr1' 10
'atr2' 10
'atr1' 17
'atr3' 20
'atr3' 4
I tried something like
select concat('{',
group_concat(
(select concat('"', type, '":', sum(amount)) from t1 group by type)
),
'}')
but failed.
I want to end up with '{"atr1":27,"atr2":10,"atr3":24}'
Try this query -
SELECT CONCAT('{', GROUP_CONCAT(c1), '}') FROM (
SELECT CONCAT('"', type, '":', SUM(amount)) c1 FROM t1 GROUP BY type
) t
something like
select
group_concat(concat('"', type, '":', TheSum))
FROM
(
SELECT SUM(amount) AS TheSum,type
FROM t1
GROUP BY type
) T