我会用一个规则表、一个条件表和一个
动作表,后 2 个具有 FK 到第 1 个。条件
表也将有一列指示要测试的字段,
表示操作符的列,以及表示值的列
将其与 ('>' 和 30 在您的示例中) 进行比较。动作表只有一个
用于指示操作的列,可能还有一个额外的列
详细信息(可能分别是“发送电子邮件”和“foo@example.com”);
这将是 jsonb 列的一个不错的候选人,因为这些操作
可能需要做各种各样的附加数据
他们的工作。
您的工作只需将条件表与最近的数据连接起来
点,可能使用 WHERE 时间戳 > 作业上次运行的时间。
SELECT actions.* FROM
data_table t
JOIN rules on rules.device_id=t.device_id
JOIN conditions on conditions.rule_id=rules.id
JOIN actions on actions.rule_id=rules.id
WHERE (
(conditions.field='temperature' and conditions.operator='>' and data_table.temperature > conditions.value)
OR (conditions.field='temperature' and conditions.operator='<' and data_table.temperature < conditions.value)
OR (conditions.field='water level' and conditions.operator='>' and data_table.water_level > conditions.value)
OR (conditions.field='water level' and conditions.operator='<' and data_table.water_level < conditions.value))
AND data_table.your_timestamp_column > '2020-07-22 10:01:02' -- the last time your job ran.
您可以将作业上次运行的时间戳存储在任何持久性中
贮存。有一张只有 job_name 和
您的作业在启动时查询以获取的 last_completion_time 列
用于时间戳比较的值,然后更新
完成时处理的 data_table 时间戳的最大值。
将字段 & 运算符映射到 SQL 表达式的 WHERE 子句将
相当大,但这种事情会很冗长
或其他。也许您可以改为使用 CASE 语句来提取
字段值,以便您拥有的子句数量与
字段数 + 运算符数而不是字段数 *
运算符的数量,例如:
SELECT
actions.* FROM (
SELECT actions, t, conditions,
CASE WHEN conditions.field='temperature' THEN t.temperature
WHEN conditions.field='water level' THEN t.water_level
END AS data_value
data_table t
JOIN rules on rules.device_id=t.device_id
JOIN conditions on conditions.rule_id=rules.id
JOIN actions on actions.rule_id=rules.id
WHERE data_table.your_timestamp_column > '2020-07-22 10:01:02'
) AS inner_1
WHERE (
(conditions.operator = '>' AND data_value > conditions.value)
OR (conditions.operator = '<' AND data_value > conditions.value)
)
但是如果 data_value 的可能字段,这将遇到问题
没有相同的类型。你可以通过一个来解决这个问题
column-per-type,然后为每种类型定义一组可用的运算符:
-- ...
CASE WHEN conditions.field='temperature' THEN t.temperature
WHEN conditions.field='water level' THEN t.water_level
END AS data_value_numeric,
CASE WHEN conditions.field='device is enabled' THEN t.device_is_enabled
END AS data_value_bool
-- ...
WHERE
(
(conditions.operator = '>' AND data_value_numeric > conditions.numeric_value)
OR (conditions.operator = '<' AND data_value_numeric > conditions.numeric_value)
OR (conditions.operator = '=' AND data_value_bool > conditions.bool_value)
)
但在这一点上,我们离杂草还很远。希望这可以
开始吧。