MySQL multiples rows to columns [duplicate] - mysql

This question already has an answer here:
MySQL pivot row into dynamic number of columns
(1 answer)
Closed 5 years ago.
https://i.stack.imgur.com/5Pw2L.png
I have a problem that I would like to solve for pre-processing in MySQL. I have a select that returns multiple rows and columns for an id. I would like to transform the rows into columns for the same id, grouping them as per the attached figure. The column names are not important to me because I only need the values for each id.
+---+---+---+---+-----+---+
| 1 | a | b | c | ... | x |
+---+---+---+---+-----+---+
| 1 | d | e | f | ... | y |
+---+---+---+---+-----+---+
| 2 | g | h | i | ... | z |
+---+---+---+---+-----+---+
| 2 | j | k | l | ... | q |
+---+---+---+---+-----+---+
| 3 | m | n | o | ... | w |
+---+---+---+---+-----+---+
| 3 | p | q | r | ... | t |
+---+---+---+---+-----+---+
+---+---+---+---+-----+---+---+---+---+-----+---+
| 1 | a | b | c | ... | x | d | e | f | ... | y |
+---+---+---+---+-----+---+---+---+---+-----+---+
| 2 | g | h | i | ... | z | j | k | l | ... | q |
+---+---+---+---+-----+---+---+---+---+-----+---+
| 3 | m | n | o | ... | w | p | q | r | ... | t |
+---+---+---+---+-----+---+---+---+---+-----+---+

Unfortunately there is no way to create columns like that on the fly, if you have a variable amount of id repetitions in a table.
You could use group concat to get the same columns into one comma separated column
Select Id, Group_Concat(Col1) As Col1,
Group_Concat(Col2) As Col2,
Group_Concat(Col3) As Col3, ...
Group_Concat(Coln) As Coln
From table
Group By Id

Related

Count records in a MySQL table based for each record of another table

I have two tables in a MySQL database -
table_a:
+----+---------+-------------+-----------------
| id | section | sub_section | ...other_fields
+----+---------+-------------+-----------------
| 1 | A | X |
| 2 | A | Y |
| 3 | A | Z |
| 4 | B | P |
| 5 | B | Q |
| 6 | C | L |
| 7 | C | M |
| 8 | C | N |
| 9 | C | O |
+----+---------+-------------+-----------------
table_b:
+----+-------------+---------+-----------------
| id | sub_section | b_count | ...other_fields
+----+-------------+---------+-----------------
| 1 | X | 1 |
| 2 | Y | 1 |
| 3 | L | 0 |
| 4 | P | 1 |
| 5 | P | 1 |
| 6 | X | 0 |
| 7 | M | 1 |
| 8 | Y | 0 |
| 9 | Q | 1 |
+----+-------------+---------+-----------------
I want to find the count of sub_section in table_b and the sum of b_count from Table B for each distinct section in table_a -
Expected Result:
+---------+--------------------+--------------+
| section | COUNT(sub_section) | SUM(b_count) |
+---------+--------------------+--------------+
| A | 4 | 2 |
| B | 3 | 3 |
| C | 2 | 1 |
+---------+--------------------+--------------+
One way to do this would be to run Count(section) number of queries and then combine the results.
Something like:
SELECT 'A' AS section, COUNT(sub_section), SUM(b_count) FROM table_b WHERE sub_section IN (SELECT DISTINCT sub_section FROM table_a WHERE section='A')
UNION
SELECT 'B' AS section, COUNT(sub_section), SUM(b_count) FROM table_b WHERE sub_section IN (SELECT DISTINCT sub_section FROM table_a WHERE section='B')
UNION
SELECT 'C' AS section, COUNT(sub_section), SUM(b_count) FROM table_b WHERE sub_section IN (SELECT DISTINCT sub_section FROM table_a WHERE section='C');
Is there a better way to do this in a query?
The section list in table_a is dynamic and might change and I do not want to update my query each time the values change.
SELECT t1.section, COUNT(DISTINCT t1.sub_section), SUM(t2.b_count)
FROM table_a t1
LEFT JOIN table_b t2 USING (sub_section)
GROUP BY t1.section;
fiddle

how to group selection from other table as one column in sql?

here is two tables:
a:
+-----+------------------------+
| id | conten |
+-----+------------------------+
| 1 | q. |
| 2 | q. |
| 3 | s. |
| 4 | g |
| 1 | a |
| 2 | a |
+-----+------------------------+
b:
+-----+------------------------+
| id | type |
+-----+------------------------+
| 1 | I. |
| 2 | II. |
| 3 | III. |
| 4 | IV |
| 5 | V |
| 6 | VI |
+-----+------------------------+
Is there a way to select from a and b so that for one id 2, there will be one additional field that groups all content from that id? the select result should be something like this:
+-----+------------------------+-----------+
| id | type | contents |
+-----+------------------------+-----------+
| 2 |I. | q,a |
+-----+------------------------+-----------+
Edited
btw, if there is a way to do it by sqlahcmey, that would be sweet.
SELECT b.id, b.type, IFNULL(GROUP_CONCAT(a.conten), '') AS contents
FROM b
LEFT JOIN a ON a.id = b.id
GROUP BY b.id
See How do I write a group_concat function in sqlalchemy? for how to translate GROUP_CONCAT to SQLAlchemy.

