关于规则的实用提示和最佳实践
为了帮助你为研究创建规则,本页列出了各种提示和最佳实践。有关规则创建的说明,请参考创建规则。
规则详细信息(属性)
规则描述
- 使用简短而完整的句子。
- 明确指示规则的意图,包括所有参数。
- 添加表单和事件时,输入关于规则运行方式的描述
- 示例:受试者是否符合全部资格标准?如果是,则添加治疗事件组(egTREAT)
- 对于查询规则,请确切指示需要如何处理值,“……大于或等于”还是“……大于”
- 示例:“结束日期在开始日期之前。”还是“结束日期在开始日期当天或之前。”
- 添加表单和事件时,输入关于规则运行方式的描述
- 请记住,测试人员将根据描述进行测试,以确定规则是否通过
- 在描述中使用条目标签,因为它们会生成研究规范,例如,使用“开始日期”而不是“AESTDAT”。
规则范围 & 动态操作
请始终确保在必要时选择在事件组内(Within Event Group)作为规则范围(Rule Scope)。这是对规则未按预期触发进行问题排查的常见原因。
发送电子邮件规则
在创建发送电子邮件 规则时,请始终使用令牌,因为 Vault 不会存储电子邮件规则的规则执行数据。
评估缺失数据(空白处理)
最佳实践:条目 的必填(Required)属性会创建一个系统生成的规则(单变量),每当该条目 留空时,该规则即会触发。将此规则用作缺失数据的主要检查。
对于用户定义的规则,请在表达式中包含逻辑以确认数据未缺失。如果忘了考虑缺失数据的情况,则可能会遇到服务器错误、重复查询或其他意外行为。
请包含 Not(IsBlank(ITEM))
以确认数据未缺失或不为空。
在评估数字字段时,必须使用规则编辑器中的空白处理(Blank Handling)属性来选择 Vault 处理空白值的方式。你可以在以下选项之间进行选择:
- 为零(As zero):Vault 将空白值替换为零,以继续完成公式计算。
- 为空(As null):Vault 将空白值视为空,导致整个表达式返回空/空白值。
表达式 & 逻辑
#define
语句应使用条目的确切名称 或尽可能接近确切的名称来标识变量,以提高标识和复制效率。- 如果条目的名称 以下划线(_)开头,则必须重命名变量以移除
#define
语句中的下划线,否则将发生语法错误。 - 如果需要进一步明确,请使用
/* ...*/
以在规则顶部添加备注。必须在规则表达式的顶部添加这些备注,否则将无法保存规则。 - 考虑到在研究进行期间可能需要另一位研究设计者。表达式中妥善命名的条目有助于明确规则并减少修订期间的工作量。
- 使用空格和换行符来帮助明确规则。
在此处,研究设计者选择添加额外的行来分解逻辑的不同部分。他们还为表达式的每个逻辑片段使用单独的行,同时用额外的空格对齐运算符。
时区
以下最佳实践适用于规则中的时区:
- 使用
DateValue
时,请始终包含@Site.timezone__v
参数。这可确保 Vault 使用研究中心的时区返回日期。或者,你可以指定自己选择的时区。参见此列表中的时区输入格式。 - 将日期和时间加在一起返回日期时间时,运算符
+
会使用用户的时区。要使用研究中心的时区执行此运算(推荐用于 CDMS),请使用StartOfDate(date, @Site.timezone__v) + time
。
设置条目值和设置派生值规则
设置派生值 规则将 22R3 Release 中的设置条目值 替换为跨表单派生 功能。
因此,你不能在同一研究中使用设置条目值 规则和设置派生值 规则,因此无法将规则从使用一种规则类型的研究复制到包含另一种规则类型的研究中,反之亦然。
设置条目值 和设置派生值 规则都要求使用 @Form
浮动标识符(也称为“通配符标识符”)。由于这些规则类型使用 @Form
浮动标识符,因此你应该将规则操作限定为同一级别。
日期比较规则
最佳实践:要将日期条目 与其他日期条目 进行比较,我们建议尽可能使用日期比较配置器。
日期时间与日期
下面的两个示例显示了如何将日期时间类型条目 与事件日期 的值进行比较。此语法适用于任何日期/日期时间比较。
日期时间条目 不允许未知部分:
Not(IsBlank(DTC)) && Not(IsBlank(EVDAT)) && DateValue(DTC, @Site.timezone__v) != EVDAT
允许未知部分的日期时间条目:
Not(IsBlank(EVDAT)) && Not(IsBlank(VSDTC)) && If(Right(VSDTC , 4) = "UNKZ", DateValue(MinDateTime(VSDTC), 'UTC'), DateValue(MinDateTime(VSDTC), @Site.timezone__v)) != EVDAT
当你使用 =
将日期与日期时间进行比较时,Vault 会使用 Vault 的时区将日期时间转换为日期。如果你想改用研究中心的时区,请使用 DateValue({datetime}, @Site.timezone__v)
。
日期时间与日期 & 时间
将日期条目和时间条目加在一起以创建日期时间(DateItem + TimeItem
)时,请使用 StartOfDay(Date, @Site.timezone__v)
,然后向其添加时间值。与日期一起使用时,StartOfDay
会返回 00:00
。
以下示例检查实验室采集日期时间是否为口腔暴露开始日期和开始时间后 8 小时 +/- 30 分钟。它参考了以下研究设计:
- LBDTC:实验室面板表单 上的日期时间类型条目
- EXSTDAT:日期类型条目
- EXSTTIM:与 EXSTDAT 位于同一表单 上的时间类型条目
请注意,由于此示例使用 @Form
浮动标识符(也称为“通配符标识符”),因此在大多数情况下,规则操作应限定为同一级别。
#define LBDTC @Form.LBHEADER.LBDTC #define EXSTTIM $eg_MAINC1.ev_VISIT1.EXOR.ig_EXOR.EXSTTIM #define EXSTDAT $eg_MAINC1.ev_VISIT1.EXOR.ig_EXOR.EXSTDAT Not(IsBlank(LBDTC)) && Not(IsBlank(EXSTTIM)) && Not(IsBlank(EXSTDAT)) && Not(InWindow( LBDTC, StartOfDay(EXSTDAT, @Site.timezone__v) + EXSTTIM, Minutes(450), Minutes(510), false, false )) Rule Details Form: Lab
未来日期规则
最佳实践:我们建议你只需在事件 或条目 属性(Properties)面板的编辑检查(Edit Checks)部分中选择未来日期(Future Date)属性,即可检查未来日期。选中此复选框后,每当研究中心用户输入一个未来日期(基于研究中心用户的时区)时,Vault 都会打开一个查询。
如果你需要自定义规则来检查未来日期,请在表达式中使用 DateValue(Now(), @Site.timezone__v)
。Now()
和 Today()
以及 DateValue()
等函数将返回已转换为 UTC 格式的日期。协调世界时(UTC)是基于 0° 经线子午线的标准化时间。
对于日期和时间不在 UTC 的任何国家/地区(例如意大利、南非、澳大利亚),如果未包含 @Site.timezone__v
,这可能会导致规则意外触发。作为最佳实践,通过使用 @Site.timezone__v
,它将返回重新转回为研究中心时区的值,并确保规则按预期触发。
将事件日期与日期条目进行比较
研究设计者可能会尝试使用 @Event.event_date__v
作为浮动标识符,以涵盖更多事件 并编写更少的规则。但是,与 @Form
不同的是,事件 不是相互结构。修改特定事件日期 时,不会重新评估具有 @Event.event_date__v
的规则。
作为最佳实践,在比较事件日期($EventGroup.Event.event_date__v
或 @EventGroup.Event.event_date__v)时,请使用完全限定的事件标识符,并为每个事件实例编写一个规则。
例如,如果用户在完成事件 中定义的表单 后更正了事件日期,则不会重新评估如下所示的规则。
#define EVDAT @Event.event_date__v #define DAT @Form.ig_VS.VSDAT EVDAT != DAT
以下示例显示了完全限定的事件日期 标识符与不允许部分(未知)日期的日期条目 的比较操作:
#define QSDAT @Form.QS.QSDAT #define EVDAT $FOLLUP.V7.event_date__v Not(IsBlank(QSDAT)) && Not(IsBlank(EVDAT)) && QSDAT > EVDAT Rule Details Form: QS
以下示例将完全限定的事件日期 标识符与允许未知时间的日期时间类型条目 进行比较。此表达式代表一个查询 操作规则,当评估日期和时间(EGDTC)条目与该表单 的事件日期 不同时,该规则将打开查询。
#define EVDAT $FOLLUP.FOLLUP.event_date__v #define EGDTC $FOLLUP.FOLLUP.ECG.ig_ECG.EGDTC Not(IsBlank(EVDAT)) && Not(IsBlank(EGDTC)) && If( Right(EGDTC, 4) = "UNKZ", DateValue(MinDateTime(EGDTC), 'UTC'), DateValue(MinDateTime(EGDTC), @Site.timezone__v) ) != EVDAT
@Event 的其他用例有哪些?
使用 @Event
引用同一事件 中的其他表单。例如,如果必须在同一事件中的给药(EX)表单的一定时间内采集生命体征,你可以使用 @Event.FORM.IG.ITEM
来引用其他表单。以这种方式编写表达式使规则可在多个事件中重复使用。
#define VSDTC @Form.VSTPT2.VSDTC #define EXSTDTC @Event.EX.EX.EXSTDTC Not(IsBlank(VSDTC)) && Not(IsBlank(EXSTDTC)) && Not(InWindow(VSDTC, EXSTDTC, Minutes(5), Minutes(10), false, false)) Rule Details Form: VS
时间与时间(时间比较规则)
静态时间点
示例:当输入的时间在中午 12:00 之后时触发质疑
TIM1 > Time(12,0,0)
比较两个时间
Time - Time
返回两个时间之间的分钟数。
这些规则以语句(TimeA - TimeB > #
)的形式编写,其中计算结果以数字形式返回 TimeA
和 TimeB
之间的分钟差值。
示例:给药结束时间等于或晚于给药开始时间
EXENTIM - EXSTTIM >= 0
示例:输液结束时间在输液开始时间后超过 12 小时(注意:12 小时 X 60 分钟 = 720 分钟)
EXENTIM - EXSTTIM > 720
此示例还可以通过将条目与计算分钟数的表达式进行比较来编写。
EXENTIM - EXSTTIM > 12*60
不支持直接比较:Vault 不支持时间之间的直接逻辑比较,例如 Time + Time
, Time = Time
或Time (any logical operator) Time
。Vault 也不支持 Time + Number
或 Time - Number
。
具有 DateValue 的规则
使用 DateValue()
函数编写规则时,请始终使用 `DateValue(
事件日期规则 & 没有发生
请务必考虑方案是否允许受试者缺少一个事件 并继续下一个事件。同样,务必要考虑检查事件日期 的规则,根据这些规则,研究中心可能会将事件 标记为没有发生(Did Not Occur)。
你可能已经熟悉如何在规则的表达式中使用 Not(IsBlank())
函数来确认输入了日期。你可以将此功能扩展到检查研究中心是否将事件标记为没有发生,方法是检查事件更改原因($EventGroup.Event.change_reason__v
)的输入。Vault 在此处记录研究中心为事件没有发生选择的原因。
以下示例明确检查了没有发生 的原因:
#define EVDAT $TX.DAY9.event_date__v #define EVDNO $TX.DAY9.change_reason__v Not(IsBlank(EVDAT)) || EVDNO = "Subject missed event"
在此规则表达式中(与添加事件 规则一起使用),我们检查了更改原因,如果更改原因 为“受试者错过事件(Subject missed event)”,则允许显示下一个事件。如果研究中心改为选择“受试者提前终止(Subject early terminated)”,则此规则不会添加下一个事件。
请务必确认研究 Vault 中可用的更改原因 的确切文本。这些文本必须完全匹配才能正确评估规则。你可以从工具(Tools)> 系统工具(System Tools)> 更改原因(Change Reasons)查看可用原因(标准和自定义)。
布尔值条目(复选框)的规则
未设置为 true 或 false 的布尔值条目(复选框)被视为空白(“未确定”)。当研究中心从不选中复选框而不是选中然后取消选中复选框时,可能会发生这种情况。规则表达式中的适当逻辑将有助于确保按预期评估适当的场景。最佳实践是在规则表达式中将布尔值明确设置为 = true
或 = false
。
在评估一组全部留空的布尔值时,请包含适当的定义语句。考虑表单/条目何时标记为“特意留空(ILB)”以及你需要规则如何工作。
在以下示例中,规则检查是否输入了原因 以及是否选中了一个或多个复选框。
#define ND1 @Form.ig_V1.V1ND #define ND2 @Form.ig_V2.V2ND #define ND3 @Form.ig_V3.V3ND #define ND4 @Form.ig_V4.V4ND #define REAS @Form.ig_V5.VREAS Not(IsBlank(REAS)) && (ND1 = true || ND2 = true || ND3 = true || ND4 = true)
在评估一组条目或复选框是否留空时,请在定义语句中包含“特意留空(ILB)”,以根据需要评估表单或条目是否标记为 ILB。这将确保规则不会意外触发。
#define AENONE @Form.AE.AENONE #define AEMED @Form.AE.AEMED #define AEACNOTH @Form.AE.AEACNOTH #define AETRANS @Form.AE.AETRANS #define FORMILB @Form.intentionally_left_blank__v FORMILB = false && ( AENONE = false && AEMED = false && AEACNOTH = false && AETRANS = false ) Rule Details Form: Adverse Events
这通常适用于与不良事件或问卷和医疗器械表单相关的规则,以评估是否未选中任何“选中所有符合的选项”复选框。此逻辑适用的一些常见规则包括:
- 没有为“种族”选择任何选项。选中所有符合的选项
- 所采取的 AE 操作:选择了“无”,同时还选择了“药物”[等]。请更正。
年龄规则
以下规则示例计算和查询年龄,考虑闰年:
年龄派生(设置条目值)
此示例规则表达式根据在人口统计信息 表单中输入的数据派生受试者的年龄。由于此表达式使用 @Form
浮动标识符(也称为“通配符标识符”),因此必须在规则详细信息(Rule Details)面板中选择引用的表单。在大多数情况下,规则操作应限定为与标识符相同的级别。例如,选择设置条目值(Set Item Value)操作并选择此表单(this form)> ig_DM > 年龄(Age)
#define BRTHDAT @Form.ig_DM.BRTHDAT #define RFICDAT @Form.ig_DM.RFICDAT If(BRTHDAT > RFICDAT - Years((Year(RFICDAT) - Year(BRTHDAT))), (Year(RFICDAT) - Year(BRTHDAT)) - 1, (Year(RFICDAT) - Year(BRTHDAT)) ) Rule Details Form: Demographics
年龄查询(查询是否未满 18 岁)
#define BRTHDAT $eg_SCREEN.ev_SCREEN.DM.ig_DM.BRTHDAT #define EVDAT $eg_SCREEN.ev_SCREEN.event_date__v Not(IsBlank(EVDAT)) && Not(IsBlank(BRTHDAT)) && ((EVDAT - MaxDate(BRTHDAT)) / 365.25) < 17.998
使用规则构建研究计划
研究设计者可以使用规则将表单、事件 和事件组 动态添加到研究计划。
在下面的示例中,规则将评估事件组 的序列号,以在特定事件序列处添加规则操作中配置的表单。这些示例表达式使用求余运算符。请务必确认正确的序列号,因为它们与重复事件组中配置的标签相关。它们也可以在工作室生成的研究设计规范的计划树(Schedule Tree)选项卡中引用。
请注意,由于这些示例使用浮动标识符(也称为“通配符标识符”),因此在大多数情况下,应在规则操作中使用相同的标识符,并且规则表达式和规则操作都应限定为同一级别。
对于下面的所有示例,请在规则操作中选择“此事件组(this event group)”,以匹配规则表达式的 #define 语句中的 @EventGroup
浮动标识符。这将确保系统仅将 FORM1 添加到规则表达式评估为 true 的事件组。
在示例 1 中,规则表达式评估重复事件组的序列号,以确定它是否为奇数。然后,研究设计者可以配置规则操作,以便在表达式评估为 true 时将 ECOG 表单添加到指定事件组内的事件中。
示例 1:将表单添加到周期中的所有奇数事件
#define EVDAT @EventGroup.ev_D1.event_date__v #define EVSEQ @EventGroup.sequence__v Not(IsBlank(EVDAT)) && ( EVSEQ = 1 || EVSEQ % 2 = 1 ) Rule Action: Add Form: 'this event group' > ev_D1 > FORM1
在示例 2 中,规则表达式评估重复事件组的序列号,以确定它是否为偶数。然后,研究设计者可以配置规则操作,以便在表达式评估为 true 时将所需表单添加到指定事件组内的事件中。
示例 2:将表单添加到周期中的所有偶数事件
#define EVDAT @EventGroup.ev_D1.event_date__v #define EVSEQ @EventGroup.sequence__v Not(IsBlank(EVDAT)) && EVSEQ % 2 = 0 Rule Action: Add Form: 'this event group' > ev_D1 > FORM1
你还可以编写规则来评估周期中的事件组的序列号。在示例 3 中,规则表达式评估重复事件组的序列号,以确定是否为从第 2 个周期开始的重复事件的每三个周期。
示例 3:将表单添加到周期中的每第 n 个事件
#define EVDAT @EventGroup.ev_D1.event_date__v #define EVSEQ @EventGroup.sequence__v Not(IsBlank(EVDAT)) && (EVSEQ + 1) % 3 = 0 Rule Action: Add Form: 'this event group' > ev_D1 > FORM1
查询消息
- 明确提及问题和解决方法选项。实事求是,避免使用具有引导性或可能给数据带来偏见的消息。
- 避免使用特殊字符,因为它们可能无法在导出文件中正确显示:
- 例如,拼写出大于或等于,而不是使用“> 或 =”
- 使用自然键盘中的字符。不要使用可能影响下游系统或应用程序的 Alt+ 键或符号。
- 使用单引号引用回答(示例:受试者是否已入组?回答为‘否’且……)。
- 避免使用双引号。
- 查询消息的字符数限制为 500 个。
使用浮动标识符(@Form、@Event、@EventGroup)的规则
自 20R1(2020 年 4 月)起,对于使用浮动标识符(如 @Form
(也称为“通配符标识符”))的任何新规则,Vault 会在每次提交已标识的表单时自动评估规则。
相互结构规则
当规则表达式引用来自多个表单 的数据时,即使同时使用了 @
和完全限定标识符,Vault 也会在提交规则详细信息面板中选择的表单 时评估规则,并且每次规则表达式中引用的任何表单 上的数据发生更改时,也会重新评估规则。此过程称为相互结构规则。例如,如果你使用 @Form
指向在多个事件 中使用的Vitals 表单,并且还使用完全限定标识符指向 PE 表单,则 Vault 将在每次提交 Vitals 表单或特定 PE 表单时运行规则并评估指向的研究 对象中的数据。
如果你在规则详细信息面板中选择的表单是重复且完全限定的,则 Vault 将评估每个表单 实例上的规则。
完全限定与浮动标识符格式
在规则表达字段中输入标识符时使用的格式向系统指示你使用的是完全限定标识符还是浮动标识符(也称为通配符标识符)。
在大多数情况下,完全限定标识符以美元符号($
)开头,这向系统表示你正在完全限定对研究对象的引用。
完全限定标识符格式示例:
$EVENTGROUP.EVENT.FORM.ITEMGROUP.ITEM
浮动标识符始终以 at 符号(@
)开头,这向系统指示你希望它基于上下文查看指向的研究对象。
浮动标识符格式示例:
@EventGroup.EVENT.FORM.ITEMGROUP.ITEM, @Event.FORM.ITEMGROUP.ITEM, or @Form.ITEMGROUP.ITEM
在规则操作中,“@
”表示为“此事件”、“此事件组”或“此表单”。
使用浮动标识符:在大多数情况下,如果在规则表达式中使用浮动标识符(也称为“通配符标识符”),则应在规则操作中使用相同的标识符,并且规则表达式和规则操作都应限定为同一级别。这可确保规则操作和规则表达式的范围限定为病例手册 中的相同对象实例。否则,规则操作可能会影响意外的表单。
当规则包含完全限定的重复事件组、事件 或表单 时,Vault 会查看与该标识符匹配的每个实例。因此,建议不要对重复对象使用完全限定标识符,除非希望针对所有对象执行规则。
如果需要使用非相互结构行为(20R1 之前)创建新规则,请与你的 Veeva 服务代表合作完成。
在 23R2 版本中避免使用 @Form 导致的错误:自 23R2 起,对于使用 @Form
或“此表单”标识符的规则,当规则详细信息面板中的关联表单与标识符不匹配时,必须修复或停用这些规则,以避免验证错误。
优化规则排列组合的最佳实践
使用重复表单上的聚合编写规则时,请使用 聚合标识符 [*]
。
使用聚合标识符的示例 #define
语句:
#define AEOUT $LOGS.LOGS.AE[*].igAE.AEOUT
在编写引用重复表单和事件组的规则时,请使用 @Form
或 @EventGroup
浮动标识符(也称为“通配符标识符”)以防止过多的排列组合。
测试建议
最佳实践:典型的单元测试至少包括使每个规则打开(创建)并解决查询一次的测试。彻底测试一个规则(类似于完整验证),然后通过复制该规则创建类似的规则,这种做法可以帮助你提高规则质量并减少配置返工和重新验证工作。
无论是进行单元测试还是更正式地验证规则,请考虑以下最佳实践:
- 包括范围内的值和超出范围的值。这包括数值、日期和日期时间窗口
- 包括针对所有情况测试规则的触发条件和解决条件。
- 从代码列表中确认每个场景。
- 对于跨表单查询,包括的测试应显示规则在第一个表单和第个表单都完成(向前和向后)后按预期创建和解决查询。
- 如果规则引用重复条目组 中的条目,请验证该规则是否在条目组 的正确序列(实例)中打开并解决对条目 的查询。
- 对日期时间内、等于日期时间和日期时间之外的窗口进行测试。
- 测试“第二天”场景。选择一个位于窗口内但在下一个日历日的时间。
- 根据条目的掩码属性测试未知(UNK)时间、日期和月份。
- 设置具有适用时区的研究中心,以便在从各个研究中心位置输入数据时进行规则测试
- 在 TST 中添加一些测试研究中心,用来代表研究中包含的国家/地区的预期时区样本。
- 设置研究中心以及分配给该研究中心的 TST 测试用户的时区。
- 根据研究进行的情况酌情测试时间窗口规则。例如,如果较长的 IV 输液会导致结束时间或预期的心电图,或 PK 时间窗口接近午夜。
- 考虑一种基于风险的测试方法,通过对代码的同行评审提高质量并减少用户验收测试中的发现。