Mysql
 sql >> Base de données >  >> RDS >> Mysql

Sélectionnez les lignes MYSQL mais les lignes en colonnes et les colonnes en lignes

Avec une colonne fixe et connue, voici comment procéder (j'ai pris la liberté de nommer la table "notes") :

Idée générale :

Pour créer une union de différentes requêtes et l'exécuter.

Comme vous avez besoin de données réelles comme en-têtes de colonne, la première partie de l'union ressemblera à :

SELECT 'id', '1', '2', ....

Cette requête à elle seule dupliquera le résultat, nous devons donc dire à MySQL que nous devons avoir 0 lignes en ajoutant LIMIT 0, 0 .

Notre première ligne de l'union contiendra 'Name' , ainsi que toutes les données de la colonne "Nom" de la table. Pour obtenir cette ligne, nous avons besoin d'une requête comme :

SELECT 'Name',
    (SELECT Name FROM grades LIMIT 0, 1),
    (SELECT Name FROM grades LIMIT 1, 1),
    (SELECT Name FROM grades LIMIT 2, 1),
    ...

En utilisant la même logique, notre deuxième ligne ressemblera à :

SELECT 'Marks',
    (SELECT Marks FROM grades LIMIT 0, 1),
    (SELECT Marks FROM grades LIMIT 1, 1),
    (SELECT Marks FROM grades LIMIT 2, 1),
    ...

Obtenir l'en-tête :

Nous devons produire une ligne à partir de MySQL comme :

SELECT 'id', '1', '2', ... LIMIT 0, 0;

Pour obtenir cette ligne, nous utiliserons CONCAT() et GROUP_CONCAT() fonctions :

SELECT 'id', 
    (SELECT GROUP_CONCAT(CONCAT(' \'', id, '\'')) FROM grades)
LIMIT 0, 0;

et nous allons stocker cette ligne dans une nouvelle variable :

SET @header = CONCAT('SELECT \'id\', ',
    (SELECT GROUP_CONCAT(CONCAT(' \'', id, '\'')) FROM grades),
    ' LIMIT 0, 0');

Création des lignes :

Nous devons créer deux requêtes comme celle-ci :

SELECT 'Name',
    (SELECT Name FROM grades LIMIT 0, 1),
    (SELECT Name FROM grades LIMIT 1, 1),
    (SELECT Name FROM grades LIMIT 2, 1),
    ...

Comme nous ne savons pas à l'avance combien de lignes il y a dans notre table d'origine, nous utiliserons des variables pour générer les différents LIMIT x, 1 déclarations. Ils peuvent être produits à l'aide des éléments suivants :

SET @a = -1;
SELECT @a:[email protected]+1 FROM grades;

À l'aide de cet extrait, nous pouvons créer nos sous-requêtes :

SELECT GROUP_CONCAT(
    CONCAT(' (SELECT name FROM grades LIMIT ',
        @a:[email protected]+1,
        ', 1)')
    )
FROM grades

Que nous mettrons dans une variable nommée @line1, avec les données de la première colonne (qui est le nom de la deuxième colonne) :

SET @a = -1;
SET @line1 = CONCAT(
    'SELECT \'Name\',',
    (
        SELECT GROUP_CONCAT(
            CONCAT(' (SELECT Name FROM grades LIMIT ',
                @a:[email protected]+1,
                ', 1)')
            )
        FROM grades
    ));

En suivant la même logique, la deuxième ligne sera :

SET @a := -1;
SET @line2 = CONCAT(
    'SELECT \'Marks\',',
    (
        SELECT GROUP_CONCAT(
            CONCAT(' (SELECT Marks FROM grades LIMIT ',
                @a:[email protected]+1,
                ', 1)')
            )
        FROM grades
    ));

En les combinant tous :

Nos trois variables contiennent désormais :

@header:
SELECT 'id',  '1', '2' LIMIT 0, 0

@line1:
SELECT 'Name', (SELECT Name FROM grades LIMIT 0, 1),
    (SELECT name FROM grades LIMIT 1, 1)

@line2:
SELECT 'Marks', (SELECT Marks FROM grades LIMIT 0, 1),
    (SELECT marks FROM grades LIMIT 1, 1)

Nous avons juste besoin de créer une variable finale en utilisant CONCAT() , préparez-la comme une nouvelle requête et exécutez-la :

SET @query = CONCAT('(',
    @header,
    ') UNION (',
    @line1,
    ') UNION (',
    @line2,
    ')'
);

PREPARE my_query FROM @query;
EXECUTE my_query;

Solution complète :

(pour test et référence) :

SET @header = CONCAT('SELECT \'id\', ',
    (SELECT GROUP_CONCAT(CONCAT(' \'', id, '\'')) FROM grades),
    ' LIMIT 0, 0');

SET @a = -1;
SET @line1 = CONCAT(
    'SELECT \'Name\',',
    (
        SELECT GROUP_CONCAT(
            CONCAT(' (SELECT Name FROM grades LIMIT ',
                @a:[email protected]+1,
                ', 1)')
            )
        FROM grades
    ));

SET @a := -1;
SET @line2 = CONCAT(
    'SELECT \'Marks\',',
    (
        SELECT GROUP_CONCAT(
            CONCAT(' (SELECT Marks FROM grades LIMIT ',
                @a:[email protected]+1,
                ', 1)')
            )
        FROM grades
    ));

SET @query = CONCAT('(',
    @header,
    ') UNION (',
    @line1,
    ') UNION (',
    @line2,
    ')'
);

PREPARE my_query FROM @query;
EXECUTE my_query;

Sortie :

+-------+------+-------+
| id    | 1    | 2     |
+-------+------+-------+
| Name  | Ram  | Shyam |
| Marks | 45   | 87    |
+-------+------+-------+
2 rows in set (0.00 sec)

Réflexions finales :

  • Je ne sais toujours pas pourquoi vous devez transformer des lignes en colonnes, et je suis sûr que la solution que j'ai présentée n'est pas la meilleure (en termes de performances).

  • Vous pouvez même utiliser ma solution comme point de départ et l'adapter à une solution à usage général où les noms de colonne de table (et le nombre de lignes) ne sont pas connus, en utilisant information_schema .COLUMNS en tant que source, mais je suppose que cela va trop loin.

  • Je crois fermement qu'il est bien préférable de mettre la table d'origine dans un tableau, puis de faire pivoter ce tableau, obtenant ainsi les données dans le format souhaité.