Использовать функцию доступа в сквозном запросе SQL

У меня есть интерфейс MS Access с серверной базой данных Oracle SQL.

Я пытаюсь создать сквозной запрос, содержащий функцию в Access. Эта функция предназначена для установки jobnumber в зависимости от того, что пользователь вводит на экране входа в систему.

SELECT 
    CC_QAQC_SPEC_MASTER.JOBNUMBER, 
    CC_QAQC_SPEC_MASTER.SPECSECTION,
    CC_QAQC_SPEC_MASTER.SPECDESCRIPTION,
    CC_QAQC_SPEC_MASTER.ID
FROM 
    CC_QAQC_SPEC_MASTER
WHERE 
    CC_QAQC_SPEC_MASTER.JOBNUMBER=GET_QAQC_JOB()
ORDER BY 
    CC_QAQC_SPEC_MASTER.SPECSECTION, 
    CC_QAQC_SPEC_MASTER.SPECDESCRIPTION;

Когда я запускаю вышеуказанное, я получаю сообщение об ошибке, в котором говорится:

ODBC - сбой вызова [Oracle] [ODBC] [Ora] ORA-00942: таблица или представление не существует (# 942)


person House    schedule 09.05.2019    source источник


Ответы (2)


Что ж, поскольку sql отправляется в Oracle «необработанным», то, конечно, серверная база данных не знает, что делать с функцией VBA.

Итак, одним из возможных решений было бы воссоздать функцию VBA как функцию оракула масштабирования.

Однако, поскольку данная функция не имеет параметров, мы можем предположить, что функция возвращает заданное значение - чертовски близко к статическому, или значение, которое вы хотите / хотите передать в oracle.

Таким образом, этот подход означает, что мы должны разрешить функцию на стороне клиента ДО того, как мы попытаемся использовать или выполнить этот запрос PT.

Итак, я рекомендую вам взять приведенный выше запрос PT и скопировать его. (сторона доступа). Теперь у вас есть два запроса PT.

Теперь в коде мы берем sql, модифицируем его, вставляем во второй запрос, и теперь вы можете запустить + использовать этот сквозной запрос (для отчета, наборов записей, форм или чего-то еще)

Итак, ваш код будет выглядеть так:

Sub MyOraclePT()

  Dim strSQL     As String

  strSQL = CurrentDb.QueryDefs("PT1").SQL    ' <-- this change

  strSQL = Replace(strSQL, "GET_QAQC_JOB()", GET_QAQC_JOB())

  CurrentDb.QueryDefs("PT2").SQL = strSQL

  ' now you can open or use this query.

  '
  Dim rst     As DAO.Recordset
  Set rst = CurrentDb.OpenRecordset("PT2")

  ' or open a report/form based on that PT2 query
  ' such as
  DoCmd.OpenReport "MyReport", acViewPreview


End Sub

Итак, мы использовали два запроса PT, потому что первый - это sql, который у вас есть, как указано выше. Затем мы модифицируем второй запрос PT, чтобы заменить значение функции фактическим значением функции.

Вышеупомянутое предполагает, что функция является числом (а не строкой). Если бы столбец CC_QAQC_SPEC_MASTER.JOBNUMBER был строкой, то вы могли бы заключить имя функции в одинарные кавычки в первом запросе PT.

Я также отмечаю ошибку / синтаксическую ошибку, так как у вас есть:

WHERE 
    CC_QAQC_SPEC_MASTER.JOBNUMBER)=GET_QAQC_JOB()

Выше я вижу случайное ")" - вы хотите это исправить.

