MariaDB为ROW类型的变量动态提取列

MariaDB为ROW类型的变量动态提取列,mariadb,mariadb-10.3,Mariadb,Mariadb 10.3,据我在mariadb文档中看到的,您不能直接执行。行类型也没有循环支持。但是,我建议只保留信息_SCHEMA.COLUMNS游标并生成动态选择,如 读循环:循环 将c_列提取到col中; 如果这样做的话 离开read_循环; 如果结束; 将@SQL:=CONCAT'SELECT',col'设置为@colval FROM`',在'tbl'名称中,'WHERE row\u id=',在'u row\u id'中; 从@SQL准备stmt; 使用col执行stmt; 解除分配准备stmt; 设置@cr

据我在mariadb文档中看到的,您不能直接执行。行类型也没有循环支持。但是,我建议只保留信息_SCHEMA.COLUMNS游标并生成动态选择,如

读循环:循环 将c_列提取到col中; 如果这样做的话 离开read_循环; 如果结束; 将@SQL:=CONCAT'SELECT',col'设置为@colval FROM`',在'tbl'名称中,'WHERE row\u id=',在'u row\u id'中; 从@SQL准备stmt; 使用col执行stmt; 解除分配准备stmt; 设置@create_list:=CONCAT@create_list","col","col","col","colval",; 结束循环读取循环; 由于您只拆分一个表行,这就足够了

更新:有额外的信息,它可以这样做。重新思考之后:

