匹配间隔和迭代加载
LOAD 或 SELECT 语句的 Intervalmatch 前缀用于链接离散数值和一个或多个时间间隔数字。此功能十分强大,如可用于生产环境。
使用 IntervalMatch() 前缀
最基本的间隔匹配是,在一个表格中有数字或日期(事件)列表,在另一个表格中有间隔列表时。目的是联接两个表格。一般情况下,这是一种多对多的关系,即间隔可以拥有属于它的多个日期,且一个日期可以属于多个间隔。要解决此问题,您需要在两个原始表格之间创建一个桥接表格。可以通过多种方法实现此操作。
在 Qlik Sense 中解决此问题的最简单方法是在 LOAD 或 SELECT 语句前面使用 IntervalMatch() 前缀。LOAD/SELECT 语句只能包含两个字段,“From”和“To”字段用于定义间隔。然后,IntervalMatch() 前缀将会生成加载间隔和之前加载数字字段之间的所有组合,用于指定为参数的前缀。
执行以下操作:
- 创建一个新应用程序并为其指定一个名称。
- 在数据加载编辑器中新增脚本段。
- 调用部分 Events。
-
在右菜单的 DataFiles 下,单击选择数据。
- 上传然后选择 Events.txt。
- 在选择数据自窗口中,单击插入脚本。
- 上传然后选择 Intervals.txt。
- 在选择数据自窗口中,单击插入脚本。
- 在脚本中,命名第一个表格事件,然后命名第二个表格 Intervals。
- 在脚本末尾添加 IntervalMatch 创建第三个表格,以桥接前面两个表格:
- 您的脚本应如下所示:
- 单击加载数据。
- 打开数据模型查看器。数据模型如下所示:
- Events 表格只能包含每个事件的一个记录。
- Intervals 表格只能包含每个间隔的一个记录。
- 桥接表格只能包含事件和间隔的每个组合的一个记录,并且用于联接前面两个表格。
BridgeTable:
IntervalMatch (EventDate)
LOAD distinct IntervalBegin, IntervalEnd
Resident Intervals;
Events:
LOAD
EventID,
EventDate,
EventAttribute
FROM [lib://DataFiles/Events.txt]
(txt, utf8, embedded labels, delimiter is '\t', msq);
Intervals:
LOAD
IntervalID,
IntervalAttribute,
IntervalBegin,
IntervalEnd
FROM [lib://DataFiles/Intervals.txt]
(txt, utf8, embedded labels, delimiter is '\t', msq);
BridgeTable:
IntervalMatch (EventDate)
LOAD distinct IntervalBegin, IntervalEnd
Resident Intervals;
包含复合关键字段(IntervalBegin 和 IntervalEnd 字段)的数据模型会将自己显示为 Qlik Sense 合成钥。
基本表格如下:
注意,如果间隔重叠,则事件可以属于多个间隔。当然,间隔也可以拥有属于它的多个事件。
从规范化和紧凑感方面来看,此数据模型是最佳模型。Events 表格和 Intervals 表格都保持不变,并包含原始数量的记录。在这些表格中进行的所有 Qlik Sense 计算操作,如 Count(EventID) 都能够正常运行,因此需要进行正确评估。
使用 While 循环和迭代加载 IterNo()
您可以使用 While 循环和 IterNo() 创建间隔的下限和上限之间的枚举值获得几乎完全相同的桥接表格。
可以使用 While 子句在 LOAD 语句内创建循环。例如:
该 LOAD 语句将针对每个输入记录进行循环并反复加载此语句,只要 While 子句中的表达式值为 True。IterNo() 函数在第一次迭代中返回“1”,在第二次迭代中返回“2”,以此类推。
您拥有间隔的主键 IntervalID,因此在脚本中的唯一区别是创建桥接表格的方式:
执行以下操作:
- 将现有 Bridgetable 语句替换为以下脚本。
- 单击加载数据。
- 打开数据模型查看器。数据模型如下所示:
- 将以下脚本添加至您脚本的末尾:
- 单击加载数据。
- 打开数据模型查看器。数据模型如下所示:
BridgeTable:
LOAD distinct * Where Exists(EventDate);
LOAD IntervalBegin + IterNo() - 1 as EventDate, IntervalID
Resident Intervals
While IntervalBegin + IterNo() - 1 <= IntervalEnd;
通常,使用三个表格的解决办法是最好的,因为它允许在间隔和事件之间存在多对多的关系。但是,一种常见的情况是您知道事件只能属于一个单一的间隔。在该情况下,桥接表格实际并不必要:IntervalID 可直接存储在事件表内。可以通过多种方法实现此操作,但最有效的方法是联接 Bridgetable 表格和 Events 表格。
Join (Events)
LOAD EventDate, IntervalID
Resident BridgeTable;
Drop Table BridgeTable;
开放和封闭间隔
间隔是开放间隔还是封闭间隔由间隔中是否包含这些端点确定。
- 如果包含端点,则该间隔为封闭间隔:
- 如果不包含端点,则该间隔为开放间隔:
- 如果包含一个端点,则该间隔为半开放间隔:
[a,b] = {x ∈ ℝ ∣ a ≤ x ≤ b}
]a,b[ = {x ∈ ℝ ∣ a < x < b}
[a,b[ = {x ∈ ℝ ∣ a ≤ x < b}
如果出现间隔重叠和数字属于一个以上间隔的情况,则通常需要使用封闭间隔。
但是,在某些情况下,您不希望重叠间隔,希望数字只属于一个间隔。因此,如果一个端点是一个间隔的结束,同时它也是下一个间隔的开始,这就形成了一个问题。拥有此值的数字将同时属于两个间隔。因此,您应使用半开放间隔。
解决此问题的一种实用的解决办法是从所有间隔的结束值中减去一个非常小的数目,从而创建封闭间隔,但间隔不重叠。如果数字为日期,则最简单的方法是使用 DayEnd() 函数返回一天的最后一毫秒:
您也可以手动减去一个小的数目。如果这样做,请确保减去的数目不能太小,因为该操作将会四舍五入到 52 位有效的二进制数(14 位十进制数)。如果您使用太小的数目,差额将不会太明显,这样将会用回原始数。