sql >> Database >  >> RDS >> Mysql

Selecteer MYSQL-rijen maar rijen in kolommen en kolom in rijen

Met vaste en bekende kolommen, hier is hoe het te doen (ik ben zo vrij geweest om de tabel "cijfers" te noemen):

Algemeen idee:

Om een ​​samenvoeging van verschillende zoekopdrachten te maken en deze uit te voeren.

Aangezien u actuele gegevens als kolomkoppen nodig heeft, ziet het eerste deel van de unie er als volgt uit:

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

Die query alleen zal het resultaat dupliceren, daarom moeten we MySQL vertellen dat we 0 rijen moeten hebben door LIMIT 0, 0 toe te voegen .

Onze eerste rij van de vereniging zal 'Name' . bevatten , evenals alle gegevens uit de kolom "Naam" van de tabel. Om die regel te krijgen, hebben we een zoekopdracht nodig zoals:

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

Met dezelfde logica ziet onze tweede rij er als volgt uit:

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

De kop ophalen:

We moeten een rij van MySQL maken zoals:

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

Om die regel te krijgen, gebruiken we CONCAT() en GROUP_CONCAT() functies:

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

en we gaan die regel opslaan in een nieuwe variabele:

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

De lijnen maken:

We moeten twee query's maken, zoals de volgende:

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

Aangezien we niet van tevoren weten hoeveel rijen er in onze originele tabel zijn, zullen we variabelen gebruiken om de verschillende LIMIT x, 1 te genereren verklaringen. Ze kunnen worden geproduceerd met behulp van het volgende:

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

Met dit fragment kunnen we onze subquery's maken:

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

Die we in een variabele namen @line1 plaatsen, samen met de gegevens van de eerste kolom (wat de naam van de tweede kolom is):

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

Door dezelfde logica te volgen, wordt de tweede regel:

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

Ze allemaal combineren:

Onze drie variabelen bevatten nu:

@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)

We hoeven alleen een laatste variabele te maken met CONCAT() , bereid het voor als een nieuwe query en voer het uit:

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

PREPARE my_query FROM @query;
EXECUTE my_query;

Volledige oplossing:

(voor testen en referentie):

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;

Uitgang:

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

Afsluitende gedachten:

  • Ik weet nog steeds niet zeker waarom je rijen in kolommen moet omzetten, en ik weet zeker dat de oplossing die ik heb gepresenteerd niet de beste is (qua prestaties).

  • U kunt zelfs mijn oplossing als een begin gebruiken en deze aanpassen aan een oplossing voor algemene doeleinden waarbij de tabelkolomnamen (en het aantal regels) niet bekend zijn, met behulp van information_schema .COLUMNS als bron, maar ik denk dat dat gewoon te ver gaat.

  • Ik ben er sterk van overtuigd dat het veel beter is om de originele tabel in een array te plaatsen en die array vervolgens te roteren, zodat de gegevens in het gewenste formaat komen.



  1. PHP-tabel (Datum) dynamische kleurverandering op basis van geldigheid

  2. Schemabeheertips voor MySQL en MariaDB

  3. selectionArgs in SQLiteQueryBuilder werkt niet met gehele waarden in kolommen

  4. SQL AVG() voor beginners