在Qlikview中处理多个事实表

时间:2013-08-20 14:12:25

标签: database database-design data-warehouse qlikview dimensional-modeling

我有一个PostgreSQL数据库,其中包含各种教育数据,如学校级别的考试成绩和入学人数。我需要将注册与测试分数分开,因为数据是在不同的谷物上。即使注册与测试分数数据的粒度不同,但许多维度都是相同的。例如,我有:

~ ---------------------------------------------------------------------------------~
| Test Scores Fact                                                                 |
|-------------|-----------|----------|-----------|--------------|------------|-----|
| school_code | test_code | grade_id | gender_id | ethnicity_id | subject_id | ... |
|-------------|-----------|----------|-----------|--------------|------------|-----|

~ --------------------------------------------------------~
| Enrollment Fact                                         |
|-------------|----------|-----------|--------------|-----|
| school_code | grade_id | gender_id | ethnicity_id | ... |
|-------------|----------|-----------|--------------|-----|

这种结构在后端很好,但在Qlikview中,这会创建一个合成密钥。合成密钥的解决方案似乎通常是通过Qlikview脚本来替换它的链接表,这也是我的方法。但这似乎没有扩展,因为当我添加第三个事实表(在另一个粒子上)包含更多相同的维度时,如果我创建另一个链接表,现在我的两个链接表开始关联,因为它们通常包含几个命名字段,Qlikview的回应是创建更多的合成密钥?

我对Qlikview比较陌生,我自己也在工作。如何处理具有共同尺寸的不同颗粒的多个事实?

编辑:

我已经为这个问题提供了解决方案,这个问题已经在生产环境中工作了不到一年!请参阅下面的答案......

4 个答案:

答案 0 :(得分:7)

看到这个问题的受欢迎程度,我将添加我的实际解决方案,以便人们有一个工作的例子,由于某种原因很难找到这样一个常见的问题...

我继续创建链接表。这个解决方案至今仍然像一个黑客,因为它创建了一个巨大的表,其中包含所有事实表中每个键的笛卡尔积...但它确实有效。

问题:您的数据库中有多个事实表;几乎每个数据库都出现过一次。这些事实表中的一些(或全部)共享相同的关键字段;没问题,对吧?错误。不幸的是,由于Qlik的关联性质,而不是每个事实表都很好地链接到他们的查找表,你的事实表现在彼此关联并对你的数据模型造成严重破坏;创建循环引用和无数量的合成键。

解决方案:创建链接表。听起来很简单吧?嗯,确实如此,但如果没有初步解释,它也很难记录并且难以理解。您可能想知道......什么是链接表?它是所有事实表中所有键的笛卡尔积。这如何解决问题?它会删除事实表之间的所有不需要的关联,因为每个事件表现在只包含一个唯一的连接键。这些唯一键仅与链接表关联,其中包含所有唯一的连接键以及所有单独的键。随后链接表将与您的查找表相关联,并且一切都会很好。

<强>实施

此实现将使用上述问题中包含的两个表; test_scores_factenrollment_fact

test_scores_fact     |    enrollment_fact      |    school            |    gender         |   ...
----------------     |    ---------------      |    ------            |    ------         |   ---
school_code (FK)     |    school_code (FK)     |    school_code (PK)  |    gender_id (PK) |
test_code (FK)       |    grade_id (FK)        |    school_name (FK)  |    gender_desc    |
grade_id (FK)        |    ethnicity_id (FK)    |    address           |    ...            |
gender_id (FK)       |    gender_id (FK)       |    ...               |
ethnicity_id (FK)    |    number_enrolled (F)  | 
subject_id (FK)      |
test_score (F)       |

FK = Foreign Key
PK = Primary Key
F = Fact

