我有以下表格:
用户:
+---------------------------+
| id | e-mail |
+---------------------------+
| 1 | john@domain.com |
+---------------------------+
| 2 | jane@domain.com |
+---------------------------+
| 3 | mark@domain.com |
+---------------------------+
书籍:
+-------------------------------+
| id | user_id | value |
+-------------------------------+
| 1 | 1 | ABC |
+-------------------------------+
| 2 | 1 | HIJ |
+-------------------------------+
| 3 | 2 | XYZ |
+-------------------------------+
我想构建一个查询以获得以下结果:
+-------------------------------------------------------+
| user_id | e-mail | value_1 | value_2 |
+-------------------------------------------------------+
| 1 | john@domain.com | ABC | HIJ |
+-------------------------------------------------------+
| 2 | jane@domain.com | XYZ | NULL |
+-------------------------------------------------------+
| 3 | mark@domain.com | NULL | NULL |
+-------------------------------------------------------+
因此结果列是根据最大书数动态构建的。如果john@domain.com有第三本书,那么结果表应包含3" value"对于jane@domain.com和mark@domain.com,列和此列将为NULL。 MySQL中有这样的事情吗?
答案 0 :(得分:0)
哦,好吧,把它作为挑战。
以下是一个存储过程,它应动态构建所需的SQL并执行它,并返回结果集。似乎可以使用我的表的测试副本(假设您的电子邮件列名称是e_mail)。
DELIMITER ;;
CREATE DEFINER=CURRENT_USER PROCEDURE dynamic_table()
BEGIN
DECLARE max_count_var INT;
DECLARE v_counter INT UNSIGNED DEFAULT 1;
DECLARE base_sql TEXT;
SELECT COUNT(*) AS max_count FROM Books GROUP BY user_id ORDER BY max_count DESC LIMIT 1 INTO max_count_var;
SET base_sql = 'SELECT a.id AS user_id, a.e_mail ';
WHILE v_counter <= max_count_var DO
SET base_sql = CONCAT(base_sql, ',MAX(IF(cnt=', v_counter, ', `value`, NULL)) AS value_', v_counter);
SET v_counter = v_counter + 1;
END WHILE;
SET base_sql = CONCAT(@s, ' FROM Users a LEFT OUTER JOIN ( SELECT id, user_id, value, @cnt:=IF(@user_id = user_id, @cnt + 1, 1) AS cnt, @user_id := user_id FROM Books CROSS JOIN (SELECT @cnt:=1, @user_id:=0) sub0 ORDER BY user_id, id ) b ON a.id = b.user_id GROUP BY a.id, a.e_mail ORDER BY a.id');
SET @s = base_sql;
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END;;
DELIMITER ;