2009-09-09 4 views
1

Я хочу выполнить список запросов в базе данных Access с помощью DAO. Метод «Database.Execute()» подходит для этого с замечанием о том, что он может выполнять только «запросы действий», то есть запросы, которые не возвращают набор результатов (MSDN reference). Для запросов, которые возвращают записи, можно использовать «Database.OpenRecordset()». Оба метода генерируют исключения, если передается неверный тип запроса.Выполнение запросов с использованием DAO

Имея как запросы действий, так и выбирать запросы в списке, как я могу решить, что будет возвращать записи, а какие нет?

+1

Почему вы даже хотите выполнять запросы, которые являются SELECT, только если вы не собираетесь отображать их для пользователя? Что вы не должны делать в Access, если вы не используете форму или отчет. –

+1

Вам действительно нужно объяснить, что вы пытаетесь выполнить, поскольку выполнение произвольной последовательности запросов SELECT и DML не имеет никакого смысла в реальном мире. –

+1

Это имеет смысл для (единичных) целей тестирования, когда вы хотите проверить уровень доступа к данным: проверьте состояние до/после и, возможно, вернитесь в какое-то состояние. – MicSim

ответ

1

Вдохновленный ответом @ HansUp, я немного исследовал структуру QueryDef, предоставляемую интерфейсом DAO. Структура имеет свойство «Тип», которое я могу использовать для различения различных типов запросов (MSDN). В результате я получил следующую реализацию:

function TAccessDatabase.SQLExec(AName, AQuery: String): Integer; 
var 
    I: Integer; 
    QDef: QueryDef; 
    QDefExists: Boolean; 
begin 
    Result := 0; 

    // Lookup querydef in the database 
    QDefExists := False; 
    for I := 0 to DB.QueryDefs.Count - 1 do 
    begin 
    QDef := DB.QueryDefs[I]; 
    if QDef.Name = AName then 
    begin 
     QDefExists := True; 
     break; //--> 
    end; 
    end; 

    // Create query def if it doesn't exists 
    if not QDefExists then 
    begin 
    QDef := DB.CreateQueryDef(AName, AQuery); 
    // Refresh is required to get the correct QDef.Type_ 
    DB.QueryDefs.Refresh; 
    end; 

    // Execute the query only if it is not a SELECT 
    if QDef.Type_ <> dbQSelect then 
    begin 
    db.Execute(AQuery, dbInconsistent); 
    Result := DB.RecordsAffected; 
    end; 
end; 

Благодарим всех вас за полезные ответы и замечания.

+0

Извините, я полностью забыл тег Delphi. Мне нравится ваш подход QueryDef Type лучше, чем MSysObjects Flags. – HansUp

+0

@ HansUp Теперь, когда вы сказали, что принятие моего собственного ответа не будет ощущать это странно. Еще раз спасибо за подсказки. – Tihauan

-1

Эта информация относится к типу запроса. Итак:

  • Все запросы, которые выполняются в SELECT ... FROM ... являются выберите запросы
  • Все ВСТАВИТЬ, UPDATE, DELETE являются действие запросов

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

+0

«Все запросы, которые выполняют SELECT ... FROM ... - это выборные запросы», - но это не приводит к возврату набора результатов, например. подумайте, содержит ли запрос запрос SQL DDL CREATE VIEW MyView AS SELECT CustomerID FROM Customers; – onedaywhen

+0

Это не запрос SELECT, это запрос CREATE и не даст никакого результата ... Этот был бы в категории «запрос действия», как истинный со всеми запросами DDL. – MicSim

+0

Итак, вернемся к исходному вопросу: «Как я могу решить, что будет возвращать записи, а какие нет?» Иными словами, как вы скажете, вернет ли запрос, содержащий ключевое слово SELECT, набор результатов? INSERT INTO..SELECT .. - еще одна примерная конструкция. – onedaywhen

1

Обратите внимание, что метод ADO Execute может использоваться независимо от того, возвращает ли запрос набор результатов.

Но вы действительно хотите выполнить все «запросы»? Что делать, если они содержат SQL DDL? Рассмотрим вы создали PROCEDURE с помощью этого SQL кода DDL:

CREATE PROCEDURE qryDropMe AS DROP PROCEDURE qryDropMe; 

;)

1

Access поддерживает скрытую систему таблиц, называемых MSysObjects, которая включает в себя поле (Flags), которая хранит значение, указывающее тип запроса. Вы можете попробовать следующую функцию с каждым из имен запросов из своего списка и использовать возвращаемое значение, чтобы определить, следует ли использовать Database.Execute() или Database.OpenRecordset()

Функция требует разрешения на чтение для MSysObjects. Я слышал отчеты, чем некоторым пользователям Access 2007 было отказано в разрешении читать MSysObjects. Тем не менее, я не сталкивался с этой проблемой с Access 2007.

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

Единственный DDL-запрос, который я тестировал, был DROP TABLE (Flags = 96).

Кроме того, помните, что не все запросы «SELECT ... FROM ...» - это выбор запросов для вашей цели (возврат набора записей). Запрос, такой как «SELECT полей INTO newtable FROM oldtable;» не возвращает записи, а пользовательский интерфейс доступа классифицирует его как запрос Make Table.

Public Function QueryType(ByVal pQueryName As String) As String 
    Dim lngFlags As Long 
    Dim strType As String 
    Dim strCriteria As String 

    strCriteria = "[Name] = """ & pQueryName & """ And [Type] = 5" 
    lngFlags = DLookup("Flags", "MSysObjects", strCriteria) 

    Select Case lngFlags 
    Case 0 
     strType = "Select" 
    Case 16 
     strType = "Crosstab" 
    Case 32 
     strType = "Delete" 
    Case 48 
     strType = "Update" 
    Case 64 
     strType = "Append" 
    Case 80 
     strType = "Make Table" 
    Case 96 
     strType = "Drop Table" 
    Case 128 
     strType = "Union" 
    Case Else 
     strType = "Flags " & CStr(lngFlags) & " unrecognized" 
    End Select 

    QueryType = strType 
End Function 
+1

Логически, UPDATE - это DELETE и INSERT. Вышеизложенное предполагает, что для механизма базы данных Access UPDATE является DELETE и кросс-таблицей! – onedaywhen

+0

Onedaywhen. Как UPDATE не обновляет все поля в записи логическим DELETE и INSERT? –

+0

@oneday - я думаю, что вы читаете больше смысла там, где их нет - список флагов просто таков: список флагов –

0

Почему бы вам не уловить исключение и проанализировать его?

У вас есть способ использовать инструкцию beginTrans/Rollback?Затем вы можете отправить команду SQL, собрать ошибки, а затем отменить транзакции, оставив свою базу без изменений.

Как насчет использования соединения ADO, несколько более умного, чем ADO, где соединение содержит коллекцию «ошибки» и возвращает некоторые другие данные, такие как количество записей?

Смежные вопросы