代码之家  ›  专栏  ›  技术社区  ›  Starx

选择MYSQL rows,但选择rows into columns和column into rows

  •  3
  • Starx  · 技术社区  · 14 年前

    我想选择数据库中的所有行,但我希望它们的顺序相反。也就是说,我想使用第一列数据作为新实体,使用当前实体作为第一列。我想你明白我的意思了

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

    id    |   1     |    2     |
    ----------------------------
    Name  |  Ram    |   Shyam  |
    ----------------------------
    Marks |  45     |    87    | 
    
    3 回复  |  直到 14 年前
        1
  •  16
  •   Anax    11 年前

    对于固定且已知的列,下面介绍如何操作(我冒昧地将表命名为“grades”):

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

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

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

    仅此查询就将复制结果,因此我们需要通过添加 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),
        ...
    

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

    创建线条:

    我们需要创建两个查询,如下所示:

    选择“名称”,
    (从等级限制0、1中选择名称),
    (从等级限制1,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
    

    我们将把它与第一列数据(即第二列的名称)一起放入变量names@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 rows in set (0.00 sec)
    

    结束语:

    • 您甚至可以使用我的解决方案作为一个开始,并使用 information_schema . COLUMNS 作为一个来源,但我想这太过分了。

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

        2
  •  0
  •   kander    14 年前

    听起来你要找的是对数据的交叉表(或转置)操作。

    http://onlamp.com/pub/a/onlamp/2003/12/04/crosstabs.html -虽然有点过时,但不确定现在是否有更有效的方法来做这件事。对我来说已经足够好了。

        3
  •  -1
  •   Gunjan    14 年前

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

    select * from `students`\G;