2013-12-18 3 views
2

У меня есть таблица, которая выглядит следующим образом:Столбцы в строках запросов

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 And Profit и комбайна, используя функцию Union, но должен быть более простой способ.

Любая помощь была бы действительно оценена.

Макс

+2

что делать, если это доход, стоимость и прибыль имеют более 10 рядов для компании? –

+0

Это очень вероятно .. будет иметь 20 строк за компанию. Другие предметы будут накладными расходами, маркетингом и т. Д. Thx – user3114015

+0

Как насчет изменения структуры таблиц, а не одного отношения «один ко многим»? –

ответ

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

Отлично! отлично работает после корректировки IF и полевых инструкций. Еще один вопрос - у меня 20 лет данных. Есть ли более простой способ написать инструкцию MAX – user3114015

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

+0

Kickstart, как и ваше элегантное решение, но PLS-медведь с этим новичком. Вставьте код в мой запрос и измените его на мое имя таблицы. Get Error "(отсутствующий оператор) в выражении запроса 'GROUP_CONCAT (Revenue ORDER BY' Year'). Thx – user3114015

+0

Я не вижу ничего очевидного. Можете ли вы вставить полный запрос (возможно, ошибка находится в другом месте запроса) Как показывает sqlfiddle, он должен работать так, как есть. – Kickstart

+0

SELECT Company AS Expr1, item AS Expr2, 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, элемент «Выручка» AS, GROUP_CONCAT (доход ORDER BY 'Year) AS item_details – user3114015

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; 
    } 
} 

?> 
Смежные вопросы