Вы можете представить все необходимые условия с минимальными / максимальными значениями. Например, total > 10
может быть выражено как min_value = 11, max_value = null
.
Реалистичные таблицы будут включать таблицы ключ / значение для деталей, которые различны для каждого типа.
Таблица активности
+ ------------+--------------+---------+------------+
| activity_id | type | user_id | date |
+ ------------+--------------+---------+------------+
| 1 | user_ordered | 1 | 2020-01-01 |
+ ------------+--------------+---------+------------+
Таблица activity_detail
+ ------------+-------+-------+
| activity_id | key | value |
+ ------------+-------+-------+
| 1 | total | 100 |
| 1 | items | 2 |
+ ------------+-------+-------+
Таблица правил
+ --------+--------------+----------+------------+------------+
| rule_id | type | user_id | min_date | max_date |
+ --------+--------------+----------+------------+------------+
| 1 | user_ordered | | 2020-01-01 | 2020-01-15 |
+ --------+--------------+----------+------------+------------+
Таблица rule_detail
+ --------+-------+-----------+-----------+
| rule_id | key | min_value | max_value |
+ --------+-------+-----------+-----------+
| 1 | total | 11 | |
| 1 | items | 2 | 2 |
+ --------+-------+-----------+-----------+
Запрос
select a.*
from rule r
join activity a on a.type = r.type
and (a.user_id >= r.min_user_id or r.min_user_id is null)
and (a.date >= r.min_date or r.min_date is null)
and (a.date <= r.max_date or r.max_date is null)
where r.rule_id = 1
and not exists
(
select
from rule_detail rd
join activity_detail ad on ad.key = rd.key
where rd.rule_id = r.rule_id
and ad.activity_id = a.activity_id
and not
(
(ad.value >= rd.min_value or rd.min_value is null)
and
(ad.value <= rd.max_value or rd.max_value is null)
)
);
Альтернатива будет быть плоскими столами, где вы освобождаете место для всех возможных атрибутов:
Таблица активности
+ ------------+--------------+---------+------------+------------+------------+------------+------------+
| activity_id | type | user_id | date | total | items | name | location |
+ ------------+--------------+---------+------------+------------+------------+------------+------------+
| 1 | user_ordered | 1 | 2020-01-01 | 100 | 2 | | |
+ ------------+--------------+---------+------------+------------+------------+------------+------------+
Правило таблицы
+ --------+--------------+----------+------------+------------+------------+------------+------------+------------+------------+------------+--------------+--------------+
| rule_id | type | user_id | min_date | max_date | min_total | max_total | min_items | max_items | min_name | max_name | min_location | max_location |
+ --------+--------------+----------+------------+------------+------------+------------+------------+------------+------------+------------+--------------+--------------+
| 1 | user_ordered | | 2020-01-01 | 2020-01-15 | 11 | | 2 | 2 | | | | |
+ --------+--------------+----------+------------+------------+------------+------------+------------+------------+------------+------------+--------------+--------------+
Запрос
select a.*
from rule r
join activity a on a.type = r.type
and (a.user_id >= r.min_user_id or r.min_user_id is null)
and (a.date >= r.min_date or r.min_date is null)
and (a.date <= r.max_date or r.max_date is null)
and (a.total >= r.min_total or r.min_total is null)
and (a.total <= r.max_total or r.max_total is null)
and (a.items >= r.min_items or r.min_items is null)
and (a.items <= r.max_items or r.max_items is null)
and (a.name >= r.min_name or r.min_name is null)
and (a.name <= r.max_name or r.max_name is null)
and (a.location >= r.min_location or r.min_location is null)
and (a.location <= r.max_location or r.max_location is null)
where r.rule_id = 1;