根据查询结果在存储过程中动态创建列MySQL

问题描述

我需要通过具有可变列数的存储过程在 MysqL 中创建一个临时表,并将表中的数据插入其中。

这就是它的要点,现在有一点背景知识,我继承了一个系统,其中“联系表单”系统可以根据某些条件具有不同数量的字段......以前的团队能够提出的最好的with 是一个表,每次用户提交表单时,都会为该提交分配一个 ID,它会像这样存储:

ID 身份证件 实例 字段 价值
0001 100001 0000001 姓名
0002 100001 0000001 姓氏 史密斯
0003 100001 0000001 电话 2125551212
0004 100001 0000001 GDPR 真实
0005 100001 0000002 姓名
0006 100001 0000002 姓氏 能源部
0007 100001 0000002 电话 2125551213
0008 100001 0000002 GDPR
0009 100001 0000003 姓名 吉姆
0010 100001 0000003 姓氏 约翰斯
0011 100001 0000003 电话 2125551214
0012 100001 0000003 GDPR 真实
0013 100001 0000004 姓名 杰克
0014 100001 0000004 姓氏 娃娃
0015 100001 0000004 电话 2125551223
0016 100001 0000005 GDPR 真实
0016 100002 0000001 姓名
0017 100002 0000001 姓氏 史密斯
0018 100002 0000001 电话 2125551212
0019 100002 0000001 居民 真实
0020 100002 0000001 GDPR 真实
0021 100002 0000002 姓名
0022 100002 0000002 姓氏 能源部
0023 100002 0000002 电话 2125551213
0024 100002 0000001 居民 真实
0025 100002 0000002 GDPR
0026 100002 0000003 姓名 吉姆
0027 100002 0000003 姓氏 约翰斯
0028 100002 0000003 电话 2125551214
0029 100002 0000001 居民 真实
0030 100002 0000003 GDPR 真实
0031 100002 0000004 姓名 杰克
0032 100002 0000004 姓氏 娃娃
0033 100002 0000004 电话 2125551223
0034 100002 0000001 居民 真实
0035 100002 0000005 GDPR 真实

因此,在此示例中,将有 2 种类型的表单,一种有 4 个字段(姓名、姓氏、电话、gdpr),另一种有 5 个字段(姓名、姓氏、电话、居民、gdpr)。>

因此,当我需要查询填写表单类型 100001 的人员时,我需要查询 IDForm = 100001 的所有记录,然后获取唯一实例,然后遍历每个 IDForm/实例组合以获取列表字段然后再次循环以获取值...

这是一场噩梦。

现在想象一下,大约有 1000 种不同类型的表单,其中一些表单有超过 10K 的提交。

当我必须提取这 10K 份提交报告中的一份时,它需要很长时间。

我正在尝试使用存储过程重写整个过程以加快进程。

我想到的是创建一个存储过程,在其中传递 IDForm,该过程将查询表单的实例,获取所述实例的字段,为每个字段创建一个带有一列的临时表,然后遍历版本的记录集并将信息存储在所述临时表中。 (满嘴)

这是我的尝试,无论如何,第一部分,创建表并创建列...

CREATE DEFINER=`root`@`localhost` PROCEDURE `getEdition`( 
                                IN IDForm VARCHAR(15),IN edition varchar(15)
)
BEGIN

DECLARE n int DEFAULT 0;
DECLARE i int DEFAULT 0;

select count( disTINCT p.field) from wp_fields_form_ddbb as p
        where p.IDForm COLLATE utf8mb4_general_ci = IDForm 
        and p.value COLLATE utf8mb4_general_ci != ''
        order by p.ID asc into n;
DROP TEMPORARY TABLE IF EXISTS tmpTableName;
CREATE TEMPORARY TABLE IF NOT EXISTS tmpTableName ( 
        MyID INT );
set i=0;

while i<n DO
    SET i = i +1;
    SET @edition = select p.field from wp_fields_form_ddbb as p
                where p.IDForm COLLATE utf8mb4_general_ci = IDForm 
                and p.value COLLATE utf8mb4_general_ci != ''
                order by p.ID asc LIMIT i,1;
    SET @ddl = concat('ALTER TABLE ',tmpTableName,' add COLUMN ',/*,*/
        ' varchar(1024);');
        PREPARE STMT FROM @ddl;
        EXECUTE STMT;
    
END WHILE;

END

我什至不确定这是否可行,但如果可行,我将不胜感激各位大师的帮助。

提前致谢!

-奥拉洛

