sql - 如何生成具有与联接等效的数据的可以编辑窗体?

  显示原文与译文双语对照的内容
0 0

我有一个如下所示的表 Tbl:

+----+------+----------+
| ID | Item | ItemDate |
+----+------+----------+
| 1 | xv | 7/23 |
| 2 | drc | 3/15 |
| 3 | fna | 3/15 |
| 4 | fna | 1/19 |
+----+------+----------+

用户根据这里表请求了一个表单 TblForm,它包含一个列 maxDate,该列为每个 Item 提供最新的ItemDate 。 表单必须允许用户编辑 Tbl 数据,因这里我不能只在联接查询上构建 基于表单 。 此外,表单必须根据 maxDate 列进行排序。

生成了单独的maxDate 聚合查询,然后将控件添加到 TblForm,并将它的控件控件设置为:

=DLookUp("maxDate","maxDate","Item=" & [Item])

但在结果数据表中,我不能根据这个列排序;我假定它不是源代码的TblForm 记录的一部分。 因此尝试生成一个包含DLookUp的查询:

select *,=DLookUp("maxDate","maxDate","Item=" & [Item]) as maxDateField from tbl

这里查询上的基于表单 非常慢。

关于如何构建我正在寻找的东西的任何想法?

时间:原作者:1个回答

0 0

这可以通过使用临时表来实现。

你需要两个相等的临时表,我们把它们叫做tmpTbl1和 tmpTbl2.

若要刷新这些表,请创建两个查询: vwMaxDate1和 vwMaxDate2.

你还可以创建两个查询作为报表的来源: vwTbl1和 vwTbl2.你将在它们之间进行 switch,因为你不能在表单打开时更新表。

这是视图的内容:

' CreateTmpTable1
SELECT Tbl.Item, Max(Tbl.ItemDate) AS maxdate INTO TmpTable1
FROM Tbl
GROUP BY Tbl.Item;
' CreateTmpTable2
SELECT Tbl.Item, Max(Tbl.ItemDate) AS maxdate INTO TmpTable2
FROM Tbl
GROUP BY Tbl.Item;
' vwMaxDate1
INSERT INTO tmpTbl1 ( Item, maxdate )
SELECT Tbl.Item, Max(Tbl.ItemDate) AS maxdate
FROM Tbl
GROUP BY Tbl.Item;
' vwMaxDate2
INSERT INTO tmpTbl2 ( Item, maxdate )
SELECT Tbl.Item, Max(Tbl.ItemDate) AS maxdate
FROM Tbl
GROUP BY Tbl.Item;
' vwTbl1
SELECT Tbl.*, T.maxdate
FROM Tbl LEFT JOIN tmpTbl1 AS T ON Tbl.Item = T.Item;
' vwTbl2
SELECT Tbl.*, T.maxdate
FROM Tbl LEFT JOIN tmpTbl2 AS T ON Tbl.Item = T.Item;

现在,执行CreateTmpTable1和 CreateTmpTable2. 你不再需要这些查询。

在设计模式中同时输入两个临时表,并将项设置为主键。

然后,执行vwMaxDate1并在视图vwTbl1上设计 基于表单 。 完成后,删除注册表的来源。 这里外,我还将锁定tmodel字段的控件,因为这是一个计算字段,不应该手动修改。

现在将以下代码输入表单,并将表单的"更新前"。"更新后"和"打开"事件更改为"[Event procedure]"。

Option Compare Database
Option Explicit
Private dataChanged As Boolean ' True whenever Item or ItemDate are changed
Private FirstTable As Boolean ' If true the origin of the registry is vwTbl1
Private Sub Form_AfterUpdate()
 If dataChanged Then
 DoCmd.SetWarnings False
 Select Case FirstTable
 Case True: ' vwTbl1 is open: Switch to vwTbl2
 DoCmd.RunSQL"DELETE * FROM TmpTbl2" ' Delete actual data from tmp table 2
 DoCmd.OpenQuery"vwMaxDate2" ' Create new data for tmp table 2
 Me.RecordSource ="vwTbl2" ' Switch to vwTbl2
 FirstTable = False
 Case False: ' vwTbl2 is open: Switch to vwTbl1
 DoCmd.RunSQL"DELETE * FROM TmpTbl1" ' Delete actual data from tmp table 1
 DoCmd.OpenQuery"vwMaxDate1" ' Create new data for tmp table 1
 Me.RecordSource ="vwTbl1" ' Switch to vwTbl1
 FirstTable = True
 End Select
 DoCmd.SetWarnings True
 End If
End Sub
Private Sub Form_BeforeUpdate(Cancel As Integer)
 ' Examine the Item and ItemDate controls to determine whether they've changed or not
 dataChanged = (Me.Item.OldValue <> Me.Item.Value Or Me.ItemDate.OldValue <> Me.ItemDate.Value)
End Sub
Private Sub Form_Open(Cancel As Integer)
 ' Initialize variables and form registry source
 FirstTable = True
 dataChanged = False
 DoCmd.SetWarnings False
 DoCmd.OpenQuery"vwMaxDate1"
 Me.RecordSource ="vwTbl1"
 DoCmd.SetWarnings True
End Sub

查询对于查询数据和更新与项目和ItemDate不同的任何字段都是很快的。

如果需要更新这些特定字段,你将注意到可变的延迟,具体取决于你的Tbl表中寄存器的数量。

为了加速创建临时表,强烈建议基于"项目"和"itemdate"字段在Tbl表上创建索引。

如果需要在多用户环境中工作,那么应该使用表记录来保存变量 FirstTable 。 这意味着你必须使用一些指令来查询和更新这个表,如

FirstTable = DLookup("FirstTable","CtrlTable","ID=1")
DoCmd.RunSQL"UPDATE CtrlTable SET FirstTable=True WHERE ID=1"

而不是简单地将 true 或者 false 分配给带有"="的FirstTable 。

就是这样希望对你有用。

问候,

原作者:
...