Есть ли в MS access (2003) что-нибудь сравнимое с хранимой процедурой. Я хочу выполнить сложный запрос в MS Access - PullRequest
9 голосов
/ 23 октября 2008

У меня есть стол, назовите его TBL. Он имеет два столбца, назовите их A и B. Теперь в запросе мне нужен один столбец как A, а другой столбец должен быть разделенным запятыми списком всех B, которые против A в TBL. например TBL такой

1 Альфа

2 бета

1 Гамма

1 Дельта

Результат запроса должен быть

1 Альфа, Гамма, Дельта

2 бета

Этот тип вещи очень просто сделать с курсорами в хранимой процедуре. Но я не могу сделать это через MS Access, потому что, по-видимому, он не поддерживает хранимые процедуры. Есть ли способ запустить хранимую процедуру в MS Access? или есть ли способ через SQL для выполнения этого типа запроса

Ответы [ 10 ]

11 голосов
/ 24 октября 2008

Вы можете объединить записи с помощью пользовательской функции (UDF).

Код ниже можно вставить «как есть» в стандартный модуль. Пример SQL для вас будет:

SELECT tbl.A, Concatenate("SELECT B  FROM tbl
        WHERE A = " & [A]) AS ConcA
FROM tbl
GROUP BY tbl.A

Этот код предоставлен DHookom, Access MVP и взят из 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 
3 голосов
/ 23 октября 2008

Я считаю, что вы можете создавать функции VBA и использовать их в своих запросах доступа. Это может помочь вам.

2 голосов
/ 23 октября 2008

Для выполнения вашей задачи вам понадобится код. Одно решение с использованием более значимых имен выглядит следующим образом:

Основная таблица с двумя применимыми столбцами:

Название таблицы: виджеты

Поле 1: ID (длинный)

Поле 2: Цвет (Текст 32)

Добавить таблицу с двумя столбцами:

Имя таблицы: ColorListByWidget

Поле 1: ID (длинный)

Поле 2: ColorList (текст 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 символов.

2 голосов
/ 23 октября 2008

Мне не известен способ запуска хранимых процедур в базе данных Access. Однако Access может выполнять хранимые процедуры, если он используется с бэкэндом SQL. Если вы не можете разделить пользовательский интерфейс на Access и данные на SQL, то, вероятно, лучше всего будет написать код модуля VBA, чтобы получить необходимый вывод.

1 голос
/ 24 октября 2008

Возможно, вместо того, чтобы спрашивать, есть ли у Jet хранимые процедуры, вам следует объяснить, чего вы хотите достичь, а затем мы можем объяснить, как это сделать с помощью Jet (неясно, используете ли вы Access для своего приложения или просто используете Jet MDB как ваше хранилище данных).

1 голос
/ 23 октября 2008

Нет хранимых процедур, нет временных таблиц.

Если вам нужно вернуть запрос как набор записей, вы можете использовать отключенный набор записей.

0 голосов
/ 24 октября 2008

@ Remou для функции конкатенации DHookom: ни стандарт SQL, ни Jet не имеют функции set CONCATENATE(). Проще говоря, это потому, что это нарушение 1NF. Я предпочел бы делать это на стороне приложения, а не пытаться заставить SQL делать то, для чего он не предназначен. Возможно, лучше подходят многозначные типы ACE (Access2007): все еще NFNF, но, по крайней мере, есть поддержка на уровне движка. Помните, что вопрос относится к хранимому объекту: как пользователь будет запрашивать нескалярный столбец, используя SQL ...?

@ Дэвид У. Фентон о том, хранит ли Джет процедуры: разве мы с вами не обсуждали это в группах новостей пару лет назад. Начиная с версии 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 хранимые процедуры, субъективен.

0 голосов
/ 24 октября 2008

Вы можете написать свою хранимую процедуру в виде текста и отправить ее в базу данных с помощью:

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 имеет прямую ссылку в вашем приложении).

Я уверен, что с DAO что-то похожее ...

0 голосов
/ 24 октября 2008

Вы можете использовать GetString в VBA, который будет возвращать набор записей, разделенный любым значением, которое вам нравится (например, запятая, тире, ячейки таблицы и т. Д.), Хотя я должен признать, что использовал его только в VBScript, а не в Visual Basic. В W3Schools есть хороший учебник, который, как мы надеемся, подойдет вам .

0 голосов
/ 23 октября 2008

Что ж, вы можете использовать объект Recordset для циклического выполнения вашего запроса в VBA, объединяя значения полей на основе любых критериев, которые вам нужны.

Если вы хотите вернуть результаты в виде строк, все будет в порядке. Если вы хотите вернуть их как запрос, это будет сложнее. Возможно, вам придется создать временную таблицу и сохранить в ней результаты, чтобы вы могли вернуть их в виде таблицы или запроса.

...