如您所见,这两个事实表具有重叠的键school_codegrade_idgender_idethnicity_id。在关系模型中,每个关键字段都有一个对应的表,其中包含有关密钥的其他信息。由于Qlikview根据字段的名称关联表格,因此该模型不符合Qlikview的关联性质;即使你不想要它。您确实希望命名字段与其查找表关联,但是您不希望事实表中的命名字段与关联。不幸的是你无法阻止这种行为。您必须实现链接表...

  1. 在Qlikview脚本中,创建一个临时事实表,该表加载到数据库表的所有字段中:

    [temp_test_scores]:
    LOAD school_code,
         test_code,
         grade_id,
         gender_id,
         ethnicity_id,
         subject_id,
         test_score;
    SQL SELECT * FROM <database connection>
    
  2. 连接密钥并删除所有单独的密钥:

    [test_scores]:
    LOAD school_code & '_' test_code & '_' grade_id & '_' gender_id & '_' ethnicity_id & '_' subject_id as test_key,
         test_score
    RESIDENT [temp_test_scores];
    
  3. 重复步骤1&amp;每个事实表2:

    [temp_enrollment]:
    LOAD school_code,
         grade_id,
         ethnicity_id,
         gender_id,
         number_enrolled;
    SQL SELECT * FROM <database connection>
    
    [enrollment]:
    LOAD school_code & '_' & grade_id & '_' & ethnicity_id & '_' & gender_id as enrollment_key,
         number_enrolled
    RESIDENT [temp_enrollment];
    
  4. 通过将各个密钥连接到一个表中来创建链接表:

    [temp_link_table]:
    LOAD DISTINCT
        school_code,
        test_code,
        grade_id,
        gender_id,
        ethnicity_id,
        subject_id
    RESIDENT [temp_test_scores];
    
    CONCATENATE ([temp_link_table])
    LOAD DISTINCT
        school_code,
        grade_id,
        ethnicity_id,
        gender_id,
        number_enrolled
    RESIDENT [temp_enrollment];
    
    /**
     * The final Link Table will contain all of the individual keys one time as well as your concatenated keys
     */
    [link_table]:
    LOAD DISTINCT
        school_code,
        test_code,
        grade_id,
        gender_id,
        ethnicity_id,
        subject_id,
        school_code & '_' test_code & '_' grade_id & '_' gender_id & '_' ethnicity_id & '_' subject_id as test_key,
        school_code & '_' & grade_id & '_' & ethnicity_id & '_' & gender_id as enrollment_key
    RESIDENT  [temp_link_table]
    
  5. 删除临时表,使它们不会出现在您的数据模型中:

    DROP TABLE [temp_test_scores];
    DROP TABLE [temp_enrollment];
    DROP TABLE [temp_link_table];
    
  6. 这将删除事实表之间的所有关联,因为它们之间现在不存在公共字段名称。每个事实表将通过创建的连接密钥链接到链接表。然后,链接表将与每个单独的查找表相关联。您的Qlikview数据模型不包含任何合成密钥或循环引用。

    如果您将来创建另一个事实表,请按照步骤1&amp;再次2,并将任何新的单个密钥添加到链接表,并将新的连接密钥添加到链接表。它可以轻松扩展。

    祝你好运!

答案 1 :(得分:4)

在QlikView中建模数据有两种主要策略来处理多个事实表:

  1. 通常将您的事实表附加到一个事实表中 作为QlikView的语法称为CON​​CATENATED FACT 将数据附加到表是使用CONCATENATE前缀( 相当于SQL UNION操作)

  2. 建立一个链接表(到目前为止你做了什么)对于大多数人来说 实现,选项1是适当的方法。 a的属性 连带事实可概括为:

  3. 肯定:

    1. 由于数据模型中大表数量减少而表现良好
    2. 易于实现,只需将所有数据附加到一个通用事实表,同时确保通用字段名称引用通用维度
    3. 否定:

      1. 不同的事实并非直接相关。理解这一含义很重要。这意味着事实的交叉分析通常只能通过共同维度来实现。任何特定事实的维度都不以任何方式连接到不参考这些维度的事实的记录。复杂的“集合分析”语法在某种程度上可以缓解这一缺点,但如果您的核心要求是通过事实B的事实特定维度对事实A进行间接分析,那么您可能需要转而使用链接表模型。
      2. 如何构建链接表是一个复杂的主题,但依赖于传统的数据库链接表设计技术。很容易出错并生成链接表,这些表可能在前端产生正确的结果但是过大,消耗内存和CPU资源。

        根据我的经验,建模不佳的QlikView数据模型是造成性能不佳的最常见原因。

        我希望QlikView中的多事实建模的这一快速,非详尽的介绍可以为您提供一些帮助,并为您提供正确的课程。

答案 2 :(得分:2)

我能想到的两种最快捷的方式:

A)您可以将事实表连接到它们所使用的相应表中。您只需要重命名字段以避免与其他表冲突。

B)您可以重命名公共字段,可以通过

完成
  1. 使用QUALIFY(在加载事实表之前)和UNQUALIFY (在加载事实表之后)
  2. 使用“[旧字段名称]作为[新字段名称]”
  3. 重命名字段

    假设事实表具有可以链接到主表的唯一id字段名称,则不必重命名主表中的任何内容

    我会选择B-1,因为这似乎不那么麻烦。

    QUALIFY
    A,
    B,
    C,
    ID;
    
    FactTable1:
    Load ID,
    A,
    B,
    C,
    From [FactTable1];
    
    FactTable2:
    Load ID,
    A,
    B,
    C,
    From [FactTable2];
    
    UNQUALIFY
    A,
    B,
    C,
    ID;
    
    编辑:如果你想从这些链接表创建一个链接表,你可以将事实表连接到一个表中,你将所有列放入其中(很多列都会有空值,但QlikView很适合空值)。

    我通常做的是加载事实表并创建一个id字段(RowNo()或autonumberhash128([唯一id字段名列表]),然后当我将它们加载到链接表中时,我包含该id字段最后,我从事实表中删除了所有公共字段,因此它们只存在于链接表中。

答案 3 :(得分:2)

  

但是,每个事实表都有“共享”字段的不同子集,因此我无法正确键入事实表。

笛卡尔维度的输入之一是针对主题和测试代码的'N / A'(因为它不在注册表中)

因此,当您按“性别”进行衡量时,“测试分数”与具有有效主题和测试代码的维度记录匹配,并且“注册”与“N / A”主题和测试代码的记录匹配

然后,当你按性别卷起时,每次都能很好地工作。