Auto fill other column in mysql table

I have column in mysql table like this:
| Column A | Column B |
| A | |
| B | |
| C | |
| D | |
| E | |
I want to auto fill the other column using rule if A,C,D then fill X and if B, E fill the Y in the column B field.
The result will be like this:
| Column A | Column B |
|----------|----------|
| A | X |
| B | Y |
| C | X |
| D | X |
| E | Y |
Is there are an easy way to do that in MySQL query?
Thank you for help.
UPDATE table
SET B = CASE
WHEN A IN ('A','C','D') THEN 'X'
WHEN A IN ('B','E') THEN 'Y'
END

Return all rows where value appears at least once per group

I have a table listing groups of individuals and contacts assigned to them. The individual can only belong to one group however they can have multiple contacts and vice versa. An example would appear as follows:
+-------+------------+---------+
| Group | Individual | Contact |
+-------+------------+---------+
| A | J | X |
| A | K | Y |
| A | K | Z |
| B | L | X |
| B | M | Y |
| C | N | Y |
| C | N | Z |
| C | O | Z |
| C | P | Z |
+-------+------------+---------+
I am working on a way to pull a report for contacts listing all individuals in a group where they appear against at least one of those individuals. So for the above the output would appear as follows (sorted per contact):
+-------+------------+---------+
| Group | Individual | Contact |
+-------+------------+---------+
| A | J | X |
| A | K | X |
| B | L | X |
| B | M | X |
| A | J | Y |
| A | K | Y |
| B | L | Y |
| B | M | Y |
| C | N | Y |
| C | O | Y |
| C | P | Y |
| A | J | Z |
| A | K | Z |
| C | N | Z |
| C | O | Z |
| C | P | Z |
+-------+------------+---------+
Here we can see that contact X was assigned to individual J (group A) and individual L (group B). Group A has 2 individuals (J and K) and Group B has 2 (L and M) so contact X will see individuals J, K, L and M on their report (everyone in groups A and B).
I'm thinking this will require a derived table grouping by Group and then Contact but i just can't get my head around it. Any help would be appreciated.
Whilst playing around with a few things i think i may have solved this. The key link here is the group, so by creating some derived tables based on groups of contacts and groups of individuals then linking the two i got the following which gives the desired result:
select y.con, y.grp, x.ind from
(select grp, ind from tmp group by grp, ind) as x
join
(select con, grp from tmp group by con, grp) as y on y.grp = x.grp
order by y.con, y.grp, x.ind
Not sure if this is the best way to do it but it works.

MySQL query for row sequences

Is there a way to express the following query in MySQL:
Let a table have types of rows A, B, C, D, E ... Z and each row represents an event. Find the timestamps and ids of all event sequences A, .. , B, ... , C ordered by timestamp so that timestamp(C) - timestamp(A) < Thresh.
For example consider the following table
| type | timestamp | id |
|------+-----------+-----|
| Z | 19:00 | 20 |
| A | 19:01 | 21 |
| | | |
| . | ... | .. |
| | | |
| A | 20:13 | 50 | *
| B | 20:14 | 51 | *
| D | 20:17 | 52 |
| C | 20:19 | 53 | *
| | | |
| . | ... | .. |
| | | |
| A | 22:13 | 80 | *
| D | 22:14 | 81 |
| B | 22:15 | 82 | *
| K | 22:16 | 83 |
| J | 22:17 | 84 |
| C | 22:19 | 85 | *
| | | |
| . | ... | .. |
| | | |
| A | 23:13 | 100 |
| B | 23:14 | 101 |
| C | 23:50 | 102 |
The rows that the query with Thresh = 10mins should yield something along the lines of:
| A_id | B_id | C_id |
|------+------+------|
| 50 | 51 | 53 |
| 80 | 82 | 85 |
See how the last triplet of A, B and C is not present. The time distance between the last A event and the last C event is more that Thresh.
I suspect that the answer would be something along the lines of "MySQL is not the right tool if you need to ask this kind of question". In that case the followup is, which database is a good candidate to handle this kind of task?
Edit: provided an example
I think you can express this using a self join:
SELECT A.id as A_id, B.id as B_id, C.id as C_id
FROM (
SELECT *
FROM the_table
WHERE type = 'A'
) A
JOIN (
SELECT *
FROM the_table
WHERE type = 'B'
) B
JOIN (
SELECT *
FROM the_table
WHERE type = 'C'
) C ON (
(C.timestamp - A.timestamp) < 10 -- threshold here
AND B.timestamp BETWEEN A.timestamp AND C.timestamp
)