9

我有一张桌子,叫它 TBL。它有两列,分别称为 A 和 B。现在在查询中,我需要一列作为 A,另一列应该是一个逗号分隔的列表,其中包含 TBL 中与 A 对抗的所有 B。比如TBL是这样的

1 阿尔法

2 测试版

1 伽玛

1 三角洲

查询结果应该是

1 阿尔法,伽马,三角洲

2 测试版

这种类型的事情很容易用存储过程中的游标来完成。但我无法通过 MS Access 来完成,因为显然它不支持存储过程。有没有办法在 MS 访问中运行存储过程?或者有没有办法通过 SQL 来运行这种类型的查询

4

10 回答 10

11

您可以使用用户定义函数 (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 
于 2008-10-23T21:17:08.493 回答
3

我相信您可以创建 VBA 函数并在访问查询中使用它们。那可能对你有帮助。

于 2008-10-23T16:32:48.783 回答
2

据我所知,没有一种方法可以在 Access 数据库中运行存储过程。但是,如果将 Access 用于 SQL 后端,则它可以执行存储过程。如果您不能将 UI 拆分为 Access 并将数据拆分为 SQL,那么您最好的选择可能是编写一个 VBA 模块来为您提供所需的输出。

于 2008-10-23T15:47:45.957 回答
2

要完成您的任务,您将需要使用代码。一种使用更有意义的名称的解决方案如下:

具有两个适用列的主表:

表名:小部件

字段 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 个字符。

于 2008-10-23T18:17:55.173 回答
1

没有存储过程,没有临时表。

如果您需要将查询作为记录集返回,您可以使用断开连接的记录集。

于 2008-10-23T16:04:03.897 回答
1

也许与其询问 Jet 是否有存储过程,不如说明您想要完成什么,然后我们可以解释如何使用 Jet 来完成它(不清楚您是使用 Access 作为您的应用程序,还是仅使用 Jet MDB 作为您的数据存储)。

于 2008-10-24T02:58:12.843 回答
0

好吧,您可以使用 Recordset 对象在 VBA 中循环查询,根据您需要的任何条件连接字段值。

如果你想将结果作为字符串返回,你会没事的。如果您想将它们作为查询返回,那将更加复杂。您可能必须创建一个临时表并将结果存储在其中,以便您可以将它们作为表或查询返回。

于 2008-10-23T15:49:29.653 回答
0

您可以在 VBA 中使用 GetString,它将返回由您喜欢的任何值分隔的记录集(例如逗号、破折号、表格单元格等),尽管我必须承认我只在 VBScript 中使用过它,而不是在 Visual Basic 中使用它。W3Schools 有一个很好的教程,希望能满足您的需要

于 2008-10-23T21:28:29.437 回答
0

您可以将存储过程编写为文本并将其发送到数据库:

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有类似的东西......

于 2008-10-23T22:30:52.557 回答
0

@Remou 谈 DHookom 的 Concatenate 函数:SQL 标准和 Jet 都没有CONCATENATE()set 函数。简单地说,这是因为它违反了 1NF。我更愿意在应用程序端执行此操作,而不是尝试强制 SQL 执行它不打算执行的操作。也许 ACE (Access2007) 的多值类型更合适:仍然是 NFNF,但至少有引擎级别的支持。请记住,问题与存储对象有关:用户如何使用 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 是否有存储过程的答案是主观的。

于 2008-10-24T08:00:21.300 回答