Originality: We sometimes encounter this kind of requirement when we are working on a project.
hobby with name Zhang San needs to be merged as follows:
Of course, you can also merge hobby into one column through mysql's group_comcat. That's very simple. I won't introduce it here.
Build tables first, insert data
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for t_user -- ---------------------------- DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `age` int(5) NULL DEFAULT NULL, `hobby` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of t_user -- ---------------------------- INSERT INTO `t_user` VALUES (1, 'Zhang San', 18, 'read'); INSERT INTO `t_user` VALUES (2, 'Zhang San', 18, 'Play games'); INSERT INTO `t_user` VALUES (3, 'Zhang San', 18, 'Writing code');
Rewrite SQL
SELECT GROUP_CONCAT( CONCAT( '(select hobby from t_user where id = ', id, ') AS ', CONCAT('hobby',id) ) ) INTO @sql FROM t_user; SET @sql = CONCAT('select name,age, ', @sql, ' from t_user GROUP BY name'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
The above is actually equivalent to
select name,age,(select hobby from t_user where id = 1) as hobby1,(select hobby from t_user where id = 2) as hobby2, (select hobby from t_user where id = 3) as hobby3 from t_user GROUP BY name;
results of enforcement
Above is the case of Zhang Sanshi, the only name in the table.
And when there are multiple users in the table
Building tables and interpolating data
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for t_user -- ---------------------------- DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `age` int(5) NULL DEFAULT NULL, `hobby` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of t_user -- ---------------------------- INSERT INTO `t_user` VALUES (1, 'Zhang San', 18, 'read'); INSERT INTO `t_user` VALUES (2, 'Zhang San', 18, 'Play games'); INSERT INTO `t_user` VALUES (3, 'Zhang San', 18, 'Writing code'); INSERT INTO `t_user` VALUES (4, 'Wang Wu', 20, 'Having dinner'); INSERT INTO `t_user` VALUES (5, 'Wang Wu', 20, 'Sleep'); INSERT INTO `t_user` VALUES (6, 'Wang Wu', 20, 'Doudou');
Because if you want to query Wang Wu's hobby from 1, and Mysql does not have rownum like Oracle, you create rownum through sql
-- Set up rownum SELECT @rownum:=@rownum+1 AS rownum, t_user.* FROM (SELECT @rownum:=0) r, t_user where name='Wang Wu';
Then query
set @name = 'Wang Wu'; SELECT GROUP_CONCAT(DISTINCT CONCAT( '(select hobby from (SELECT @rownum:=@rownum+1 AS rownum, t_user.* FROM (SELECT @rownum:=0) r, t_user where name="',@name,'") t where t.rownum = ', t.rownum, ') AS ', CONCAT('hobby',rownum) ) ) INTO @sql FROM (SELECT @rownum:=@rownum+1 AS rownum, t_user.* FROM (SELECT @rownum:=0) r, t_user where name=@name) t; SET @sql = CONCAT('select distinct name,age, ', @sql, ' from t_user where name ="',@name,'"'); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
results of enforcement
Finish sharing
Here's how Mysql can be dynamically implemented by row-column transformation.https://blog.csdn.net/xeseo/article/details/24364921
How to dynamically generate PivotTable of Title under MYSQL.
First, use the following script to generate a table called "properties" that contains several attributes.
- CREATE TABLE properties (
- id INT(11) NOT NULL AUTO_INCREMENT,
- item_id INT(11) DEFAULT NULL,
- property_name VARCHAR(255) DEFAULT NULL,
- value VARCHAR(255) DEFAULT NULL,
- PRIMARY KEY (id)
- );
- INSERT INTO properties VALUES
- (1, 1, 'color', 'blue'),
- (2, 1, 'size', 'large'),
- (3, 1, 'weight', 65),
- (4, 2, 'color', 'orange'),
- (5, 2, 'weight', 57),
- (6, 2, 'size', 'large'),
- (7, 3, 'size', 'small'),
- (8, 3, 'color', 'red'),
- (9, 3, 'weight', 12),
- (10, 4, 'color', 'violet'),
- (11, 4, 'size', 'medium'),
- (12, 4, 'weight', 34),
- (13, 5, 'color', 'green'),
- (14, 5, 'weight', 10);
Then we want to generate the following report based on the original data.
|
=> |
|
As we all know, MySql has no automatic table conversion function. Of course, we can use some additional programs or tools to connect MySQL to perform data conversion. But here, we will discuss how to write a query manually to achieve data conversion. The query can be implemented as follows:
- SELECT
- item_id,
- MAX(case when property_name = 'color' then VALUE else NULL END) AS color,
- MAX(CASE property_name WHEN 'weight' THEN value ELSE null END) AS weight,
- MAX(IF(property_name = 'size', value, NULL)) AS size,
- ...
- ...
- FROM
- properties
- GROUP BY
- item_id;
Obviously, we have defined any'property_name', such as'color','size'. If the type of attribute is unchanged, the query will be fine. But what if the field'property_name'changes frequently and may add a new one? Can you only change this query statement every time? In this case, you can use dynamic generation of query statements - read all the values of the field'property_name'in the table, and dynamically create a query statement based on that value.
The implementation of dynamically generating queries is as follows:
- SET @sql = NULL;
- SELECT
- GROUP_CONCAT(DISTINCT
- CONCAT(
- 'MAX(IF(property_name = ''',
- property_name,
- ''', value, NULL)) AS ',
- property_name
- )
- ) INTO @sql
- FROM properties;
- SET @sql = CONCAT('SELECT item_id, ', @sql, ' FROM properties GROUP BY item_id');
Executing this statement generates the following query statement (the following format has been adjusted for easy reading):
- SELECT
- item_id,
- MAX(IF(property_name = 'color', value, NULL)) AS color,
- MAX(IF(property_name = 'size', value, NULL)) AS size,
- MAX(IF(property_name = 'weight', value, NULL)) AS weight
- FROM
- properties
- GROUP BY
- item_id
Be careful:
MySQL uses system variables for GROUP_CONCAT results group_concat_max_len The default value is 1024. So, if your table has many columns, it's better to set the value higher.
- SET @@group_concat_max_len = 5000;
- SELECT GROUP_CONCAT(column_name) FROM table;
After executing the dynamically generated statement, the query statement is written into the variable @sql. Now we can use prepared state to execute the statement:
- PREPARE stmt FROM @sql;
- EXECUTE stmt;
- DEALLOCATE PREPARE stmt;
Result:
-
-
+---------+--------+--------+--------+
-
| item_id | color | size | weight |
-
+---------+--------+--------+--------+
-
| 1 | blue | large | 65 |
-
| 2 | orange | large | 57 |
-
| 3 | red | small | 12 |
-
| 4 | violet | medium | 34 |
-
| 5 | green | NULL | 10 |
-
+---------+--------+--------+--------+