历史表格数据的数据库设计与查询

时间:2018-05-18 00:03:40

标签: php mysql database database-design

我有一组HTML表格,可以存储调查问题和响应。每个问题都有自己的HTML表,列是年份,行是响应,然后单个单元格具有该年份的响应数,如下所示:

enter image description here

我已经来回了解如何规范化这些数据并将其存储在数据库中,但我不确定最佳方法是什么。我正在寻找一个好的数据库架构,可以随着时间的推移处理其他问题,响应和年限。我还在寻找一个可以输出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

非常感谢任何帮助或改进。

3 个答案:

答案 0 :(得分:0)

您不需要表year,因为 问题 - 独立。

并改变表格data

  • year_id int(11) unsigned FKyear SMALLINT(4) UNSIGNED

  • UNQ (year_id + response_id)UNQ (year + response_id)

答案 1 :(得分:0)

一般来说,如果你有一个UNIQUE密钥(就是'UNQ'的含义?),请使用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吗?

答案 2 :(得分:0)

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

以下是'逻辑',并且会与每个kimball et. al.的事实表中的属性/维度相关联,其中事实表的'grain'是'src html file + table + row + cell + value (s)',假设您的值随时间变化一致

  • (我在图片中注意到一个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文件的年份)

  • 值1 .. n 必须计算相同的内容,否则您需要将它们拆分

要生成合适的输出,您需要在数据表上最终确定问题,但无论您做什么,使用php导出html都相对简单

我想到了将数据加载到mysql中的方法,但是没有作为数据源的html文件的实体样本,很难编写特定代码(即在浏览器中打开并查看源代码) '或同等的)

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

在这种情况下,'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;
  }
}

?>