编辑

我终于让它“工作”了,我的意思是,它做了应该做的事情,但仍然需要 foreeeeeever 来处理数据。

我将把代码在这里,以防它对处于(希望不是)类似情况的人有所帮助。

我有 3 个存储过程,一个获取 IDForm 调用一个创建列的存储过程,然后它遍历结果将每个提交插入一行。

干杯!

-奥拉洛


CREATE DEFINER=`root`@`localhost` PROCEDURE `getEdition`(IN `IDForm` VARCHAR(15),IN `edition` VARCHAR(15))
    MODIFIES sql DATA
BEGIN
DECLARE bDone INT;
DECLARE var1 VARCHAR(256);
DECLARE var2 VARCHAR(256);
DECLARE curs CURSOR FOR select disTINCT p.field from wp_fields_form_ddbb as p
        where p.IDForm COLLATE utf8mb4_general_ci = IDForm 
        and p.value COLLATE utf8mb4_general_ci != ''
        order by p.ID asc;
DECLARE cursEditions CURSOR FOR select disTINCT p.edition from wp_fields_form_ddbb as p
        where p.IDForm COLLATE utf8mb4_general_ci = IDForm 
        order by p.ID asc;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET bDone = 1;

DROP TEMPORARY TABLE IF EXISTS tmpTableName;
CREATE TEMPORARY TABLE IF NOT EXISTS tmpTableName ( 
        MyID INT NOT NULL AUTO_INCREMENT PRIMARY KEY);

OPEN curs;
/* CREATE THE COLUMNS */
SET bDone = 0;
main_loop: LOOP
    FETCH curs INTO var1;
    IF bDone THEN
        LEAVE main_loop;
    END IF;
    CALL createColumn('tmpTableName',var1,'varchar(256)');

END LOOP;
CLOSE curs;
/* END CREATE THE COLUMNS */

/* SELECT ALL EDITIONS FROM THIS FORM */
OPEN cursEditions;
SET bDone = 0;
editions_loop: LOOP
    FETCH cursEditions INTO var2;
    IF bDone THEN
        LEAVE editions_loop;
    END IF;
    CALL insertEdition(IDForm,var2);
END LOOP;
CLOSE cursEditions;
/* RETURN THE TABLE */
SELECT * FROM tmpTableName;
END

CREATE DEFINER=`root`@`localhost` PROCEDURE `createColumn`(IN `mytable` VARCHAR(256),IN `colname` VARCHAR(256),IN `mytype` VARCHAR(256))
    NO sql
BEGIN

SET @ddl = concat('alter table ',mytable,' add column (',colname,' ',mytype,')');

PREPARE STMT FROM @ddl;
EXECUTE STMT;

END

delimiter $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `insertEdition`(IN `IDForm` VARCHAR(256),IN `edition` VARCHAR(256))
    MODIFIES sql DATA
BEGIN
DECLARE bDone INT;
DECLARE varField VARCHAR(4096);
DECLARE varValue VARCHAR(4096);
DECLARE varFieldsTmp VARCHAR(4096) DEFAULT '';
DECLARE varValuesTmp VARCHAR(4096) DEFAULT '';
DECLARE cnt int DEFAULT 1;

DECLARE strsql varchar(4026) DEFAULT '';

DECLARE curs CURSOR FOR select p.field,p.value from wp_fields_form_ddbb as p
        where p.IDForm COLLATE utf8mb4_general_ci = IDForm 
        and p.edition COLLATE utf8mb4_general_ci = edition
        and p.value != ''
        order by p.ID asc;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET bDone = 1;

SET strsql = "INSERT INTO tmpTableName (";
OPEN curs;
/* INSERT THE ROW */
SET bDone = 0;

main_loop: LOOP
    FETCH curs INTO varField,varValue;
    IF bDone THEN
        LEAVE main_loop;
    END IF;
    if (!INSTR(varFieldsTmp,varField)) THEN
        if (cnt = 1) THEN
            set varFieldsTmp = CONCAT(varFieldsTmp,varField);
            set varValuesTmp = CONCAT(varValuesTmp,'"',varValue,'"');
        ELSE
            set varFieldsTmp = CONCAT(varFieldsTmp,',"','"');
        END IF;
    END IF;
    SET cnt = cnt + 1;
END LOOP;
CLOSE curs;
SET strsql = CONCAT(strsql,varFieldsTmp,") VALUES (",varValuesTmp,");"); 
PREPARE stmt FROM strsql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

END$$




解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)