我可能会过度思考这一点,但我看到各种各样的潜在问题......
我有一张桌子,我称之为师父。在其他项目中,它包含一个名为Serial的字段。我思想这将是一个静态项目 - 即,它永远不会改变(一旦最初分配),对于Master中的任何给定行。我现在发现可以更改,不仅如此,我还需要存储这些更改的历史记录。
我可以将Serial打破到一个单独的表中,其中每一行都有一个MasterId,EffectiveDate和Termination Date(Master行的当前Serial将是一行(并且只有一行代码) Null TerminationDate)。到目前为止,这太好了....
现在我问的问题是:我有一个基于Select from Master构建的绑定表单,包括Serial。
我想做的事情我想做的是,为了让这个可更改性对用户透明,可以将对Serial文本框所做的任何更改短路,可能在文本框BeforeUpdate事件中。然后我使用代码终止串行表中的当前行&插入一个新行,该行变为当前行并显示在文本框中。我(我认为)需要取消表单记录集中的更新,不用丢失用户对其他字段所做的任何更改....
正是在这一点上,我的大脑出去吃午饭,因为我对未绑定的表格更加舒服。保存按钮。我建议可以这样做吗?什么伎俩和陷阱我需要知道吗?如果需要,我可以将表单上的Serial字段设置为只读,并需要弹出窗口来编辑它,但如果可以,我宁愿避免使用。
*的 *修改
希望这会有所帮助:
之前
table Master
Id AutoNumber PK
Serial Text(20)
--other fields
目前的frmMaster RecordSource:
SELECT Id, Serial, yada, yada FROM Master WHERE blahBlah
后
table Master
Id AutoNumber PK
--other fields
table Serial
Id AutoNumber PK
MasterId Long
Serial Text(20)
EffDt Date/Time
TermDt Date/Time
新的frmMaster RecordSource:
SELECT Master.Id, Serial.Serial, yada, yada
FROM Master LEFT JOIN Serial ON Master.Id = Serial.MasterId
WHERE Serial.TermDt is Null AND blahBlah
表单上的“编辑”应该导致:
再次编辑
好的,所以HansUp给出了一个答案,看起来它涵盖了我需要的大部分内容。我剩下的绊脚石可能不是一个问题(但如果是这样的话,有人可以解释原因吗?)。
添加Master的用例非常简单,但是在更新Serial的用例中我仍然感到困惑:如果txtSerial
绑定到Serial.Serial
,那么用户更改txtSerial
的内容,是否会尝试更新Serial.Serial
的内容以进行匹配?如何在更改时添加串行(看起来应该可以处理),阻止更新现有的串行?
答案 0 :(得分:1)
您尚未向我们展示Serial表的示例数据。我很好奇它是否会像这样:
Id MasterId Serial date_added
1 1 foo 4/21/2011 7:00:00 AM
2 1 bar 4/21/2011 9:00:00 AM
3 1 foo 4/21/2011 11:00:00 AM
4 2 asldkjf 4/4/2011 1:00:00 PM
每当您需要使用EffDt和TermDt表示的Serial行时,您可以使用相关的子查询。
SELECT
s.Id,
s.MasterId,
s.Serial,
s.date_added AS EffDt,
(SELECT TOP 1 sub.date_added
FROM Serial As Sub
WHERE
sub.MasterId = s.MasterId
And sub.date_added > s.date_added
ORDER BY sub.date_added) AS TermDt
FROM Serial AS s
ORDER BY
s.MasterId,
s.date_added;
我意识到你的问题更广泛。就目前而言,这件作品是我可以包裹的。但它是否符合您的要求?
更新:我使用的是我的Serial表版本。我创建了一个主表,其中包含自动编号Id,文本序列,以及其他2个文本字段,Other_field1和Other_field2。然后创建一个简单的连续形式绑定到“SELECT Id,Serial,Other_field1,Other_field2 FROM Master Order By Id;”。
这是表单的代码:
Option Compare Database
Option Explicit
Dim varSerialOldvalue As Variant
Private Sub Form_AfterInsert()
addSerialRow
End Sub
Private Sub Form_AfterUpdate()
Dim strSql As String
If Me.txtSerial.value <> varSerialOldvalue Then
addSerialRow
End If
End Sub
Private Sub Form_BeforeUpdate(Cancel As Integer)
varSerialOldvalue = Me.txtSerial.OldValue
End Sub
Private Sub addSerialRow()
Dim strSql As String
Dim strMsg As String
On Error GoTo ErrorHandler
strSql = "INSERT INTO Serial(MasterId, Serial, date_added)" & _
vbNewLine & "VALUES(" & Me.txtid & ",'" & _
Replace(Me.txtSerial, "'", "''") & "', #" & _
Format(Now(), "yyyy/mm/dd hh:nn:ss") & "#);"
CurrentDb.Execute strSql, dbFailOnError
ExitHere:
On Error GoTo 0
Exit Sub
ErrorHandler:
strMsg = "Error " & Err.Number & " (" & Err.description _
& ") in procedure addSerialRow" & vbNewLine & _
"SQL: " & strSql
MsgBox strMsg
GoTo ExitHere
End Sub
这是你想要完成的事情的有用起点吗?
Update2 :您说 txtSerial绑定到Serial.Serial ;但是我的方法将txtSerial直接绑定到Master表中的Serial字段......这是我原先认为你提出的。这种方法现在有什么问题?
答案 1 :(得分:0)
实际上,我不明白为什么要阻止更改文本框?如果我读的是正确的,你所说的是如果文本框改变了,那么你需要保存以前的当前数据并在更改前记录吗?
如果是上述情况,那么只需在序列文本框的更新后事件中,运行一个追加查询,该查询从表中获取当前记录并复制(将其附加到其他地方)。
当您有绑定表单时,对表单上控件的更改不会提交给实际的基础表。如果您的代码或进程或某些追加查询或VBA代码查看或从表中复制该行,则所有旧值仍将保持不变。
因此绑定表单并不意味着文本框中的每个更改都写入表中,但实际上整个记录只在保存记录时写入表中,这就是为什么更新事件之前的表单有取消可以阻止记录写入发生,直到满足您的规则等。
因此,您只需要在更新事件后的串行框中需要一行或两行(除非对文本框进行更改,否则该事件不会触发)从表中复制当前记录,该记录将具有所有旧值,包括旧的序列号。
答案 2 :(得分:0)
如果Master不经常更改且不太大,则在保存时,添加添加了whoChanged记录和时间段的整个Master记录。然后,当您想要查看Serial中的更改时,只需在Serial上执行GroupBy,您就可以看到时间和更改者。
这对于一个字段来说是过度的,但通常提供记录更改的好方法。