如何在不知道列的情况下进行数据透视表

时间:2012-08-31 20:22:37

标签: mysql sql postgresql pivot

我已经阅读了有关如何进行数据透视表的stackoverflow上的大部分帖子,但所有帖子都显示了具有列的先验知识的示例。如果您不知道列将是什么,如何构造查询。这是一些示例数据:

id       column       value       Row
1        age          13          1
2        height       55          1
3        fav number   NULL        1
4        siblings     4           1
5        age          55          2
6        height       54          2
7        fav number   12          2

我正在寻找这个输出:

row        age       height        fav number       siblings
1          13        55            NULL             4
2          55        54            12               NULL

正如您所看到的,没有第2行缺少兄弟姐妹的条目。查询时列名称未知。你会如何进行这个查询。

2 个答案:

答案 0 :(得分:2)

我没有看到任何方法你可以写一些花哨的SELECT查询来获得你想要的东西。你将不得不做一些预处理。


您必须从某种程序,应用程序,脚本等执行此MySQL查询。不确定该语言是什么,但这是我在PHP中要做的事情:

/* $data is where our data is going to be stored in our desired format */
$data = array();
/* $columns is a list of all column names */
$columns = array();
/* $rows is a list of all row names (probably '1', '2', etc) */
$rows = array();

$result = mysql_query('SELECT column, value, row FROM TableName');
while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
  /* if this row isn't in $data yet, add it */
  if (!array_key_exists($row['row'], $data) {
    $data[$row['row']] = array();
  }

  /* if this column isn't in $columns yet, add it */
  if (!in_array($row['column'], $columns)) {
    array_push($columns, $row['column']);
  }

  /* if this row isn't in $rows yet, add it */
  if (!in_array($row['row'], $rows)) {
    array_push($rows, $row['row']);
  }

  /* set the actual value in our multi-dimensional array $data */
  $data[$row['row']][$row['column']] = $row['value'];
}
/* free the result (php specific thing) */
mysql_free_result($result);

/* if we didn't set anything (row, column) pairs, set it to null in $data */
foreach ($rows as $r) {
  foreach ($columns as $c) {
    if (!array_key_exists($c, $data[$r])) {
      $data[$r][$c] = null;
    }
  }
}

这将把所有数据放入PHP中数组中所需的格式。


例如,在您上面提供的示例数据上运行此算法后,您将能够:

echo $data['2']['age']; // $data['row']['column']

哪个会输出55。


或者如果您的数据库没有实时更新(您有一堆数据需要重新格式化一次,而不是连续更新),您可以将上面的脚本扩展为还有一些“CREATE TABLE” ,“INSERT INTO”查询基本上以您正在寻找的格式重新创建表。

此外,如果您实时接收数据,您仍然可以编写上述脚本,但是您只想在处理原始表时删除这些行,然后只要数据运行就运行该脚本被放入原始表格。

答案 1 :(得分:2)

我怀疑你可以像你期望的那样在MySQL或PostgreSQL中做到这一点,但是我已经使用了一种替代方法,其中数据是非常自由形式的。我们的用例是“菜单项传递回应用程序的属性”,当然我们在查询中不了解这些属性。但是你无法创建一个简单的数据透视表。

你不能的原因是PostgreSQL要求返回的元组结构事先定义。并非所有db都这样做(例如,Informix允许不同的行具有不同的结构!)但大多数都是这样做。

我们的方法仅限PostgreSQL。但是,也许通过一些调整,您可以找到某个地方的MySQL等价物。我们所做的基本上就是你的版本:

select row, array_agg("column" || '=' || "value") from sample_data group by row;

这会产生如下输出:

1 {"age=3","height=55",null,"siblings=4"}
2 {"age=55","height=54","favorite_number=12"}

你甚至可以通过以下方式摆脱NULLS:

select row, array_agg("column" || '=' || "value")
 WHERE value is not null
 GROUP BY row;

然后你得到类似的东西:

1 {"age=3","height=55","siblings=4"}
2 {"age=55","height=54","favorite_number=12"}

我不知道如何在MySQL中做同样的事情。