MS access(2003) 是不是有任何可与存储过程相媲美的东西。我想在 MS 访问中运行一个复杂的查询
Posted
技术标签:
【中文标题】MS access(2003) 是不是有任何可与存储过程相媲美的东西。我想在 MS 访问中运行一个复杂的查询【英文标题】:Does MS access(2003) have anything comparable to Stored procedure. I want to run a complex query in MS acceessMS access(2003) 是否有任何可与存储过程相媲美的东西。我想在 MS 访问中运行一个复杂的查询 【发布时间】:2008-10-23 15:40:24 【问题描述】:我有一张桌子,叫它 TBL。它有两列,分别称为 A 和 B。现在在查询中,我需要一列作为 A,而另一列应该是一个逗号分隔的列表,其中包含 TBL 中与 A 相对的所有 B。 例如TBL是这样的
1 个阿尔法
2 测试版
1 伽马
1 个三角洲
查询结果应该是
1 Alpha、Gamma、Delta
2 测试版
这种事情很容易用存储过程中的游标来完成。但我无法通过 MS Access 来完成,因为显然它不支持存储过程。 有没有办法在 MS 访问中运行存储过程?或者有没有办法通过 SQL 来运行这种类型的查询
【问题讨论】:
VB6有存储过程吗? .NET 有存储过程吗? Access 是一个数据库应用程序开发平台。 Jet 是默认的数据库引擎,这是要询问的。 Jet 缺少存储过程(没有服务器进程来管理它们,因此不可能存在)。 【参考方案1】:您可以使用用户定义函数 (UDF) 连接记录。
下面的代码可以“按原样”粘贴到标准模块中。您的示例 SQL 将是:
SELECT tbl.A, Concatenate("SELECT B FROM tbl
WHERE A = " & [A]) AS ConcA
FROM tbl
GROUP BY tbl.A
此代码由 Access MVP DHookom 提供,取自 http://www.tek-tips.com/faqs.cfm?fid=4233
Function Concatenate(pstrSQL As String, _
Optional pstrDelim As String = ", ") _
As String
'example
'tblFamily with FamID as numeric primary key
'tblFamMem with FamID, FirstName, DOB,...
'return a comma separated list of FirstNames
'for a FamID
' John, Mary, Susan
'in a Query
'(This SQL statement assumes FamID is numeric)
'===================================
'SELECT FamID,
'Concatenate("SELECT FirstName FROM tblFamMem
' WHERE FamID =" & [FamID]) as FirstNames
'FROM tblFamily
'===================================
'
'If the FamID is a string then the SQL would be
'===================================
'SELECT FamID,
'Concatenate("SELECT FirstName FROM tblFamMem
' WHERE FamID =""" & [FamID] & """") as FirstNames
'FROM tblFamily
'===================================
'======For DAO uncomment next 4 lines=======
'====== comment out ADO below =======
'Dim db As DAO.Database
'Dim rs As DAO.Recordset
'Set db = CurrentDb
'Set rs = db.OpenRecordset(pstrSQL)
'======For ADO uncomment next two lines=====
'====== comment out DAO above ======
Dim rs As New ADODB.Recordset
rs.Open pstrSQL, CurrentProject.Connection, _
adOpenKeyset, adLockOptimistic
Dim strConcat As String 'build return string
With rs
If Not .EOF Then
.MoveFirst
Do While Not .EOF
strConcat = strConcat & _
.Fields(0) & pstrDelim
.MoveNext
Loop
End If
.Close
End With
Set rs = Nothing
'====== uncomment next line for DAO ========
'Set db = Nothing
If Len(strConcat) > 0 Then
strConcat = Left(strConcat, _
Len(strConcat) - Len(pstrDelim))
End If
Concatenate = strConcat
End Function
【讨论】:
你拯救了我的一天,成就了我的一天。多么优雅的解决方案。非常感谢【参考方案2】:我相信您可以创建 VBA 函数并在访问查询中使用它们。那可能对你有帮助。
【讨论】:
【参考方案3】:据我所知,没有一种方法可以在 Access 数据库中运行存储过程。但是,如果将 Access 用于 SQL 后端,则它可以执行存储过程。如果您无法将 UI 拆分为 Access 并将数据拆分为 SQL,那么您最好的选择可能是编写一个 VBA 模块来为您提供所需的输出。
【讨论】:
【参考方案4】:要完成您的任务,您需要使用代码。一种使用更有意义的名称的解决方案如下:
具有两个适用列的主表:
表格名称:小部件
字段 1:ID(长)
字段 2:颜色(文本 32)
添加两列表格:
表格名称:ColorListByWidget
字段 1:ID(长)
字段 2:颜色列表(文本 255)
将以下代码添加到模块并根据需要调用以更新 ColorListByWidget 表:
Public Sub GenerateColorList()
Dim cn As New ADODB.Connection
Dim Widgets As New ADODB.Recordset
Dim ColorListByWidget As New ADODB.Recordset
Dim ColorList As String
Set cn = CurrentProject.Connection
cn.Execute "DELETE * FROM ColorListByWidget"
cn.Execute "INSERT INTO ColorListByWidget (ID) SELECT ID FROM Widgets GROUP BY ID"
With ColorListByWidget
.Open "ColorListByWidget", cn, adOpenForwardOnly, adLockOptimistic, adCmdTable
If Not (.BOF And .EOF) Then
.MoveFirst
Do Until .EOF
Widgets.Open "SELECT Color FROM Widgets WHERE ID = " & .Fields("ID"), cn
If Not (.BOF And .EOF) Then
Widgets.MoveFirst
ColorList = ""
Do Until Widgets.EOF
ColorList = ColorList & Widgets.Fields("Color").Value & ", "
Widgets.MoveNext
Loop
End If
.Fields("ColorList") = Left$(ColorList, Len(ColorList) - 2)
.MoveNext
Widgets.Close
Loop
End If
End With
End Sub
ColorListByWidget 表现在包含您想要的信息。注意列表(本例中为颜色)不要超过 255 个字符。
【讨论】:
【参考方案5】:没有存储过程,没有临时表。
如果您需要将查询作为记录集返回,您可以使用断开连接的记录集。
【讨论】:
您的回答似乎很有趣,您能再解释一下吗? 断开连接的记录集是 Access 中使用的一种设备,通常用于代替临时表,您可以在其中创建记录集,然后取消它的 ActiveConnection。它很复杂,但可以在需要临时表的地方使用。我不够熟悉,无法提供所有详细信息,您需要 Google 一下。 断开连接的记录集是 ADO 功能,而不是“访问”功能。 ADO 不是 Jet 数据的首选接口——DAO 是。您可以通过使用事务而不是提交它们来获得相同的“临时表”功能。 ADO 是 Jet 的 my 首选接口 :) 如果您认为“临时表”等同于事务,那么您也可以喜欢 ADO,因为它与 DAO 不同,支持嵌套事务。 我也使用 ADO,虽然我还没有完全了解它的来龙去脉。【参考方案6】:也许与其询问 Jet 是否有存储过程,您应该解释您想要完成什么,然后我们可以解释如何使用 Jet 来完成它(不清楚您是在应用程序中使用 Access,还是仅使用Jet MDB 作为您的数据存储)。
【讨论】:
如果他们试图在 Access 中执行此操作,那么我会说“使用报告”。如果他们试图在 Jet(或任何其他 SQL)中执行此操作,那么我会说,“不要。使用报告。”【参考方案7】:嗯,您可以使用 Recordset 对象在 VBA 中循环查询,根据您需要的任何条件连接字段值。
如果你想将结果作为字符串返回,你会没事的。如果您想将它们作为查询返回,那将更加复杂。您可能必须创建一个临时表并将结果存储在其中,以便可以将它们作为表或查询返回。
【讨论】:
【参考方案8】:您可以在 VBA 中使用 GetString,它将返回由您喜欢的任何值分隔的记录集(例如逗号、破折号、表格单元格等),尽管我必须承认我只在 VBScript 中使用过它,而不是在 Visual Basic 中使用它。 W3Schools has a good tutorial which will hopefully lend itself to your needs.
【讨论】:
【参考方案9】:您可以将存储过程编写为文本并将其发送到数据库:
Dim sp as string
sp = "your stored procedure here" (you can load it from a text file or a memo field?)
Access.CurrentProject.AccessConnection.Execute sp
这假设您正在使用 ADODB 对象(ActiveX 数据对象库在您的应用程序中被 coorectly 引用)。
我确信 DAO 也有类似的东西......
【讨论】:
【参考方案10】:@Remou 谈 DHookom 的 Concatenate 函数:SQL 标准和 Jet 都没有CONCATENATE()
set 函数。简单地说,这是因为它违反了 1NF。我更愿意在应用程序端执行此操作,而不是尝试强制 SQL 执行它不打算执行的操作。也许 ACE (Access2007) 的多值类型更合适:仍然是 NFNF,但至少有引擎级别的支持。请记住,这个问题与 stored 对象有关:用户如何使用 SQL 查询非标量列...?
@David W. Fenton 关于 Jet 是否具有存储过程:几年前你和我没有在新闻组中讨论过这个问题。从 4.0 版开始,Jet/ACE 支持 ANSI-92 查询模式中的以下语法:
CREATE PROCEDURE procedure (param1 datatype[, param2 datatype][, ...]) AS sqlstatement;
EXECUTE procedure [param1[, param2[, ...]];
因此,Jet 正在创建和执行它所知道的(至少在一种模式下)作为“存储”在 MDB 文件中的“过程”。然而,Jet/ACE SQL 是纯粹而简单的:它没有控制流的语法,PROCEDURE
只能包含一条 SQL 语句,因此任何过程代码都是不可能的。因此,Jet是否有存储过程的答案是主观的。
【讨论】:
我现在没有时间去查找它,但是 Jet 4 的“过程”是不是完全不像大多数服务器数据库提供的存储过程?换句话说,它是一种功能非常有限的东西,不可能替代服务器类型的对象? 我不是已经涵盖了你的所有观点吗?例如我说,“......纯粹和简单:它没有控制流的语法,并且 PROCEDURE 只能包含一个 SQL 语句,所以任何过程代码都是不可能的”,但您仍然希望我澄清是否它是“功能非常有限的东西”?以上是关于MS access(2003) 是不是有任何可与存储过程相媲美的东西。我想在 MS 访问中运行一个复杂的查询的主要内容,如果未能解决你的问题,请参考以下文章
如何在 MS Access 2003 中删除具有唯一 ID 的重复条目?
ms access 2003 - 表单上的文本框:不跳转到任何文本框
有没有办法在 VBA(MS Access 2002 或 2003)中调用任何控件的更新前事件过程?
MS Access 2003 - 排序列表框的字符串值不是按字母顺序
MS-Access 2003 CurrentDb.TableDefs("tablename").Connect 数据库啥都不是