set@SQL:=“选择CONCAT”; 读循环:循环 将c_列提取到col中; 如果这样做的话 离开read_循环; 如果结束; SET@SQL:=CONCAT@SQL,“\\”,列,“\\”,“\\”,列,“\\”,”; 结束循环读取循环; set@SQL:=substring@SQL,1,CHAR_LENGTH@SQL - 3; set@SQL:=concat@SQL,进入@create_list FROM`',在` tbl_name',` WHERE row_id=',在` row_id'中; 从@SQL准备stmt; 使用col执行stmt; 解除分配准备stmt;
@谢谢你的支持。我对你的答案做了一些调整,增加了对空字符和转义字符的支持。以下是最后的程序

delimiter $$

CREATE OR REPLACE PROCEDURE  `populate_audit_helper_new3`(
    IN in_db_name VARCHAR(100),
    IN in_tbl_name VARCHAR(100),
    IN in_row_id INT(10)
)
proc: BEGIN
        DECLARE done INT DEFAULT FALSE;
        DECLARE col CHAR(40);
        DECLARE val TEXT(10000);
        DECLARE q TEXT(100000);     

        DECLARE c_columns CURSOR FOR 
            SELECT column_name
            FROM INFORMATION_SCHEMA.COLUMNS
            WHERE TABLE_SCHEMA = in_db_name
                AND table_name = in_tbl_name
            ORDER BY ordinal_position;

        DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

        OPEN c_columns;

        SET q = "";
        SET @val = "";

        read_loop: LOOP
            FETCH c_columns INTO col;

            IF done THEN
                LEAVE read_loop;
            END IF;
            SET q = CONCAT(q, "'", col, "','|', IFNULL(QUOTE(", col, "), ''),'$'");

        END LOOP read_loop;

        SET q = TRIM(TRAILING "," FROM q);

        SET q = CONCAT("CONCAT(", q, ") INTO @val");

        EXECUTE IMMEDIATE CONCAT("SELECT ", q , " FROM ", in_tbl_name, " WHERE row_id = ", in_row_id);

        IF @val = '' THEN
            LEAVE proc;
        END IF;

        SELECT CONCAT("'", REPLACE(@val, "|", "',"), "'") INTO @val;

        SELECT REPLACE(@val, "$", ",") INTO @val;

        SELECT TRIM(TRAILING ",'" FROM @val) INTO @val;

        EXECUTE IMMEDIATE CONCAT("INSERT INTO x1 SET dynamic_cols_l1 = COLUMN_CREATE(", @val, ")" );

        CLOSE c_columns;
 END$$

我不明白,你在读循环中做了什么你得到了专栏名和什么?可以在开始时执行stmt。rec是ROW类型的变量,因此它有多个列。所以我想在循环的每次迭代中一个接一个地获取每个列,列的名称也是一个变量'col',它在每次迭代中都会改变,但rec不会。我试过准备好的语句,它不起作用。错误是rec是游标类型,而不是表。您必须做的是首先在所有列中运行,然后在所有行中运行。这更合理,但我仍然没有得到你想要达到的目标。我从未见过带有SELECt*的光标。你应该用具体的数据示例来解释你试图实现的目标。我删除了mysql标记,因为mysql没有行数据类型或语法类型。该过程在MySQL上不起作用。@nbk我已更新了计划生成的最终查询。这里唯一的问题是,它在每次迭代中插入rec.name的值。相反,我想要rec.col的值,其中col是一个变量。col的值之一是name。不能使用?列名的占位符。在准备语句时,所有标识符表、列等都必须固定。但是,您应该在\u row\u id中参数化,而不是将其连接到SQL字符串中。但你不是。不,我不应该。它是存储过程的参数,所以保持它的静态是更好的主意。感谢您关于列名的注释howeverThis将为每一列运行一个查询,我不想这样做,因为我计划在所有表的每次更新上通过触发器调用此过程。这就是您最初在问题中所做的
delimiter $$

CREATE OR REPLACE PROCEDURE  `populate_audit_helper_new3`(
    IN in_db_name VARCHAR(100),
    IN in_tbl_name VARCHAR(100),
    IN in_row_id INT(10)
)
proc: BEGIN
        DECLARE done INT DEFAULT FALSE;
        DECLARE col CHAR(40);
        DECLARE val TEXT(10000);
        DECLARE q TEXT(100000);     

        DECLARE c_columns CURSOR FOR 
            SELECT column_name
            FROM INFORMATION_SCHEMA.COLUMNS
            WHERE TABLE_SCHEMA = in_db_name
                AND table_name = in_tbl_name
            ORDER BY ordinal_position;

        DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

        OPEN c_columns;

        SET q = "";
        SET @val = "";

        read_loop: LOOP
            FETCH c_columns INTO col;

            IF done THEN
                LEAVE read_loop;
            END IF;
            SET q = CONCAT(q, "'", col, "','|', IFNULL(QUOTE(", col, "), ''),'$'");

        END LOOP read_loop;

        SET q = TRIM(TRAILING "," FROM q);

        SET q = CONCAT("CONCAT(", q, ") INTO @val");

        EXECUTE IMMEDIATE CONCAT("SELECT ", q , " FROM ", in_tbl_name, " WHERE row_id = ", in_row_id);

        IF @val = '' THEN
            LEAVE proc;
        END IF;

        SELECT CONCAT("'", REPLACE(@val, "|", "',"), "'") INTO @val;

        SELECT REPLACE(@val, "$", ",") INTO @val;

        SELECT TRIM(TRAILING ",'" FROM @val) INTO @val;

        EXECUTE IMMEDIATE CONCAT("INSERT INTO x1 SET dynamic_cols_l1 = COLUMN_CREATE(", @val, ")" );

        CLOSE c_columns;
 END$$
delimiter $$

CREATE OR REPLACE PROCEDURE  `populate_audit_helper_new5`(
    IN in_db_name VARCHAR(100),
    IN in_tbl_name VARCHAR(100),
    IN in_row_id INT(10)
)
proc: BEGIN

    DECLARE done INT DEFAULT FALSE;
    DECLARE create_list TEXT(10000);
    DECLARE col TEXT(10000);

    DECLARE c_columns CURSOR FOR 
        SELECT column_name
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_SCHEMA = in_db_name
            AND table_name = in_tbl_name
        ORDER BY ordinal_position;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    OPEN c_columns;

    set @SQL := 'SELECT CONCAT(\'';

    read_loop: LOOP
        FETCH c_columns INTO col;
        IF done THEN
           LEAVE read_loop;
        END IF;
        SET @SQL := CONCAT(@SQL, "\\'", col, "\\'\', \', \', IFNULL(QUOTE(", col, "), \'\'), '\, ");
    END LOOP read_loop;

    set @SQL := substring(@SQL, 1, CHAR_LENGTH(@SQL) - 5);

    set @SQL := concat(@SQL, ') into @create_list FROM `', in_tbl_name, '` WHERE row_id = ', in_row_id);

    PREPARE stmt FROM @SQL;
    execute stmt;
    DEALLOCATE PREPARE stmt;

    EXECUTE IMMEDIATE CONCAT("INSERT INTO x1 SET dynamic_cols_l1 = COLUMN_CREATE(", @create_list, ")" );

    CLOSE c_columns;

END$$