person Albert D. Kallal    schedule 10.05.2019
comment
Для всех, кто ищет общее решение проблемы, обратите внимание, что это будет работать только до тех пор, пока функция не принимает никаких табличных данных в качестве параметров. - person SunKnight0; 10.05.2019
comment
Когда дело доходит до VBA, я новичок, так что терпите меня. Куда мне поместить Sub MyOraclePT ()? Я просто создаю новый модуль и вставляю его туда? У меня есть несколько запросов, которые я хочу преобразовать в PT, но каждый из них использует эту функцию номера задания. - person House; 10.05.2019
comment
Код должен работать нормально, если он помещен в стандартный модуль кода доступа (а не в модуль класса). В этом примере также предполагается, что вы создали два сквозных запроса. Первый запрос PT не требуется, но я просто подумал, что сохранить SQL будет проще. Мы используем два запроса PT, потому что я изменяю второй, и поэтому имя функции заменяется фактическим значением, которое функция возвращает. Итак, в следующий раз имя функции исчезнет из необработанного текста sql. Итак, каждый раз я беру свежий немодифицированный SQL из PT1 и модифицирую его, вставляю в PT2, а затем составляю отчеты или что-то еще, что может его использовать. - person Albert D. Kallal; 11.05.2019
comment
Я скопировал приведенный выше код, и когда я его компилирую, я получаю ошибку несоответствия типа в первом strSQL. - person House; 14.05.2019
comment
Ах хорошо. Я исправил выше. Я беру SQL, поэтому мне нужно свойство SQL. См. Редактирование выше: - person Albert D. Kallal; 15.05.2019
comment
@ Альберт, я не совсем уверен, что делать дальше. Я создал модуль и назвал его PT. Я скопировал приведенный выше код туда, где он начинается с CurrentDb.QueryDefs, а затем добавил End Sub. Я предполагаю, что это все, что должно быть в модуле, но, возможно, я ошибаюсь. Я не уверен, как выполнить этот код. У меня есть несколько запросов, которые я хочу сделать в качестве PT, и у меня есть несколько форм и отчетов, которые будут загружаться на основе этих запросов. Это также многопользовательская среда с отдельными номерами заданий, над которыми одновременно могут работать несколько пользователей. Прошу прощения за незнание. - person House; 15.05.2019
comment
И вы создали два запроса PT? После того, как вы запустите код, ваш второй запрос PT должен иметь фактическое значение. После запуска этого кода вы должны иметь возможность щелкнуть запрос PT на панели навигации, и он должен запуститься. На этом этапе вы можете использовать запрос PT2 для отчета, формы или даже источника набора записей в коде VBA. - person Albert D. Kallal; 15.05.2019
comment
Предполагается, что ваша база данных разделена. Каждая рабочая станция получает копию вашего приложения Access. Итак, этот код настроит PT2, а затем вы можете запустить форму или отчет или что угодно, что будет основано на PT2. - person Albert D. Kallal; 15.05.2019
comment
@ AlbertD.Kallal Да, у меня есть PT1 и PT2. Я создал модуль под названием Module1 с приведенным ниже кодом. Как мне запустить этот модуль? Sub MyOraclePT () Dim strSQL As String strSQL = CurrentDb.QueryDefs (PT1) .SQL '‹- это изменение strSQL = Replace (strSQL, GET_QAQC_JOB (), GET_QAQC_JOB ()) CurrentDb.QueryDefs (PT2) .SQL = strSQL End Sub. - person House; 15.05.2019
comment
Я понял, как это сделать. Спасибо за помощь, Альберт !! Это будет огромным подспорьем! - person House; 16.05.2019
comment
@ AlbertD.Kallal Я просмотрел свою базу данных и создал все запросы PT, а затем изменил источник записи форм на новый запрос PT. У меня две проблемы. Во-первых, во вспомогательной форме не будет отображаться информация, потому что связанные поля неверны, и я не могу выбрать новые. Вторая проблема заключается в том, что когда я пытаюсь добавить записи или редактировать данные, он сообщает мне, что набор записей не обновляется. - person House; 20.05.2019
comment
но зачем вы тратите все усилия на выполнение всевозможных запросов PT? В 9 из 10 случаев вам не нужно (или вы не хотите) использовать PT-запрос. Они доступны только для чтения. Прочтите этот мой пост и прочтите его несколько раз: utteraccess.com/forum /index.php?showtopic=2053744&hl= - person Albert D. Kallal; 21.05.2019
comment
В этом есть смысл. Я тоже думал об этом вчера, когда возился с этим. Спасибо, что поправили меня. ;) - person House; 21.05.2019

Предполагая, что функция является функцией, написанной на VBA в Access, вы не можете вызвать ее из запроса. Я считаю, что DML в запросе полностью отправляется исходной системе, в данном случае Oracle. Oracle не знает, что это за функция, и ошибки.

Вариант-1: отправьте запрос через ADO.NET в VBA.

Откажитесь от объектов сквозного запроса в Access. Выполните запрос от VBA, подключившись к Oracle через ADO или что-то в этом роде. Существует множество ресурсов о том, как использовать ADO для извлечения данных из внешних источников данных, таких как Как открыть ADO Connection и объекты Recordset. Вот пример использования DAO.

Вариант 2: заключить сквозной запрос в другой запрос

Access позволяет создавать запросы, вызывающие другие запросы. Создайте сквозной запрос без предиката WHERE. Это сквозной запрос. Создайте другой запрос доступа, который вызывает сквозной запрос. Это запрос на упаковку. Запрос-оболочка (начиная с его собственного SQL Access) должен иметь параметр, который вы используете для фильтрации набора результатов.

Полное раскрытие. Я не пробовал этого с Oracle.

Теперь, если сквозной запрос захватывает много данных. Этот вариант не работает.

Вариант 3: динамическое создание сквозного запроса

У вас есть событие (нажатие кнопки или что-то еще), вызывающее подпроцедуру VBA, которая динамически создает и назначает SQL для запроса:

Public Sub foo()
    Let qaqc_job_number = GET_QAQC_JOB()
    Set Query = CurrentDb.QueryDefs("<your-pass-thru-function-name>")

    Let sql_job_data = "SELECT" & _
                       "CC_QAQC_SPEC_MASTER.JOBNUMBER, " & _
                       "CC_QAQC_SPEC_MASTER.SPECSECTION, " & _
                       "CC_QAQC_SPEC_MASTER.SPECDESCRIPTION, " & _
                       "CC_QAQC_SPEC_MASTER.ID " & _
                       "FROM " & _
                       "CC_QAQC_SPEC_MASTER " & _
                       "WHERE " & _
                       "CC_QAQC_SPEC_MASTER.JOBNUMBER)= " & qaqc_job_number & " " & _
                       "Order BY " & _
                       "CC_QAQC_SPEC_MASTER.SPECSECTION, " & _
                       "CC_QAQC_SPEC_MASTER.SPECDESCRIPTION; "

    Let Query.Sql = sql_job_data

End Sub

Затем вы запускаете запрос.

Все, что есть в SQL, который вы вставляете в этот объект запроса Access, должно существовать в Oracle и ТОЛЬКО в Oracle.

person Adam    schedule 09.05.2019