检测 SQL 中的循环引用
我有下表:
CREATE TABLE X (
A SOMETYPE NOT NULL,
B SOMETYPE NOT NULL,
C SOMETYPE NULL,
PRIMARY KEY (A,B),
FOREIGN KEY (A,C) REFERENCES X (A,B)
);
存储在 X
中的实体是按层次结构组织的:如果存在行 (A1,B1,C1)
且 C1 IS NOT NULL
code> 则它被认为是 (A1,C1,C2)
的“子级”,无论 C2
是什么。由于一个项目不能从自身下降,我想让循环分层序列的存在非法:
-- legal
INSERT INTO X (A1,B1,NULL);
INSERT INTO X (A1,B2,B1);
INSERT INTO X (A1,B3,B2);
INSERT INTO X (A1,B4,B2);
-- currently legal, but I want to make it illegal
UPDATE X SET C = B1 WHERE B = B1; /* B1-B1 */
UPDATE X SET C = B2 WHERE B = B1; /* B1-B2-B1 */
UPDATE X SET C = B3 WHERE B = B1; /* B1-B2-B3-B1 */
UPDATE X SET C = B4 WHERE B = B1; /* B1-B2-B4-B1 */
UPDATE X SET C = B2 WHERE B = B2; /* B2-B2 */
UPDATE X SET C = B3 WHERE B = B2; /* B2-B3-B2 */
UPDATE X SET C = B4 WHERE B = B2; /* B2-B4-B2 */
UPDATE X SET C = B3 WHERE B = B3; /* B3-B3 */
UPDATE X SET C = B4 WHERE B = B4; /* B4-B4 */
我该如何做到这一点?
或者,我可以在表中添加一个表示层次结构中“级别”的字段:
CREATE TABLE X (
A SOMETYPE NOT NULL,
B SOMETYPE NOT NULL,
C SOMETYPE NULL,
LEVEL INT NOT NULL,
PRIMARY KEY (A,B),
FOREIGN KEY (A,C) REFERENCES X (A,B)
);
然后,当 C IS NULL 时,我希望要求
,否则LEVEL
为 0
父母的LEVEL + 1
。
我正在使用 SQL Server 2008 R2。
I have the following table:
CREATE TABLE X (
A SOMETYPE NOT NULL,
B SOMETYPE NOT NULL,
C SOMETYPE NULL,
PRIMARY KEY (A,B),
FOREIGN KEY (A,C) REFERENCES X (A,B)
);
The entities stored in X
are hierarchically organized: If a row (A1,B1,C1)
exists and C1 IS NOT NULL
then it is considered to be a "child" of (A1,C1,C2)
whatever C2
is. Since an item cannot descend from itself, I would like to make it illegal that circular hierarchical sequences exist:
-- legal
INSERT INTO X (A1,B1,NULL);
INSERT INTO X (A1,B2,B1);
INSERT INTO X (A1,B3,B2);
INSERT INTO X (A1,B4,B2);
-- currently legal, but I want to make it illegal
UPDATE X SET C = B1 WHERE B = B1; /* B1-B1 */
UPDATE X SET C = B2 WHERE B = B1; /* B1-B2-B1 */
UPDATE X SET C = B3 WHERE B = B1; /* B1-B2-B3-B1 */
UPDATE X SET C = B4 WHERE B = B1; /* B1-B2-B4-B1 */
UPDATE X SET C = B2 WHERE B = B2; /* B2-B2 */
UPDATE X SET C = B3 WHERE B = B2; /* B2-B3-B2 */
UPDATE X SET C = B4 WHERE B = B2; /* B2-B4-B2 */
UPDATE X SET C = B3 WHERE B = B3; /* B3-B3 */
UPDATE X SET C = B4 WHERE B = B4; /* B4-B4 */
How do I do this?
Alternatively, I could add a field representing the "level" in the hierarchy to the table:
CREATE TABLE X (
A SOMETYPE NOT NULL,
B SOMETYPE NOT NULL,
C SOMETYPE NULL,
LEVEL INT NOT NULL,
PRIMARY KEY (A,B),
FOREIGN KEY (A,C) REFERENCES X (A,B)
);
Then I would like to require that LEVEL
be 0
when C IS NULL
, and parent's LEVEL + 1
otherwise.
I am using SQL Server 2008 R2.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
为了检查循环引用,我使用了触发器和递归 CTE:
现在,我们可以运行一些测试:
结果:
对于第二个测试,您可以看到此触发器如何取消 (
ROLLBACK TRANSACTION
) 事务并且,更新后,没有执行任何操作(在当前批次中)。To check for circular references i have used a trigger and recursive CTE:
Now, we can run some tests:
Results:
For the second test, you can see how this trigger has canceled (
ROLLBACK TRANSACTION
) the transaction and, after UPDATE, nothing has been executed (in current batch).