SQLite):删除行后自动更新两个表中的索引
Posted
技术标签:
【中文标题】SQLite):删除行后自动更新两个表中的索引【英文标题】:SQL(ite): auto updating indexes in two tables after row deletion 【发布时间】:2013-10-16 16:08:30 【问题描述】:再次在这里向你们寻求帮助!
我有两个问题要问你和两个 sql 表:
TABLE_1
[ ID_T1, T1_NAME, T1_VALUE ]
0 | name_t1_0 | value_t1_0
1 | name_t1_1 | value_t1_1
2 | name_t1_2 | value_t1_2
3 | name_t1_3 | value_t1_3
TABLE_2
[ ID_T2, ID_T1_IN_T2, T2_NAME, T2_VALUE ]
0 | 0 | name_t2_00 | value_t2_00
1 | 0 | name_t2_10 | value_t2_10
2 | 0 | name_t2_20 | value_t2_20
3 | 0 | name_t2_30 | value_t2_30
0 | 1 | name_t2_01 | value_t2_01
1 | 1 | name_t2_11 | value_t2_11
0 | 2 | name_t2_02 | value_t2_02
1 | 2 | name_t2_12 | value_t2_12
ID_T1 是唯一的渐进式索引。 TABLE_1 中的每个 ID_T1 可以在 ID_T1_IN_T2 列中出现 N 次。
ID_T2 是与每个 ID_T1 相关联的渐进式索引。
这意味着对于 TABLE_1 中的每一行,我们可以在 TABLE_2 中有 N 行。
问题 #1:如何在从 TABLE_1 中删除一行时自动更新 ID_T1_IN_T2 值?示例:从表 1 中删除 ID_T1 = 0 的行。预期结果如下(0 后的 ID_T1 减少,ID_T1_IN_T2 也减少)
TABLE_1
[ ID_T1, T1_NAME, T1_VALUE ]
0 | name_t1_1 | value_t1_1
1 | name_t1_2 | value_t1_2
2 | name_t1_3 | value_t1_3
表_2
[ ID_T2, ID_T1_IN_T2, T2_NAME, T2_VALUE ]
0 | 0 | name_t2_01 | value_t2_01
1 | 0 | name_t2_11 | value_t2_11
0 | 1 | name_t2_02 | value_t2_02
1 | 1 | name_t2_12 | value_t2_12
问题 #2:如何在删除行时自动更新 ID_T2 值?
示例:从刚刚更新的 TABLE_2 中删除 ID_T2 = 0 且 ID_T1_IN_T2=0 的行。预期结果如下(0后的ID_T2减少,ID_T1_IN_T2保持不变)
[ ID_T2, ID_T1_IN_T2, T2_NAME, T2_VALUE ]
0 | 0 | name_t2_11 | value_t2_11
0 | 1 | name_t2_02 | value_t2_02
1 | 1 | name_t2_12 | value_t2_12
在这些情况下你建议怎么做?
请注意,删除表并重新创建它们不被视为一种解决方案,因为它很脏而且性能极差(这是我暂时采用的解决方案)。
【问题讨论】:
您是否在存储派生值? 数据库刚刚被 C++ 应用程序填满,查询总是类似于“select t*name from table* where id* = x and id_* = y ”。当 c++ 端的名称或值发生更改时,它会在 db 中正确更新。如果在 c++ 端删除了一个项目,这就是问题所在:) 【参考方案1】:您的 C++ 应用程序没有使用好的数据库方法。我建议您使用 views 和 triggers 解决此问题。
例子:
您的主表变为T1
和T2
:
CREATE TABLE T1(ID, T1_NAME, T1_VALUE);
CREATE TABLE T2(ID, ID_T1, T2_NAME, T2_VALUE);
那些ID
已修复!你不应该改变它们!
接下来,辅助视图,将真实的ID
映射到动态视图:
CREATE VIEW T1_IDX AS SELECT DISTINCT ID, (SELECT COUNT() FROM (SELECT DISTINCT ID FROM T1 AS _ WHERE ID<T1.ID)) AS ID_T1 FROM T1;
CREATE VIEW T2_IDX AS SELECT DISTINCT ID, (SELECT COUNT() FROM (SELECT DISTINCT ID FROM T2 AS _ WHERE ID<T2.ID)) AS ID_T2 FROM T2;
TABLE_1
和 TABLE_2
被模拟为视图:
CREATE VIEW TABLE_1 AS
SELECT ID_T1, T1_NAME, T1_VALUE FROM T1
JOIN T1_IDX ON T1.ID=T1_IDX.ID;
CREATE VIEW TABLE_2 AS
SELECT ID_T2, T1_IDX.ID_T1 AS ID_T1_IN_T2, T2_NAME, T2_VALUE FROM T2
JOIN T2_IDX ON T2.ID=T2_IDX.ID
JOIN T1_IDX ON T2.ID_T1=T1_IDX.ID;
并且TABLE_1
上的DELETE
语句与以下TRIGGER
映射:
CREATE TRIGGER TABLE_1_DELETE INSTEAD OF DELETE ON TABLE_1 BEGIN
DELETE FROM T2 WHERE ID_T1 = (SELECT ID FROM T1_IDX WHERE ID_T1=OLD.ID_T1);
DELETE FROM T1 WHERE ID = (SELECT ID FROM T1_IDX WHERE ID_T1=OLD.ID_T1);
END;
通过这种自动化,您的 C++ 应用程序将看到带有计算索引的TABLE_1
,而不是真实索引,并且DELETE
操作由 SQLite 引擎处理以对真实表进行操作。
注意:除SELECT
和DELETE FROM TABLE_1
之外的视图上的其他操作,如果需要,必须作为触发器实现!
【讨论】:
非常有趣的方法,我会尽快尝试:) 谢谢【参考方案2】:另一个更简单的选择。
只需添加一个触发器:
CREATE TRIGGER TABLE_1_DELETE AFTER DELETE ON TABLE_1 BEGIN
UPDATE TABLE_1 SET ID_T1=ID_T1-1 WHERE ID_T1>OLD.ID_T1;
-- DELETE FROM TABLE_2 WHERE ID_T1_IN_T2=OLD.ID_T1;
UPDATE TABLE_2 SET ID_T1_IN_T2=ID_T1_IN_T2-1 WHERE ID_T1_IN_T2>OLD.ID_T1;
END;
CREATE TRIGGER TABLE_2_DELETE AFTER DELETE ON TABLE_2 BEGIN
UPDATE TABLE_2 SET ID_T2=ID_T2-1 WHERE ID_T2>OLD.ID_T2 AND ID_T1_IN_T2=OLD.ID_T1_IN_T2;
END;
这些触发器将在删除后立即更新索引。
如果删除注释行,删除TABLE_1
也会导致删除TABLE_2
中的对应记录。
【讨论】:
以上是关于SQLite):删除行后自动更新两个表中的索引的主要内容,如果未能解决你的问题,请参考以下文章