列到行查询

时间:2013-12-18 06:37:39

标签: mysql select pivot

我的桌子看起来像这样:

Company Year    Revenue Cost    Profit
ABC      1         10    6        4
ABC      2         12    7        5
ABC      3         14    8        6
XYZ      1         25   18        7
XYZ      2         27   19        8
XYZ      3         29   20        9

我希望它看起来像这样:

Company Item    1   2   3
ABC     Revenue 10  12  14
ABC     Cost    6   7   8
ABC     Profit  4   5   6
XYZ     Revenue 25  27  29
XYZ     Cost    18  19  20
XYZ     Profit  7   8   9

交叉表查询仅允许一个值。我可以使用单独的交叉表查询为Revenue,Cost和Profit以及使用Union功能的组合,但必须有一个更简单的方法。

任何帮助都会非常感激。

最高

4 个答案:

答案 0 :(得分:2)

您尝试的变化。

SELECT Company, 
    item, 
    SUBSTRING_INDEX(SUBSTRING_INDEX(item_details, ',', 1), ',', -1) AS `1`,
    SUBSTRING_INDEX(SUBSTRING_INDEX(item_details, ',', 2), ',', -1) AS `2`,
    SUBSTRING_INDEX(SUBSTRING_INDEX(item_details, ',', 3), ',', -1) AS `3`
FROM
(
    SELECT Company, 'Revenue' AS item, GROUP_CONCAT(Revenue ORDER BY `Year`) AS item_details
    FROM SomeTable
    GROUP BY Company
    UNION
    SELECT Company, 'Cost' AS item, GROUP_CONCAT(Cost ORDER BY `Year`)
    FROM SomeTable
    GROUP BY Company
    UNION
    SELECT Company, 'Profit' AS item, GROUP_CONCAT(Profit ORDER BY `Year`)
    FROM SomeTable
    GROUP BY Company
) Sub1
ORDER BY Company, FIELD(Item, 'Revenue', 'Cost', 'Profit')

SQL小提琴: -

http://www.sqlfiddle.com/#!2/995a0/6

答案 1 :(得分:1)

试试这个:

SELECT Company, Item, Col1 AS 1, Col2 AS 2, Col3 AS 3
FROM (SELECT a.Company, 'Revenue' AS Item, MAX(IF(a.Year = 1, a.Revenue, 0)) AS Col1, 
             MAX(IF(a.Year = 2, a.Revenue, 0)) AS Col2, MAX(IF(a.Year = 3, a.Revenue, 0)) AS Col3
      FROM tableA a 
      GROUP BY a.Company 
      UNION 
      SELECT a.Company, 'Cost' AS Item, MAX(IF(a.Year = 1, a.Cost, 0)) AS Col1, 
             MAX(IF(a.Year = 2, a.Cost, 0)) AS Col2, MAX(IF(a.Year = 3, a.Cost, 0)) AS Col3
      FROM tableA a 
      GROUP BY a.Company 
      UNION
      SELECT a.Company, 'Profit' AS Item, MAX(IF(a.Year = 1, a.Profit, 0)) AS Col1, 
             MAX(IF(a.Year = 2, a.Profit, 0)) AS Col2, MAX(IF(a.Year = 3, a.Profit, 0)) AS Col3
      FROM tableA a 
      GROUP BY a.Company 
     ) AS A 
ORDER BY Company, FIELD(Item, 'Revenue', 'Cost', 'Profit')

答案 2 :(得分:1)

出于可伸缩性(和灵活性)的原因,这样的问题最好留给应用程序级代码(例如,在有序的结果集上的简单PHP循环),但是,只是为了好玩......

