【问题标题】:Pivoting mysql result with dates and sums使用日期和总和透视 mysql 结果
【发布时间】:2016-05-05 07:45:55
【问题描述】:

我在 mysql 中有一些数据,我需要从中创建一些报告。 我的数据来自以下查询:

SELECT StoreNbr,StoreName,Date, SUM(`Sales`) FROM sales_tbl GROUP BY StoreNbr,StoreName,Date;

这会产生以下数据(我的示例只是一小部分):

+-----------+---------------------------+----------------------------+
| StoreNbr | StoreName              | Date       | SUM(Sales)        |
+-----------+---------------------------+----------------------------+
|      1112 | Store1                | 2016-01-16 |            115.09 |
|      1112 | Store1                | 2016-01-17 |             81.00 |
|      1113 | Store2                | 2016-01-16 |            112.44 |
|      1113 | Store2                | 2016-01-17 |             56.61 |

我想把我的数据变成这样:

+-----------+---------------------------+----------------------------+
| StoreNbr | StoreName              | 2016-01-16       | 2016-01-17  |
+-----------+---------------------------+----------------------------+
|      1112 | Store1                | 115.09           |       81.00 |
|      1113 | Store2                | 112.44           |       56.61 |

显然,查询中可能会返回数千行(商店)和未知数量的日期,因为我的查询可能会像这样运行(这将需要返回 120+ 列的日期):

SELECT StoreNbr,StoreName,Date, SUM(`Sales`) FROM sales_tbl WHERE (Date BETWEEN '2016-01-10' AND '2016-05-10') GROUP BY StoreNbr,StoreName,Date;

有几种方法可以做到这一点,没有一个很简单。我做了一些研究,有些人提到 mysql 不支持旋转。我正在运行 mariadb,并且看到 mariadb 支持通过连接引擎进行旋转。我无法让它工作(调整他们在我的数据上的官方示例)。 另一种方法是大量的 IF 和案例,但我发现的大多数答案都很难适应,或者仅针对所询问的人提供的数据量身定制。 另一种方法是在数据出现在我的数组中时对其进行处理,因为我最后有一个 json 响应来提供数据表。 - 这是我还没有弄清楚的另一个想法。

我正在寻找一种方法来获得独立于日期数量的所需输出(我猜日期可以用几周或其他任何东西代替)。有人可以帮忙吗?

【问题讨论】:

  • 我怀疑这能否提供一个非常好的报告,但最简单的解决方案可能是使用您在标签中列出的 PHP。
  • 我知道!我只是在执行公司的需求 :) 尽管营销部门可能希望查看商店在 5 天内的表现,并且这些数据可以很好地用于屏幕上的图表或导出到 excel 之后,但这是有道理的。
  • SQL 实际上不是一种好的报告语言。不过,它是一种出色的数据提取语言。所以你应该保留你当前的查询,并根据它用另一种语言(如 PHP)制作报告。
  • 你的数据中有很多不同的日期吗?
  • 每天都有来自多家商店的报告。因此,例如,如果我现在提取报告,我将获得昨天的日期以及该日期商店的所有销售额。这些数据是累积的,是我要报告的数据。

标签: php mysql arrays


【解决方案1】:

选择所有不同的日期

SELECT DISTINCT Date 
FROM sales_tbl 
WHERE (Date BETWEEN '2016-01-10' AND '2016-05-10')
ORDER BY Date;

并初始化一个由存储零的日期索引的数组:

