如果列数是固定的且已知,下面是如何实现的(我给表格取了一个名称“grades”):
总体思路:
创建不同的查询并将其合并执行。
由于您需要使用实际数据作为列标题,因此联合查询的第一部分将如下所示:
SELECT 'id', '1', '2', ....
那个查询会重复结果,因此我们需要告诉MySQL我们需要通过添加LIMIT 0, 0
来获取0行。
我们联接的第一行将包含'Name'
以及表中“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:=@a+1 FROM grades;
使用此代码片段,我们可以创建子查询:
SELECT GROUP_CONCAT(
CONCAT(' (SELECT name FROM grades LIMIT ',
@a:=@a+1,
', 1)')
)
FROM grades
我们将把它与第一列数据(即第二列的名称)放入名为 @line1 的变量中。
SET @a = -1;
SET @line1 = CONCAT(
'SELECT \'Name\',',
(
SELECT GROUP_CONCAT(
CONCAT(' (SELECT Name FROM grades LIMIT ',
@a:=@a+1,
', 1)')
)
FROM grades
));
按照同样的逻辑,第二行将是:
SET @a := -1;
SET @line2 = CONCAT(
'SELECT \'Marks\',',
(
SELECT GROUP_CONCAT(
CONCAT(' (SELECT Marks FROM grades LIMIT ',
@a:=@a+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:=@a+1,
', 1)')
)
FROM grades
));
SET @a := -1;
SET @line2 = CONCAT(
'SELECT \'Marks\',',
(
SELECT GROUP_CONCAT(
CONCAT(' (SELECT Marks FROM grades LIMIT ',
@a:=@a+1,
', 1)')
)
FROM grades
));
SET @query = CONCAT('(',
@header,
') UNION (',
@line1,
') UNION (',
@line2,
')'
);
PREPARE my_query FROM @query;
EXECUTE my_query;
输出:
+-------+------+-------+
| id | 1 | 2 |
+-------+------+-------+
| Name | Ram | Shyam |
| Marks | 45 | 87 |
+-------+------+-------+
共2行(0.00秒)
结束语:
我仍然不确定为什么需要将行转换为列,并且我相信我提出的解决方案并不是最好的(从性能角度考虑)。
您甚至可以使用我的解决方案作为起点,并使用information_schema
.COLUMNS
作为数据源,将表列名(和行数)未知的表转换为通用解决方案,但我认为这只是过于繁琐了。
我强烈建议将原始表格放入数组中,然后旋转该数组,从而获得所需格式的数据。