我正在尝试从数据库读取配置条目,该数据库具有由 ID 0 定义的基本“项目”和基本“机器”。基本配置(键 + 值)可以被更具体的项目和机器覆盖。我在 MariaDB 上使用 HeidiSQL。
项目_id | 机器_id | 钥匙 | 价值 | 解读 |
---|---|---|---|---|
0 | 0 | Uc_max | 5000 | 机器 2 和项目 2 |
1 | 0 | Uc_max | 4000 | 机器 2 和项目 1 |
0 | 1 | Uc_max | 10000 | 机器 1 和项目 2 |
1 | 1 | Uc_max | 15000 | 机器 1 和项目 1 |
0 | 2 | Uc_max | 20000 | 机器 2 和项目 1 |
编辑1:
解释栏仅显示一种可能的解释方式。该表的想法是仅定义那些需要的更具体的值。所有未指定的组合都应默认为基础项目/机器。所以例如project_id 0 和 machine_id 0 的条目也对 project_id 7 和 machine_id 9 有效。最后一个条目(project_id 0 和 machine_id 2)对机器 2 和所有项目都有效。
我从以下最小示例表开始:
DROP TABLE IF EXISTS `overwrite`;
CREATE TABLE IF NOT EXISTS `overwrite` (
`id` int(11) NOT NULL,
`project_id` int(11) NOT NULL,
`machine_id` int(11) NOT NULL,
`key` char(50) NOT NULL DEFAULT '',
`value` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
DELETE FROM `overwrite`;
INSERT INTO `overwrite` (`id`, `project_id`, `machine_id`, `key`, `value`) VALUES
(0, 0, 0, 'Uc_max', 5000),
(1, 1, 0, 'Uc_max', 4000),
(2, 0, 1, 'Uc_max', 10000),
(3, 1, 1, 'Uc_max', 15000),
(4, 0, 2, 'Uc_max', 20000);
通过我当前的查询,我可以正确读取前四个条目。不幸的是,当我尝试读取项目 1 和机器 2 的配置时,没有显示任何条目。由于项目 1 的条目不存在,因此应默认为 0 并返回 ID 为 4 的条目。
SELECT o.`id`, o.`project_id`, o.`machine_id`, o.`key`, o.`value`
FROM overwrite o
LEFT JOIN (
-- get all keys, for specific project_id
SELECT DISTINCT o1.`key`
FROM overwrite o1
-- insert specific project_id here
WHERE o1.`project_id` = 1
) subquery_project ON o.`key` = subquery_project.`key`
LEFT JOIN (
-- Get all keys for specific machine_id
SELECT DISTINCT o1.`key`
FROM overwrite o1
-- insert specific machine_id here
WHERE o1.`machine_id` = 2
) subquery_machine ON o.`key` = subquery_machine.`key`
-- always read entries for 0, replace second ID with specifc project / machine
WHERE o.`project_id` IN (0, 1)
AND o.`machine_id` IN (0, 2)
AND (
-- If project_id is 0, include only if there is no more specific projects entry
(o.`project_id` = 0 AND subquery_project.`key` IS NULL)
-- Always include more specific project entries
OR o.`project_id` = 1
)
AND (
-- If machine_id is 0, include only if there is no more specific machine entry
(o.`machine_id` = 0 AND subquery_machine.`key` IS NULL)
-- Always include more specific machine entries
OR o.`machine_id` = 2
)
我明白,在这种情况下, subquery_project.
key
不会为空并导致问题。我仍然不知道如何修改查询或创建一个不同的查询,但效果很好。
编辑2: 我想保存和检索特定项目的配置,但也想仅在特定项目没有覆盖时才考虑全局配置 (project_id = 0)。这样,只有覆盖和全局配置才会保存到数据库中。不存在特定覆盖的键将具有全局配置的值 (project_id = 0)。 这变得更加复杂,因为不仅每个项目都存在全局配置,而且每台机器也存在。
如果需要有关覆盖概念以及这些覆盖如何存储在数据库中的更多信息,请给我反馈。
我的问题是,我无法在所有情况下检索正确的配置值。上面的 SELECT 应返回 ID 为 4 的行,但不返回任何内容。如果我调整它以找到项目 7 和机器 1 的有效配置,它会正确返回 ID 为 2 的行:
SELECT o.`id`, o.`project_id`, o.`machine_id`, o.`key`, o.`value`
FROM overwrite o
LEFT JOIN (
-- get all keys, for specific project_id
SELECT DISTINCT o1.`key`
FROM overwrite o1
-- insert specific project_id here
WHERE o1.`project_id` = 7
) subquery_project ON o.`key` = subquery_project.`key`
LEFT JOIN (
-- Get all keys for specific machine_id
SELECT DISTINCT o1.`key`
FROM overwrite o1
-- insert specific machine_id here
WHERE o1.`machine_id` = 1
) subquery_machine ON o.`key` = subquery_machine.`key`
-- always read entries for 0, replace second ID with specifc project / machine
WHERE o.`project_id` IN (0, 7)
AND o.`machine_id` IN (0, 1)
AND (
-- If project_id is 0, include only if there is no more specific projects entry
(o.`project_id` = 0 AND subquery_project.`key` IS NULL)
-- Always include more specific project entries
OR o.`project_id` = 7
)
AND (
-- If machine_id is 0, include only if there is no more specific machine entry
(o.`machine_id` = 0 AND subquery_machine.`key` IS NULL)
-- Always include more specific machine entries
OR o.`machine_id` = 1
)
编辑3: 将 SQL 表中的值更新为与表中的值相同以避免混淆。
在我看来,最合适的方法是应用一系列 JOIN 来选择配对(项目、机器)的
specifc values
以及默认值。
主表 - 元组列表(project_id,machine_id,key)。
第一个连接表
overwrite
- 完全适合键、project_id、machine_id。结果值首先是来自project_machine、project、machine的非空值。
参见示例
有源数据
id | 项目_id | 机器_id | 键 | 价值 |
---|---|---|---|---|
0 | 0 | 0 | Uc_max | 5000 |
1 | 1 | 0 | Uc_max | 4000 |
2 | 0 | 1 | Uc_max | 10000 |
3 | 1 | 1 | Uc_max | 15000 |
4 | 0 | 2 | Uc_max | 20000 |
此查询检索表中所有组合(key、project_id、machine_id)的所有键的所有值
overwrite
。
with mp as( -- all possible key,project_id,value_id - without defaults (0)
select p.project_id,m.machine_id,k
from (select distinct project_id from overwrite where project_id<>0
) p
cross join (select distinct machine_id from overwrite where machine_id<>0
) m
cross join (select distinct `key` as k from overwrite
) k
)
select mp.project_id,mp.machine_id,mp.k
,coalesce(pm.value,pd.value,md.value) key_value -- result key
,pm.value project_machine_value -- project and machine
,pd.project_id pd_project_id,pd.value project_default -- project defaults
,md.machine_id md_machine_id,md.value machine_default -- machine defaults
from mp
left join overwrite pm on pm.key=mp.k and pm.project_id=mp.project_id
and pm.machine_id=mp.machine_id
left join overwrite pd on pd.key=mp.k and pd.project_id=mp.project_id
and pd.machine_id=0
left join overwrite md on md.key=mp.k and md.machine_id=mp.machine_id
and md.project_id=0
order by mp.project_id,mp.machine_id
项目_id | 机器_id | k | 键值 | 项目机器值 | pd_项目_id | 项目默认 | md_machine_id | 机器_默认值 |
---|---|---|---|---|---|---|---|---|
1 | 1 | Uc_max | 15000 | 15000 | 1 | 4000 | 1 | 10000 |
1 | 2 | Uc_max | 4000 | 空 | 1 | 4000 | 2 | 20000 |
with mp as(
select 1 as project_id,7 as machine_id,'Uc_max' as k
)
select mp.project_id,mp.machine_id,mp.k
,coalesce(pm.value,pd.value,md.value) key_value
,pm.value project_machine_value -- project and machine
,pd.project_id pd_project_id,pd.value project_default -- project defaults
,md.machine_id md_machine_id,md.value machine_default -- machine defaults
from mp
left join overwrite pm on pm.key=mp.k and pm.project_id=mp.project_id
and pm.machine_id=mp.machine_id
left join overwrite pd on pd.key=mp.k and pd.project_id=mp.project_id
and pd.machine_id=0
left join overwrite md on md.key=mp.k and md.machine_id=mp.machine_id
and md.project_id=0
;
项目_id | 机器_id | k | 键值 | 项目机器值 | pd_项目_id | 项目默认 | md_machine_id | 机器_默认值 |
---|---|---|---|---|---|---|---|---|
1 | 7 | Uc_max | 4000 | 空 | 1 | 4000 | 空 | 空 |