【问题标题】:Pivot report with MySQL and PHP使用 MySQL 和 PHP 进行数据透视报告
【发布时间】:2015-02-19 17:34:30
【问题描述】:

我有 3 个 mysql 表,如下所示: table-01: 公司

id | comp_name | year
------------------------
 1 | Novartis  | 2015
 2 | Roche     | 2015
 3 | Glaxco    | 2015

table-02:产品

id | fullname
 1 | Paracetamol
 2 | Eesomaprazol 
 3 | Phenobuterol

table-03:出价

id | comp_id | prod_id | rate | year
 1 |       1 |       1 |  2.0 | 2015
 2 |       1 |       2 |  4.2 | 2015
 3 |       1 |       3 |  2.3 | 2015
 4 |       2 |       1 |  3.0 | 2015
 5 |       2 |       2 |  4.0 | 2015
 6 |       2 |       3 |  2.5 | 2015
 7 |       3 |       1 |  2.3 | 2015
 8 |       3 |       2 |  4.5 | 2015
 9 |       3 |       3 |  2.8 | 2015

从上面三个表中我想得到以下由 php 获取的汇总表:

fullname     | Novartis | Roche | Glaxco
Paracetamol  |      2.0 |   3.0 | 2.3
Eesomaprazol |      4.2 |   4.0 | 4.5 
Phenobuterol |      2.3 |   2.5 | 2.8

我不太了解如何使用 MySQL 表和准备好的语句从 php 创建数据透视报告。另外,我必须从 php 端(而不是从 MySQL 端的 SQL 查询)实现这一点。

虽然我知道基本的 MySQL 查询并且可以获取和获取正常的 MySQL 数据,但我不知道如何实现这一点。但是如果我能从上面三个表的数据中得到一个实际的想法,我可以从任何大而复杂的数据结构中着手。

【问题讨论】:

  • 好的,省略那个子句

标签: php mysql oop pivot


【解决方案1】:

您必须动态生成要透视的列,您可以在 mysql 中使用:

#1st part
SET @sql = NULL;

SELECT GROUP_CONCAT(
    DISTINCT CONCAT('sum(case when comp_name = ''', comp_name, ''' then rate else 0 end) as ',
                    replace(comp_name, ' ', ''))
)
INTO @sql
FROM company;

#2nd part
SET @sql = CONCAT('SELECT
  fullname,
  ', @sql, '
FROM bid
  JOIN product ON product.id = bid.prod_id
  JOIN company ON company.id = bid.comp_id
GROUP BY fullname');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

解释:

#1st部分

这部分生成 SQL 来汇总费率并生成列标题,因此在@sql 中您将拥有:

sum(case when comp_name = 'Novartis' then rate else 0 end) as Novartis,sum(case when comp_name = 'Roche' then rate else 0 end) as Roche,sum(case when comp_name = 'Glaxco' then rate else 0 end) as Glaxco

#第二部分

这部分生成并执行主查询,生成输出。


然后输出(对我来说):

+--------------+----------+-------+--------+
| fullname     | Novartis | Roche | Glaxco |
+--------------+----------+-------+--------+
| Eesomaprazol |      4.2 |     4 |    4.5 |
| Paracetamol  |        2 |     3 |    2.3 |
| Phenobuterol |      2.3 |   2.5 |    2.8 |
+--------------+----------+-------+--------+

PHP 代码(我想你正在使用 PDO):

$dbh = new PDO($dsn, $user, $password);
$dbh->query("SET @sql = NULL");
$dbh->query("SELECT GROUP_CONCAT(
    DISTINCT CONCAT('sum(case when comp_name = ''', comp_name, ''' then rate else 0 end) as ',
                    replace(comp_name, ' ', ''))
    )
    INTO @sql
    FROM company"
);
$dbh->query("SET @sql = CONCAT('SELECT
      fullname,
      ', @sql, '
    FROM bid
      JOIN product ON product.id = bid.prod_id
      JOIN company ON company.id = bid.comp_id
    GROUP BY fullname')"
);
$dbh->query("PREPARE stmt FROM @sql");
$result = $dbh->query("EXECUTE stmt")->fetchAll(PDO::FETCH_ASSOC);
$dbh->query("DEALLOCATE PREPARE stmt");

print_r($result);

然后输出:

Array
(
    [0] => Array
        (
            [fullname] => Eesomaprazol
            [Novartis] => 4.2
            [Roche] => 4
            [Glaxco] => 4.5
        )

    [1] => Array
        (
            [fullname] => Paracetamol
            [Novartis] => 2
            [Roche] => 3
            [Glaxco] => 2.3
        )

    [2] => Array
        (
            [fullname] => Phenobuterol
            [Novartis] => 2.3
            [Roche] => 2.5
            [Glaxco] => 2.8
        )

)

变量@sql在当前数据库连接中可见,所以你可以使用它。

【讨论】:

  • 我为您的回答 +1。只有一件事您可以改进:在您的case 中使用 id 而不是 comp_name,这将在第二个请求中保存加入公司。我也不确定你是否应该按 comp_name/id 分组或按年份过滤......这取决于 op 想要什么。我不知道
  • Yeep in case 也可以是 id 列,这取决于 OP 想要如何实现,但你有好点子。关于分组,我不知道OP想要什么结果,但现在只是改变。
  • 无论如何,如果我能 +2 你的答案,我会做到的。
  • 这根本不是我的做法,而是努力+1。
  • 我有一个问题,我怎样才能将公司名称作为列标题,因为公司名称在数组键中,所以我必须指定公司名称才能从关联数组中获取数据。但是让更多的公司甚至公司是动态的,所以我不知道所有公司的名称。如果我想获取 html 表中的数据,那么如何将公司名称作为该 html 表的列标题?
猜你喜欢
  • 1970-01-01
  • 2016-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 2016-11-29
  • 1970-01-01
相关资源
最近更新 更多