【问题标题】:Database Design and Query for Historical Tabular Data历史表格数据的数据库设计与查询
【发布时间】:2018-10-28 08:18:40
【问题描述】:

我有一组 HTML 表格,用于存储随时间推移的调查问题和回复。每个问题都有自己的 HTML 表格,列是年份,行是回复,然后各个单元格有当年的回复数量,如下所示:

我反复讨论了如何规范化这些数据并将其存储在数据库中,但我不确定最好的方法是什么。我正在寻找一个好的数据库模式,它可以随着时间的推移处理额外的问题、响应和年份。我也在寻找一个可以输出如下 HTML 表格的好查询。我可以在 PHP 循环中轻松做到这一点,但我担心这对性能不利。

现在,我有以下表格设计:

问题

id int(11) unsigned AI PK
name varchar(255) UNQ
number varchar(255) UNQ
text

年份

id int(11) unsigned AI PK
question_id int(11) unsigned FK
name varchar(255) UNQ (question_id + name)

回复

id int(11) unsigned AI PK
question_id int(11) unsigned FK
name varchar(255) UNQ (question_id + name)

数据

id int(11) unsigned AI PK
question_id int(11) unsigned FK
year_id int(11) unsigned FK
response_id int(11) unsigned FK UNQ (year_id + response_id)
count int(11) unsigned NULL

任何帮助或改进将不胜感激。

【问题讨论】:

  • 看起来方向是正确的
  • 表格上的每个单元格都显示 2 个值,例如:0 0.00 0.00 代表什么?

标签: mysql database database-design


【解决方案1】:

您不需要表 year,因为 yearquestion 独立的。

然后修改表data

  • year_id int(11) unsigned FKyear YEAR
  • UNQ (year_id + response_id)UNQ (year + response_id)

感谢Rick James

【讨论】:

  • 有一个YEAR 数据类型;使用它。
【解决方案2】:

对于您的目标数据模型的结构化版本已经有了很好的想法 - 如果您希望统计数据的结构更加灵活,但仍然能够随着时间的推移进行键控和分组,那么另一种选择可能是遵循 bi /dw 模式为你的数据建模

以下是“逻辑的”,并且与kimball et. al. 的事实表中的属性/维度相关,其中事实表的“粒度”是“src html 文件 + 表 + 行 + 单元格 + 值” )',假设你的价值观随着时间的推移是一致的

  • (我注意到在您的图片中,一个 html 文件有几个表格,每个单元格中有几个值)

  • group_srcfile(指向源 html 文件/表/行/单元格中的位置,您可能也可以存储源 html,以防以后需要进行尸检)

  • group_cohort(指向标准化队列,例如“18-24 岁随着时间的推移”或“男性随着时间的推移”)

  • group_question(指向问题定义 - 随着时间的推移,这些问题都是相同的)

  • question_id(问题定义+问题年份)

  • question_year(这是提出问题的年份)

  • cohort_start_year(这是该队列的开始年份被问到的问题)

  • cohort_end_year(这是被问到这个问题的队列的年末)

  • cohort_start_age(如果适用,将是标准化的“xxxx - yyyy”,例如:“18”)

  • cohort_end_age(这是指定的,或由“xxxx - present”推断,其中“present”是报告 html 文件的年份)

  • values 1 .. n 必须计算相同的东西,否则您还需要将它们分开

要生成体面的输出,您需要完成数据表上的问题,但无论您做什么,使用 php 导出 html 都相对简单

我考虑了将数据加载到 mysql 中的方法,但是没有作为数据源的 html 文件的可靠示例,很难编写特定代码(即在浏览器中打开并“查看源代码”) ',或等效)

作为一种通用方法,我将使用 php 和 DOMDocument 从 html 中解析每个事实(表格单元格 td),然后以非规范化形式发出一行,以便随后加载到临时表并最终加载到您的事实表中

在这种情况下,'emit' 是事实表中最终成为单个行的来源,但您还不能加载它,因为您不知道维度键是什么,除非您及时定义它们解析html

这实际上是不可能做到的:相反,加载到一个松散定义的表中(没有任何参考完整性),一旦你完成了所有文件的解析,编写 etl 或查询来生成你的维度表,然后再完成你的事实

(我可能会使用pentaho data integration 来处理第二阶段 - 它的流式 xml 解析器无法处理第一阶段:太严格了)


我发现 this test html file 已经足够老了,以至于我一想到要无休止地重写抓取代码来解释“dreamtheaver”带来的永无止境的布局变化,就忍不住吐了最后一杯咖啡。 ..

一旦我的手足够稳定,血流恢复正常,我引导机灵并生成以下 php - 尤其是没有对源表进行任何形式的重组/非规范化:

<?php

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

$dom = new DOMDocument();

$srcfile = 'testxmlparser.html';
$dom->loadHTMLFile( $srcfile, NULL );

echo 'odom is: ' . ($dom ? 'nice':'naughty') . PHP_EOL;

if( $dom ) {
  // get all the table rows in the document
  $tblrows = $dom->getElementsByTagName('tr');

  foreach( $tblrows as $trrow ) {
    $tblcells = $trrow->getElementsByTagName('td');
    $incr = 0;

    // buffer this table row's cell (td) data that we encounter, in case it is interesting...
    $srowbuf = '';
    foreach( $tblcells as $tdcell ) {
      $srowbuf = ($srowbuf . $tdcell->nodeValue);
      if( 1 <= $incr++ )
        $srowbuf = ($srowbuf . '+|');
    }
    // we know the table data we're interested in has 12 cells only
    if( 12 == $incr )
      echo $srowbuf . '+|' . $incr . '+|' . $srcfile . PHP_EOL;
  }
}

?>

【讨论】:

    【解决方案3】:

    一般来说,如果您有一个UNIQUE 键(这就是“UNQ”的意思吗??),请使用 if 表示 PRIMARY KEY

    “名称”通常不需要是VARCHAR(255)。选择较小的尺寸。

    “数字”通常不需要是VARCHAR(255)。选择更合适的数据类型。

    CREATE TABLE 语法编写架构;我在解析您的连续描述时遇到了严重问题。

    “0.00”代表什么?它可以从其他数据中推导出来吗?如果是这样,请不要存储它。

    从提供的第二张图片来看,我猜你有 1 张桌子:

    CREATE TABLE foo (
        year YEAR NULL,
        gender ENUM('male', 'female') NOT NULL,
        val SMALLINT UNSIGNED NOT NULL,
        PRIMARY KEY(year, gender)
    ) ENGINE=InnoDB;
    

    我不明白'1959-1974'的意思,但可能是

        cohort VARHAR(20) NOT NULL
    

    并在第二个表中替换gender,否则它看起来像上表。

    但是...如果不了解如何处理数据,就无法真正设计架构。有没有暂定的SELECTs

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多