$dateIndexedArray = array();
while($row = $stmt1->fetch(PDO::FETCH_ASSOC) {
    $dateIndexedArray[$row['Date']] = 0;
}

阵列看起来像

[
    '2016-01-16' => 0,
    '2016-01-17' => 0
]

然后执行你的查询

SELECT StoreNbr, StoreName,Date, SUM(`Sales`) AS Sales 
FROM sales_tbl
WHERE (Date BETWEEN '2016-01-10' AND '2016-05-10')
GROUP BY StoreNbr,StoreName,Date;

并将“销售”存储在每个商店的日期索引数组中

$report = array();
while($row = $stmt2->fetch(PDO::FETCH_ASSOC)){
    $storeIndex = $row['StoreNbr'] . ':' . $row['StoreName'];
    if (!isset($report[$storeIndex])) {
        $report[$storeIndex] = array(
            'StoreNbr'  => $row['StoreNbr'],
            'StoreName' => $row['StoreName'],
            'Sales' => $dateIndexedArray
        );
    }
    $report[$storeIndex]['Sales'][$row['Date']] = $row['Sales'];
}

$report 数组将如下所示:

[
    '1112:Store1' => [
        'StoreNbr'  => 1112,
        'StoreName' => 'Store1',
        'Sales' => [
            '2016-01-16' => 115.09,
            '2016-01-17' => 81.00
        ]
    ],
    '1113:Store2' => [
        'StoreNbr'  => 1113,
        'StoreName' => 'Store2',
        'Sales' => [
            '2016-01-16' => 112.44,
            '2016-01-17' => 56.61
        ]
    ]
]

更新: 如果您需要将每个商店的所有数据放在一行中,您可以将代码更改为:

$report = array();
while($row = $stmt2->fetch(PDO::FETCH_ASSOC)){
    $storeIndex = $row['StoreNbr'] . ':' . $row['StoreName'];
    if (!isset($report[$storeIndex])) {
        $report[$storeIndex] = $dateIndexedArray;
        $report[$storeIndex]['StoreNbr']  = $row['StoreNbr'];
        $report[$storeIndex]['StoreName'] = $row['StoreName'];
    }
    $report[$storeIndex][$row['Date']] = $row['Sales'];
}

生成的数组将如下所示:

[
    '1112:Store1' => [
        'StoreNbr'  => 1112,
        'StoreName' => 'Store1'
        '2016-01-16' => 115.09,
        '2016-01-17' => 81.
    ],
    '1113:Store2' => [
        'StoreNbr'  => 1113,
        'StoreName' => 'Store2',
        '2016-01-16' => 112.44,
        '2016-01-17' => 56.61
    ]
]

更新 2:要获得每家商店的总销售额,您可以使用 WITH ROLLUP

SELECT StoreNbr, StoreName,Date, SUM(`Sales`) AS Sales 
FROM sales_tbl
WHERE (Date BETWEEN '2016-01-10' AND '2016-05-10')
GROUP BY StoreNbr,StoreName,Date WITH ROLLUP;
$report = array();
while($row = $stmt2->fetch(PDO::FETCH_ASSOC)){
    if ($row['StoreName'] === null) {
        // Skip this row.
        // It contains total sales grouped by StoreNbr 
        // (or not grouped if StoreNbr === null).
        continue;
    }
    $storeIndex = $row['StoreNbr'] . ':' . $row['StoreName'];
    if (!isset($report[$storeIndex])) {
        $report[$storeIndex] = $dateIndexedArray;
        $report[$storeIndex]['StoreNbr']  = $row['StoreNbr'];
        $report[$storeIndex]['StoreName'] = $row['StoreName'];
    }
    if ($row['Date'] === null) {
        // This row contains total sales grouped by StoreNbr & StoreName
        $report[$storeIndex]['TotalSales'] = $row['Sales']
    } else {
        $report[$storeIndex][$row['Date']] = $row['Sales'];
    }
}

请注意,我从未使用过WITH ROLLUP。所以你可能需要调整代码。

【讨论】:

  • 谢谢!我有没有机会在这个循环中得到总数?例如 '1113:Store2' => [ 'StoreNbr' => 1113, 'StoreName' => 'Store2', '2016-01-16' => 112.44, '2016-01-17' => 56.61, '总计' => 169.05 ]
  • @IoannisKokkinis,检查更新。如果您在测试后给我一些反馈会很好,因为我从未尝试过。
  • 这个 ROLUP 太棒了.. 以前从未使用过。只是它让我获得了与子句中按项目分组一样多的 NULL 行。我正在努力,准备好后会回来。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-28
  • 2022-12-19
  • 1970-01-01
  • 2017-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多