首先,我在这里发帖的借口,通常我觉得我应该能够通过尝试和搜索足够长的时间来找到一个情况的答案......到目前为止,它已经大约 5 个小时的搜索和测试,我无法解释结果我越来越。我现在有点不知所措。如果你们中的任何人可以帮助我,那将不胜感激。
情况
以下是所有现有代码,但我正忙于优化行为。
我使用三张桌子;
- 第一个表包含项目,
- 第二个表包含所有项目的属性字段,其中包括名称和默认值
- 第三个表包含属性字段的字段值,通过 id 链接到项目并通过字段 id 链接到字段
这个想法是让每个项目的所有字段都有一个值。如果值表中不存在字段和项值的行,则应使用默认值。
这一切都必须发生在一个查询中。
我之前的那个人通过确保每次添加一个字段时,都会将一个默认值字段插入到所有项目的值表中,从而“修复”了这个问题。当您的数据库表中可以有超过 10.000 个项目和超过 10 个字段时,这当然是错误的方法
我的测试用例
在这个系统上工作了 2 年多,我终于有时间从现有的权力中解决这个问题。对工作系统的正常测试总是给我所期望的不一致的回报。这是内部测试系统的当前状态:
- 277 个项目行
- 3 个字段行
- 824 个值行
这是在我通过执行一次性清理查询来清理系统上不再存在的项目和字段的值之后(是的,这部分是错误的):
DELETE FROM values WHERE item_id NOT IN (SELECT id FROM items) OR field_id NOT IN (SELECT id FROM fields);
我还制作了一个具有最低要求的虚拟系统,因为原始表包含更多字段:
-- table a represents items
CREATE TABLE IF NOT EXISTS `a` (
`id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `a` (`id`) VALUES (1),(2),(3);
-- table b represents fields
CREATE TABLE IF NOT EXISTS `b` (
`id` int(11) NOT NULL,
`default` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `b` (`id`, `default`) VALUES
(1, 4),
(2, 5),
(3, 6),
(4, 11),
(5, 12);
-- table c represents values
CREATE TABLE IF NOT EXISTS `c` (
`id` int(11) NOT NULL,
`a_id` int(11) NOT NULL,
`b_id` int(11) NOT NULL,
`value` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `c` (`id`, `a_id`, `b_id`, `value`) VALUES
(1, 1, 1, 7),
(2, 1, 2, 8),
(3, 2, 3, 9),
(4, 2, 1, 7),
(5, 3, 2, 8),
(6, 3, 3, 9),
(7, 1, 5, 13);
预期结果应为 831 行(277 个项目 * 3 个字段),其中值表中不可用的项目/字段组合应填充字段默认值,而不是值表中的值。
我在为检查我的发现而制作的虚拟系统上尝试的成功测试用例 SQL 返回了我的预期:
SELECT a.id,
b.id,
IF(c.value IS NOT NULL, c.value, b.default) as t_value
FROM a
join b
LEFT JOIN c on c.a_id = a.id AND c.b_id = b.id
这将返回 15 行(3 a(项目)x 5 b(字段)),包含所有预期数据
在更改内部测试系统的查询时,它应该可以工作。这是我发送的 SQL:
SELECT items.id AS item_id, fields.id AS field_id, IF(values.value IS NULL, fields.default_value, value.value) AS field_value
FROM items
JOIN fields
LEFT JOIN values ON values.item_id = item.id AND values.field_id = fields.id
...但它返回 1104 行而不是预期的 831 行。这些表已经清除了不准确的数据,并且我没有考虑到的额外字段根本没有在 SQL 中使用,而且抽象测试已经证明了查询概念。只有实际情况不断失败。
如果有人能指出我的错误,那将不胜感激。此处的表名已重命名,但根据要求,我还可以发布相关内部测试系统表的部分转储。上面的例子应该是准确的。