web-dev-qa-db-fra.com

Mysql Faire pivoter les lignes dans des colonnes dynamiques avec un nombre inconnu de colonnes

J'ai une sortie d'une requête comme suit:

bid  | code | amount        |
-----------------------------
2915 | BF   |   -10700.00   |
2915 | YQ   |   -300.00     |
2915 | YR   |   0.00        |
2915 | YM   |   0.00        |
2915 | WO   |   -153.00     |
2915 | IN   |   -329.00     |
2915 | K3   |   0.00        |
2915 | CUTE |   -50.00      |
-----------------------------

J'ai besoin de convertir les valeurs de la colonne code en colonnes individuelles avec le nom de la colonne comme code correspondant et le montant sera la valeur.

bid  | BF       | YQ     | ... | CUTE  |
----------------------------------------
2915 | -10700.00| -300.00| ... | -50.00|

Le problème est que le résultat de ma requête initiale a des codes dynamiques et doit donc générer des colonnes en conséquence.

J'ai déjà essayé la logique suivante mais je n'ai pas pu atteindre l'objectif:

tableau croisé dynamique utilisant mysql , lignes mysql en colonnes , transposition mysql

Tous les liens ci-dessus utilisent une expression ou l'autre pour générer les colonnes.

Mes lignes résultantes d'origine sont le résultat d'une simple sélection sur plusieurs tables jointes et n'ont aucune portée de calcul ou d'expression.

Veuillez suggérer un pointeur ou un indice sur la façon d'y parvenir.

Merci d'avance.

3
Gunnrryy

Procédure:

DELIMITER @@;

DROP PROCEDURE IF EXISTS pivot@@;
CREATE PROCEDURE pivot ( IN schema_name VARCHAR(64) /* database name */
                       , IN table_name VARCHAR(64)  /* table name */
                       , IN id_name VARCHAR(64)     /* row values field name */
                       , IN key_name VARCHAR(64)    /* col values field name, 
                                                           must be char or varchar type 
                                                           and <= 64 chars long */
                       , IN value_name VARCHAR(64)  /* val values field name */
                       )
pivot:BEGIN
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET @error := 1;
    SET @error := 0;
    SELECT character_maximum_length 
        INTO @maxlen 
        FROM information_schema.columns
        WHERE table_schema = schema_name
          AND table_name = table_name
          AND column_name = key_name
          AND data_type IN ('char', 'varchar');
    IF @error OR !@maxlen OR @maxlen IS NULL THEN
        SELECT '@error OR @maxlen=0 OR @maxlen IS NULL', @error, @maxlen;
        LEAVE pivot;
    END IF;
    DROP TEMPORARY TABLE IF EXISTS temp_pivot;
    SET @sql := CONCAT('CREATE TEMPORARY TABLE temp_pivot (key_name VARCHAR(',
                       @maxlen,
                       ')) ENGINE=Memory SELECT DISTINCT `',
                       key_name,
                       '` key_name FROM `',
                       schema_name,
                       '`.`',
                       table_name,
                       '`;');
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DROP PREPARE stmt;
    SELECT GROUP_CONCAT(CONCAT( ', MAX(CASE `',
                                key_name,
                                '` WHEN ''',
                                temp_pivot.key_name,
                                ''' THEN `',
                                value_name,
                                '` END) `',
                                temp_pivot.key_name,
                                '`') SEPARATOR '')
        INTO @sql
        FROM temp_pivot;
    DROP TEMPORARY TABLE temp_pivot;
    SET @sql := CONCAT('SELECT `',
                       id_name,
                       '`',
                       @sql,
                       ' FROM `',
                       schema_name,
                       '`.`',
                       table_name,
                       '` GROUP BY `',
                       id_name,
                       '`;');
    PREPARE stmt FROM @sql;
    EXECUTE stmt;
    DROP PREPARE stmt;
    SET @error := NULL;
    SET @maxlen := NULL;
    SET @sql := NULL;

END pivot@@;

DELIMITER ;

Exemple d'utilisation:

/* USE test; */
DROP TABLE IF EXISTS testtab;
CREATE TABLE testtab(id INT, `key` VARCHAR(16), val INT);
INSERT INTO testtab (id, `key`, val)
VALUES (1,'key1',11),
       (1,'key2',12),
       (1,'key3',13),
       (2,'key1',21),
       (2,'key2',22),
       (2,'key4',24),
       (3,'key1',31),
       (3,'key2',32),
       (3,'key3',33),
       (3,'key4',34);
SELECT * FROM testtab;

CALL pivot('test', 'testtab', 'id', 'key', 'val');

DROP PROCEDURE pivot;
DROP TABLE testtab;
2
Akina