簡體   English   中英

選擇MYSQL行,但行為列,列為行

[英]Select MYSQL rows but rows into columns and column into rows

我想選擇數據庫中的所有行,但我希望它們按順序排列。 意思是,我想使用第一列數據作為新實體,並將實體作為第一列。 我想你明白了我的意思

這是一個例子

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

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

使用固定和已知的列,這里是如何做到的(我冒昧地命名表“成績”):

大概的概念:

創建不同查詢的並集並執行它。

由於您需要實際數據作為列標題,因此聯合的第一部分將如下所示:

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;

使用此代碼段,我們可以創建子查詢:

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()創建一個final變量,將其准備為新查詢並執行它:

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作為一個來源,但我想這只是走得太遠了。

  • 我堅信將原始表放入數組然后旋轉該數組會更好,從而獲得所需格式的數據。

聽起來你正在尋找的是對數據進行交叉表(或轉置)操作。

這是一篇很好的文章,描述了如何實現這個目標: http//onlamp.com/pub/a/onlamp/2003/12/04/crosstabs.html - 它雖然有點陳舊,但不確定現在是否有更有效的方法要做到這一點。 它對我來說效果很好。

在命令行上,您可以使用\\ G結束查詢以實現此目的

select * from `students`\G;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM