2012-07-24 56 views
0

我一直在用让我的计划,通过依赖于记录中的值的数据库跟踪记录了一点问题,简单地说,这就是我想要的目的。以下记录

这是表的简化版本,我的工作:

Record Name | Val1 | Val2 | Link | Prev Link | 
Rec1   | 5 | 3 | Rec2 |   | 
Rec2   | 2 | 4 | Rec6 | Rec1  | 
Rec3   | 1 | 8 | Rec4 |   | 
Rec4   | 1 | 1 |  | Rec3  | 
Rec5   | 8 | 3 |  |   | 
Rec6   | 9 | 3 |  | Rec2  | 

我的程序需要通过上面的表格,保存对一个特定记录的信息,请访问它的链接记录,清晰先前的记录的值,然后将它们添加到较新的记录(它应该继续这样做,直到它到达链的末尾),作为一个例子,这是运行我的程序后会发生什么。

Record Name | Val1 | Val2 | Link | Prev Link | 
Rec1   | 0 | 0 | Rec2 |   | 
Rec2   | 0 | 0 | Rec6 | Rec1  | 
Rec3   | 0 | 0 | Rec4 |   | 
Rec4   | 2 | 9 |  | Rec3  | 
Rec5   | 8 | 3 |  |   | 
Rec6   | 16 | 10 |  | Rec2  | 

我使用目前的程序可以在以下位置找到:http://pastebin.com/A10hW0C6

我现在面临的主要问题是,我不能让程序要经过每一条记录,点击任何链接,然后返回到它停止的地方以确保它不会错过任何东西,我该如何让程序忽略它已经作为循环的一部分结束的记录?

任何帮助,将不胜感激:)

+3

请在这里发表您的代码。不得不离开这个网站去其他地方阅读它很烦人,如果外部网站被移动或由于某种原因离线,它是不可用的。这还不算通过未来的读者检索。发布适用于您的问题在这里它的最小部分,请。谢谢。 – 2012-07-24 22:53:29

+0

我没有看到你实际迭代表的位置..你需要在你的while循环之前有tblParts.first,在while循环的底部有tblParts.next。 – 2012-07-25 02:21:57

+0

* lvBookmark:= tblParts.RecNo * - 为什么?标准方式,所以更好的图书馆支持,将是* lvBookmark:= tblParts.Bookmark * – 2012-07-25 09:17:32

回答

1

嗯,你可以做的是有一个单独的查询持有启动的最环节的记录,如:

qry1.sql := 'select * from table where prev_link is null;'; 

这给

Record Name | Val1 | Val2 | Link | Prev Link |  
Rec1   | 5 | 3 | Rec2 |   |  
Rec3   | 1 | 8 | Rec4 |   |  
Rec5   | 8 | 3 |  |   |  

然后你就可以按照结果数据集,寻求/找到的其他查询(QUERY2),还有你的应用的处理逻辑。

您用结果日期集完成的时间,就完成了。这当然,假设你的数据是合法的,即没有断开的链接,没有循环链接等

一些增强。您可以添加名为“状态”的列以反映记录的状态。例如,status = 0表示'未处理','1'表示处理,'2'表示断开链接,'3'表示循环链接等。您可以从0开始填充所有状态列(未处理)。

如果你不能找到通过寻找/在“链接”栏中查找它的记录(可能在某种程度上被删除),那么你可以标记的状态为“2”。

每次点击一个链接时,保持跟随记录的轨道。例如,您可以使用列表。在“链接”列中查看记录之前,请查看列表。如果记录在列表中,那么你有一个循环链接。停止跟踪,将状态标记为'3'(循环链接),清除列表,并从query1中的下一条记录开始。处理循环链接很重要,否则你的程序可能会卡住它(永不结束)。

处理完链接链,则标志状态为“1”到列表中的所有记录。

您可以使用数据库事务(交易开始... END交易),所以当你遇到下的链接链Deadlink中或圆形的链接,就可以相应地回滚更改后的值,并标记状态。

完成后,可以检查状态栏。如果全部'1'表示全部好(已处理)。如果没有,那么你可以决定下一步该做什么。

列状态可以被用来在另一个子序贯操作过滤掉已经处理过的记录,所以上面的查询可以改变:

qry1.sql := 'select * from table where prev_link is null and status = 0;'; 

当然,这是一个初步的策略,你可以修改它以适应你。

0

根据您使用的数据库,这可能纯粹通过服务器上的SQL来解决。这里有一个Firebird的例子(假设链接是一致的,并且没有可以通过引用完整性约束和触发器强制执行的无限递归 - 这里不包括这些)。

/* metadata */ 
set sql dialect 3; 

create table test (
    id  integer not null, 
    val1  integer, 
    val2  integer, 
    next_id integer, 
    prev_id integer 
); 

alter table test add constraint pk_test primary key (id); 
alter table test add constraint fk_test_next_id foreign key (next_id) references test (id) on update cascade; 
alter table test add constraint fk_test_prev_id foreign key (prev_id) references test (id) on update cascade; 

/* data */ 
insert into test (id, val1, val2, next_id, prev_id) values (1, 5, 3, 2, null); 
insert into test (id, val1, val2, next_id, prev_id) values (2, 2, 4, 6, 1); 
insert into test (id, val1, val2, next_id, prev_id) values (3, 1, 8, 4, null); 
insert into test (id, val1, val2, next_id, prev_id) values (4, 1, 1, null, 3); 
insert into test (id, val1, val2, next_id, prev_id) values (5, 8, 3, null, null); 
insert into test (id, val1, val2, next_id, prev_id) values (6, 9, 3, null, 2); 

/* update statement (could also be a stored procedure) */ 
execute block 
as 
    declare variable id integer; 
    declare variable val1 integer; 
    declare variable val2 integer; 
begin 
    for with recursive test_list (
    id, 
    val1, 
    val2, 
    next_id 
) 
    as (
    select 
     t.id, 
     t.val1, 
     t.val2, 
     t.next_id 
    from test t 
    where (t.prev_id is null) 
    union all 
    select 
     t.id, 
     t.val1 + tl.val1, 
     t.val2 + tl.val2, 
     t.next_id 
    from test t 
    join test_list tl on (tl.id = t.prev_id) 
) 
    select 
    tl.id, 
    iif(tl.next_id is null, tl.val1, 0) val1, 
    iif(tl.next_id is null, tl.val2, 0) val2 
    from test_list tl 
    order by tl.id 
    into 
    :id, 
    :val1, 
    :val2 
    do 
    update test set 
     val1 = :val1, 
     val2 = :val2 
    where (id = :id); 
end 
0

TOndrej给了你很好的答案,但你要知道SQL好了点。 它支付 - 制作正确的SQL将使您的数据库可靠,在您的程序错误不会损坏数据库数据。但是你有时间学习。 另外他的SQL使用的是最近Firebird版本的功能,这个词几乎不适用于NexusDB或其他服务器。

这是一个更愚蠢的方法。你也可以尝试一下。

所以,如果我理解你的任务,表被分成一组链? 这里u有三个链:Rec1-> Rec2-> REC6Rec3-> REC4Rec5孤单。

当U添加新的元素,它总是去尾,所以这将是Rec1-> Rec2-> Rec6-> NewRec7,但绝不可以NewRec7-> Rec1-> Rec2- > Rec6 and Rec1-> Rec2-> NewRec7-> Rec6

就这样吗?

那么在哪里添加栏距离从根

Record Name | Val1 | Val2 | Link | Prev Link | Dist | 
Rec1   | 5 | 3 | Rec2 |   | 0 | 
Rec2   | 2 | 4 | Rec6 | Rec1  | 1 | 
Rec3   | 1 | 8 | Rec4 |   | 0 | 
Rec4   | 1 | 1 |  | Rec3  | 1 | 
Rec5   | 8 | 3 |  |   |  | 
Rec6   | 9 | 3 |  | Rec2  | 2 | 

您可以在SQL计算和更新触发器或在你的程序。 SQL触发器更好 - 更可靠。但是你需要把握它们。 无论何时何时添加记录,删除记录或更改记录链接 - yow都必须重新计算所有受影响记录的距离。例如,如果我将Rec6切割并重新连接到Rec1-> Rec2,Rec6-> Rec3-> Rec4,则Rec6和Rec3和Rec4的距离将不得不重新计算

1)get max (dist)从数据库。

SELECT MAX(DIST)FROM THE_TABLE

2),用于从0每chosen_dist到最大(DIST)-1-

2。1),用于与这样的距离中的每个记录

SELECT RecordName,链接VAL1,VAL2 FROM THE_TABLE WHERE DIST =:choosen_dist和链路IS NOT NULL

2.1.1)更新下一个连接的一个递增值

更新表设置Val1 = Val1 +:PrevLinked_Val1; VAL2 = VAL2 +:PrevLinked_Val2 WHERE RecordName =:NEXTLINK

2.1.2)更​​新所选一个,清零值

更新-TABLE SET VAL1 = 0; VAL2 = 0 WHERE RecordName =:CurrentRecordName

这种做法更糟糕的是:

  1. 没有这么快 - 重复,而不是捆绑成一个程序,并调用一次许多单独的报表;
  2. 没有那么快也不太可靠 - 如果你从程序一行接一行地调用它,那么数据将通过网络从服务器飞到程序并返回,而不是所有服务器内部的计算结果
  3. 你必须计算距离的时候要非常小心。截至删除它们的点ALL并重新计算,如果事情得到打破。

而且最好是:

  1. 更容易理解SQL新手

  2. 仅使用非常基本的SQL,所以可以进入任何服务器:NexusDB,火鸟,SQLite的,什么ü选择

相关问题