Mysql
 sql >> база данни >  >> RDS >> Mysql

Изберете MYSQL редове, но редове в колони и колона в редове

С фиксирани и известни колони, ето как да го направите (позех си свободата да назова таблицата „оценки“):

Обща идея:

За да създадете обединение от различни заявки и да го изпълните.

Тъй като имате нужда от действителни данни като заглавки на колони, първата част от съюза ще изглежда така:

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

Само тази заявка ще дублира резултата, следователно трябва да кажем на MySQL, че трябва да имаме 0 реда, като добавим LIMIT 0, 0 .

Първият ни ред на съюза ще съдържа 'Name' , както и всички данни от колоната "Име" на таблицата. За да получим този ред, имаме нужда от заявка като:

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

Използвайки същата логика, вторият ни ред ще изглежда така:

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

Получаване на заглавката:

Трябва да създадем ред от MySQL като:

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

За да получим този ред, ще използваме CONCAT() и GROUP_CONCAT() функции:

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

и ще съхраним този ред в нова променлива:

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

Създаване на линиите:

Трябва да създадем две заявки като следните:

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

Тъй като не знаем предварително колко реда има в нашата оригинална таблица, ще използваме променливи, за да генерираме различните LIMIT x, 1 изявления. Те могат да бъдат произведени с помощта на следното:

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

Използвайки този фрагмент, можем да създадем нашите подзаявки:

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

Което ще поставим в променлива с имена @line1, заедно с данните от първата колона (което е името на втората колона):

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

Комбиниране на всички:

Нашите три променливи вече съдържат:

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

Просто трябва да създадем окончателна променлива с помощта на CONCAT() , подгответе го като нова заявка и я изпълнете:

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

PREPARE my_query FROM @query;
EXECUTE my_query;
 

Цялото решение:

(за тестване и справка):

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;
 

Изход:

<пред>+-------+-----+-------+| ID | 1 | 2 |+-------+-----+-------+| Име | Рам | Шям || Марки | 45 | 87 |+-------+------+-------+2 реда в комплект (0,00 сек)

Заключителни мисли:

  • Все още не съм сигурен защо трябва да трансформирате редовете в колони и съм сигурен, че решението, което представих, не е най-доброто (по отношение на производителността).

  • Можете дори да използвате моето решение като начало и да го адаптирате към решение с общо предназначение, където имената на колоните на таблицата (и броя на редовете) не са известни, като използвате information_schema .COLUMNS като източник, но предполагам, че просто отива твърде далеч.

  • Силно вярвам, че е много по-добре оригиналната таблица да се постави в масив и след това да се завърти този масив, като по този начин се получават данните в желания формат.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. АКТУАЛИЗИРАНЕ/ИЗТРИВАНЕ в mysql и да получите списъка със засегнатите идентификатори на редове?

  2. Някаква причина за клауза GROUP BY без функция за агрегиране?

  3. MySQL Connector/J буферира ли се редове при поточно предаване на ResultSet?

  4. Актуализирайте MySQL с условието if

  5. Как мога да вмъкна данни в MySQL база данни?