选择 MYSQL 行,但将行选择为列,将列选择为行

Posted

技术标签:

【中文标题】选择 MYSQL 行,但将行选择为列,将列选择为行【英文标题】:Select MYSQL rows but rows into columns and column into rows 【发布时间】:2010-07-20 08:01:44 【问题描述】:

我想选择数据库中的所有行,但我希望它们以倒序排列。意思是,我想使用第一列数据作为新实体并将实体作为第一列。我想你明白我的意思

这是一个插图

id    |     name       | marks
-------------------------------
1     |    Ram         | 45
--------------------------------
2     |    Shyam       |  87

id    |   1     |    2     |
----------------------------
Name  |  Ram    |   Shyam  |
----------------------------
Marks |  45     |    87    | 

【问题讨论】:

php 中需要倒序吗?在 SQL 中,我猜它没有任何意义...... 结帐***.com/questions/1241178/mysql-rows-to-columns - 但你能解释一下你为什么想要这个吗?可能有更好的解决方案。 @kaavier,我知道如何在 PHP 中做到这一点?但是我需要一个sql解决方案 这在mySQL中可能做不到。这不是它的设计目的。 【参考方案1】:

使用固定且已知的列,这是如何做到的(我冒昧地将表格命名为“等级”):

总体思路:

创建不同查询的联合并执行它。

由于您需要实际数据作为列标题,联合的第一部分将如下所示:

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

单独的查询将重复结果,因此我们需要通过添加LIMIT 0, 0 来告诉 MySQL 我们需要有 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:=@a+1 FROM grades;

使用这个 sn-p,我们可以创建我们的子查询:

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;

输出:

+--------+------+--------+ |编号 | 1 | 2 | +--------+------+--------+ |姓名 |拉姆 |希亚姆 | |标记 | 45 | 87 | +--------+------+--------+ 2 行(0.00 秒)

结束的想法:

我仍然不确定为什么需要将行转换为列,而且我确信我提出的解决方案不是最好的(就性能而言)。

您甚至可以使用我的解决方案作为开始,并将其调整为不知道表列名称(和行数)的通用解决方案,使用 information_schema.COLUMNS 作为源,但我想这太过分了。

我坚信最好将原始表格放入一个数组中,然后旋转该数组,从而获得所需格式的数据。

【讨论】:

【参考方案2】:

听起来您正在寻找的是对数据的交叉表(或转置)操作。

这是一篇很好的文章,描述了如何做到这一点:http://onlamp.com/pub/a/onlamp/2003/12/04/crosstabs.html - 虽然有点过时,但不确定现在是否有更有效的方法可以做到这一点。它对我来说足够好。

【讨论】:

【参考方案3】:

在命令行上,您可以使用 \G 结束查询以实现此目的 例如

select * from `students`\G;

【讨论】:

有趣。但我认为这不是操作人员正在寻找的。它将每一行显示为一个块,而不是每一行并排显示 同意。而且我不确定这是否甚至可以与 php 的 mysql 函数一起使用,但这是我所知道的最接近的事情:)

以上是关于选择 MYSQL 行,但将行选择为列,将列选择为行的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 2008 R2,将列转换为行,将行转换为列[重复]

MySQL - 根据每列的最新日期和 id 列表将行转换为列

Postgres 表选择多列并将结果(列)动态转换为行 - 将列转置为行

将行数据拆分为列

按一定数量将行拆分为列

使用可能的组合将行转换为列