7

我有一个 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

4 回答 4

9

看到这个问题的受欢迎程度,我将把我的实际解决方案添加到混合中,这样人们就有了一个可以工作的例子,出于某种原因,对于这样一个常见的问题,真的很难找到......

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

问题:您的数据库中有多个事实表;几乎在每个数据库中都出现过。这些事实表中的一些(或全部)共享相同的关键字段;没问题,对吧?错误的。不幸的是,由于 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 和 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];
    

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

如果您将来创建另一个事实表,只需再次执行步骤 1 和 2,并将任何新的单个键添加到链接表,并将新的连接键也添加到链接表。它可以轻松扩展。

祝你好运!

于 2014-05-21T23:47:03.157 回答
4

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

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

  2. 建立一个链接表(到目前为止你所做的) 对于大多数实现,选项 1 是合适的方法。CONCATNATED 事实的属性可以概括为:

正面:

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

负面:

  1. 不同的事实并不直接相互关联。理解的含义很重要。这意味着事实的交叉分析通常只能通过共同的维度来实现。任何事实特定维度都不会以任何方式连接到未引用这些维度的事实记录。复杂的“集合分析”语法可以在一定程度上缓解这一缺点,但如果您的核心要求是通过事实 B 的事实特定维度对事实 A 进行间接分析,那么您可能需要改为使用链接表模型。

如何构建链接表是一个复杂的主题,但依赖于传统的数据库链接表设计技术。很容易出错并生成链接表,这些链接表在前端似乎可以产生正确的结果,但过大,消耗内存和 CPU 资源。

根据我的经验,建模不佳的 QlikView 数据模型是导致性能不佳的最常见罪魁祸首。

我希望这篇关于 QlikView 中多事实建模的快速介绍(远非详尽)能证明一些帮助,并使您走上正确的道路。

于 2013-09-19T22:35:50.367 回答
2

The two quickest ways I can think of:

A) You can just left join the fact table into the corresponding tables that they are used in. You will just need to rename the fields to avoid conflicts with the other tables.

B)You can rename the common fields, which can be done by

  1. using a QUALIFY (before you load the fact tables) and UNQUALIFY (after you load the fact tables)
  2. renaming the field using "[Old Field Name] as [New Field Name]"

Assuming that the fact tables have unique id field names that can be linked to the main tables , you shouldn't have to rename anything in the main tables

I'd go with B-1, since that seems a little less of a hassle.

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;

EDIT: If you want to create a link table from these, you can concatenate the fact tables into one table where you put all the columns into it (there will be nulls for a lot of the columns, but QlikView is good with nulls).

What i usually do is load the fact tables in and create an id field (either RowNo() or autonumberhash128([list of unique id fieldnames]), then when i load them into a link table, I include that id field in the link table as well. Finally, i drop the all the common fields from the fact tables, so they only exist in the link table.

于 2013-08-20T16:00:11.530 回答
2

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

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

因此,当您按“性别”衡量时,测试分数与具有有效主题和测试代码的维度记录相匹配,而注册与具有“不适用”主题和测试代码的记录相匹配

然后,当您按性别汇总时,一切都“正常工作”。

于 2013-08-23T07:54:41.547 回答