SELECT company
     , item
     , MAX(CASE WHEN year = 1 THEN value END) y1
     , MAX(CASE WHEN year = 2 THEN value END) y2
     , MAX(CASE WHEN year = 3 THEN value END) y3
  FROM 
     ( SELECT company, year, 'revenue' item, revenue value FROM my_table
       UNION
       SELECT company, year, 'cost',cost FROM my_table
       UNION
       SELECT company, year, 'profit',profit FROM my_table
     ) x
 GROUP
    BY company
     , item
 ORDER 
    BY company
     , FIELD(item,'Revenue','Cost','Profit');

答案 3 :(得分:0)

第二种方式。没有经过测试(可能是一些拼写错误),但是做一些SQL来获取数据然后循环细节,将它们抛向一个对象来放出行。这将解决公司缺少一年数据的任何问题。

请注意,如果您有一个您感兴趣的年份表和一个公司表,您可以大大简化SQL。

<?php

$sql = "SELECT Sub1.Year, Sub2.Company, IFNULL(SomeTable.Revenue, 0) AS aValue, 'Revenue' AS Item
        FROM
        (
            SELECT DISTINCT Year FROM SomeTable
        ) Sub1
        CROSS JOIN 
        (
            SELECT DISTINCT Company FROM SomeTable
        ) Sub2
        LEFT OUTER JOIN SomeTable
        ON Sub1.Year = SomeTable.Year
        AND Sub2.Company = SomeTable.Company
        UNION
        SELECT Sub1.Year, Sub2.Company, IFNULL(SomeTable.Cost, 0) AS aValue, 'Cost' AS Item
        FROM
        (
            SELECT DISTINCT Year FROM SomeTable
        ) Sub1
        CROSS JOIN 
        (
            SELECT DISTINCT Company FROM SomeTable
        ) Sub2
        LEFT OUTER JOIN SomeTable
        ON Sub1.Year = SomeTable.Year
        AND Sub2.Company = SomeTable.Company
        UNION
        SELECT Sub1.Year, Sub2.Company, IFNULL(SomeTable.Profit, 0) AS aValue, 'Profit' AS Item
        FROM
        (
            SELECT DISTINCT Year FROM SomeTable
        ) Sub1
        CROSS JOIN 
        (
            SELECT DISTINCT Company FROM SomeTable
        ) Sub2
        LEFT OUTER JOIN SomeTable
        ON Sub1.Year = SomeTable.Year
        AND Sub2.Company = SomeTable.Company
        ORDER BY Company, FIELD(Item, 'Revenue', 'Cost', 'Profit'), Year";

$query = $db->query($sql) or die($db->error()) ;
if ($row = $this->db->fetchAssoc())
{
    echo "<table>";
    $PrevCompany = $row['Company'];
    $PrevItem = $row['Item'];
    $aLine = new ProcessLine($PrevCompany, $PrevItem, true);
    do
    {
        if ($PrevCompany != $row['Company'] or $PrevItem != $row['Item'])
        {
            unset($aLine);
            $PrevCompany = $row['Company'];
            $PrevItem = $row['Item'];
            $aLine = new ProcessLine($PrevCompany, $PrevItem);
        }
        $aLine->Assign_Detail($row['Year'], $row['aValue'])

    } while($row = $this->db->fetchAssoc());
    unset($aLine);
    echo "</table>";
}

class ProcessLine
{
    private $Company;
    private $Item;
    private $row_details = array();
    private $FirstRow = false
    public __CONSTRUCT($Company, $Item, $FirstRow=false)
    {
        $this->Company = $Company;
        $this->Item = $Item;
    }

    public __DESTRUCT()
    {
        if ($this->Firstrow)
        {
            echo "<tr><th>".$this->Company."</th><th>".$this->Item."</th>";
            foreach($row_details AS $row_year=>$row_value)
            {
                echo "<th>$row_year</th>";
            }
            echo "</tr>";
        }
        echo "<tr><td>".$this->Company."</td><td>".$this->Item."</td><td>".implode("</td><td>", $row_details)."</td></tr>";
    }

    public Assign_Detail($in_year, $in_value)
    {
        $row_details[$in_year] = $in_value;
    }
}

?>