Создание SQL представляет в виде строки в Access/VBA

То, что мы сделали, сделано, C ++\CLI возражают, что содержал строку в коде unmangaed и выделит manged копии объекта. Код преобразования смотрит очень как то, что Stan имеет на своем блоге (я не могу помнить его точно) (Если Вы используете его код, удостоверяются, что Вы обновляете его для использования, удаляют []), но мы удостоверились, что деструктор обработает выпуск всех unmanged элементов объекта. Это немного раздуто, но у нас не было утечек, когда мы набросились на модули кода C++ прежней версии.

15
задан Community 23 May 2017 в 12:01
поделиться

7 ответов

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

Переменные strSQLInsert, strSQLValues, strSQLUpdate - это строки уровня формы.

Многие строки следующего содержания:

Call CreateSQLString("[transJobCategoryBillingTypesID]", lngJobCategoryBillingTypesID)

, за которым следует:

If lngTransID = 0 Then
    strSQL = "INSERT into Transactions (" & Mid(strSQLInsert, 3) & ") VALUES (" & Mid(strSQLValues, 3) & ")"
Else
    strSQL = "UPDATE Transactions SET " & Mid(strSQLUpdate, 3) & " WHERE transID=" & lngTransID & ";"
End If

conn.Open
conn.Execute strSQL, lngRecordsAffected, adCmdText

Обратите внимание, что средние строки удаляют начальные символы ",". lngTrans - это значение autonumber primamy kay.

Sub CreateSQLString(strFieldName As String, varFieldValue As Variant, Optional blnZeroAsNull As Boolean)
'    Call CreateSQLString("[<fieldName>]", <fieldValue>)

Dim strFieldValue As String, OutputValue As Variant

    On Error GoTo tagError

    ' if 0 (zero) is supposed to be null
    If Not IsMissing(blnZeroAsNull) And blnZeroAsNull = True And varFieldValue = 0 Then
        OutputValue = "Null"
    ' if field is null, zero length or ''
    ElseIf IsNull(varFieldValue) Or Len(varFieldValue) = 0 Or varFieldValue = "''" Then
        OutputValue = "Null"
    Else
        OutputValue = varFieldValue
    End If

    ' Note that both Insert and update strings are updated as we may need the insert logic for inserting
    '    missing auto generated transactions when updating the main transaction
    ' This is an insert
    strSQLInsert = strSQLInsert & ", " & strFieldName
    strSQLValues = strSQLValues & ", " & OutputValue
    ' This is an update
    strSQLUpdate = strSQLUpdate & ", " & strFieldName & " = " & OutputValue

    On Error GoTo 0
    Exit Sub

tagError:

    MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure CreateSQLString of VBA Document Form_LabourEntry"
    Exit Sub
End Sub

Я вижу, что все другие плакаты используют метод Execute. Проблема с DoCmd.RunSQL в том, что он может игнорировать ошибки. Любое из следующих сообщений отобразит сообщения об ошибках, полученные по запросу. При использовании DAO используйте Currentdb.Execute strSQL, dbfailonerror .. Для ADO используйте CurrentProject.Connection.Execute strCommand, lngRecordsAffected, adCmdText Затем вы можете удалить строки docmd.setwarnings.

Если вы собираетесь использовать docmd.setnings очень уверен, что вы также поместили оператор True в любой код обработки ошибок. В противном случае позже могут произойти странные вещи, особенно когда вы работаете над приложением. Например, вы больше не будете получать сообщение «Вы хотите сохранить изменения», если закроете объект. Это может означать, что нежелательные изменения, удаления или добавления будут сохраняться в вашем MDB.

Также производительность этих двух методов может значительно отличаться. В одном сообщении говорилось, что currentdb.execute занял две секунды, а docmd.runsql - восемь секунд. Как всегда YMMV.

9
ответ дан 1 December 2019 в 03:52
поделиться

As others have said, it's probably better to utilize parameters in the first place. However, ...

I, too, have missed a concatenation operator, having become accustomed to .= in PHP. In a few cases, I've written a function to do it, though not specific to concatenating SQL strings. Here's the code for one I use for creating a query string for an HTTP GET:

  Public Sub AppendQueryString(strInput As String, _
       ByVal strAppend As String, Optional ByVal strOperator As String = "&")
    strAppend = StringReplace(strAppend, "&", "&amp;")
    strInput = strInput & strOperator & strAppend
  End Sub

And an example of where I've called it:

  AppendQueryString strOutput, "InventoryID=" & frm!InventoryID, vbNullstring
  AppendQueryString strOutput, "Author=" & URLEncode(frm!Author)

...and so forth.

Now, for constructing SQL WHERE clauses, you might consider something like that as a wrapper around Application.BuildCriteria:

  Public Sub ConcatenateWhere(ByRef strWhere As String, _
      strField As String, intDataType As Integer, ByVal varValue As Variant)
    If Len(strWhere) > 0 Then
       strWhere = strWhere & " AND "
    End If
    strWhere = strWhere & Application.BuildCriteria(strField, _
       intDataType, varValue)
  End Sub

You would then call that as:

  Dim strWhere As String

  ConcatenateWhere strWhere,"tblInventory.InventoryID", dbLong, 10036
  ConcatenateWhere strWhere,"tblInventory.OtherAuthors", dbText, "*Einstein*"
  Debug.Print strWhere
  strSQL = "SELECT tblInventory.* FROM tblInventory"
  strSQL = strSQL & " WHERE " & strWhere

...and the Debug.Print would output this string:

  tblInventory.InventoryID=10036 AND tblInventory.OtherAuthors Like "*Einstein*"

Variations on that might be more useful to you, i.e., you might want to have an optional concatenation operator (so you could have OR), but I'd likely do that by constructing a succession of WHERE strings and concatenating them with OR line by line in code, since you'd likely want to place your parentheses carefully to make sure the AND/OR priority is properly executed.

Now, none of this really addresses the concatenation of VALUES for an INSERT statement, but I question how often you're actually inserting literal values in an Access app. Unless you're using an unbound form for inserting records, you will be using a form to insert records, and thus no SQL statement at all. So, for VALUES clauses, it seems that in an Access app you shouldn't need this very often. If you are finding yourself needing to write VALUES clauses like this, I'd suggest you're not using Access properly.

That said, you could use something like this:

  Public Sub ConcatenateValues(ByRef strValues As String, _
      intDatatype As Integer, varValue As Variant)
    Dim strValue As String

    If Len(strValues) > 0 Then
       strValues = strValues & ", "
    End If
    Select Case intDatatype
      Case dbChar, dbMemo, dbText
        ' you might want to change this to escape internal double/single quotes
        strValue = Chr(34) & varValue & Chr(34)
      Case dbDate, dbTime
        strValue = "#" & varValue & "#"
      Case dbGUID
        ' this is only a guess
        strValues = Chr(34) & StringFromGUID(varValue) & Chr(34)
      Case dbBinary, dbLongBinary, dbVarBinary
        ' numeric?
      Case dbTimeStamp
        ' text? numeric?
      Case Else
        ' dbBigInt , dbBoolean, dbByte, dbCurrency, dbDecimal, 
        '   dbDouble, dbFloat, dbInteger, dbLong, dbNumeric, dbSingle
        strValue = varValue
    End Select
    strValues = strValues & strValue
  End Sub

...which would concatenate your values list, and then you could concatenate into your whole SQL string (between the parens of the VALUES() clause).

But as others have said, it's probably better to utilize parameters in the first place.

1
ответ дан 1 December 2019 в 03:52
поделиться

Одна из вещей, которые я делал в прошлом, - это создание системы для синтаксического анализа кода SQL с целью поиска параметров и сохранения параметров в таблице. Я бы писал свои MySQL-запросы вне Access. Тогда все, что мне нужно было сделать, это открыть файл из Access, и он будет готов к обновлению на лету каждый раз, когда я захочу его запустить.

Это был действительно сложный процесс, но я был бы счастлив откопать код на следующей неделе, когда я вернусь к работе, если вам интересно.

0
ответ дан 1 December 2019 в 03:52
поделиться

FWIW, я использую немного другой формат, используя символ разрыва строки "_" в Access. Я также использую оператор конкатенации «&». Основная причина - удобочитаемость:

Dim db as Database: Set db = Current Db
Dim sql$
sql= "INSERT INTO MyTable (Field1, Field2, Field3 ...Fieldn) " & _
     "VALUES (" & _
     Me.TextMyField1 & _
     "," & Me.TextMyField2 & _
     "," & Me.TextMyField3 & _
     ...
     "," & Me.TextMyFieldn & _
     ");"
db.Execute s
Set db = nothing
1
ответ дан 1 December 2019 в 03:52
поделиться

Добавив к тому, что сказал @astander, вы можете создать querydef (с параметрами) и сохранить его как часть базы данных.

например

Parameters dtBegin DateTime, dtEnd DateTime;
INSERT into myTable (datebegin, dateend) values (dtBegin, dtEnd)

Предположим, вы сохранили его с помощью name myTableInsert , вы можете написать код, как показано ниже

dim qd as QueryDef
set qd = CurrentDB.QueryDefs("myTableInsert")
qd.Parameters("dtBegin").Value = myTextFieldHavingBeginDate
qd.Parameters("dtEnd").Value = myTextFieldHavingEndDate    
qd.Execute

Примечание: я не тестировал этот фрагмент кода. Но, думаю, это должно быть так.
Надеюсь, это даст вам достаточно информации, чтобы начать работу.

4
ответ дан 1 December 2019 в 03:52
поделиться

Я бы использовал подход, описанный выше, с каждым параметром в отдельной строке, это приятно и легко отлаживать и добавлять к.

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

Другой способ - определить общедоступную функцию для вставки в эту таблицу и передать ей значения в качестве параметров.

Я бы, однако, придерживался того, что у вас есть, но было бы неплохо, если бы VBA понимал = +

0
ответ дан 1 December 2019 в 03:52
поделиться
    Private Sub Command0_Click()
Dim rec As Recordset2
Dim sql As String
Dim queryD As QueryDef

    'create a temp query def.
    Set queryD = CurrentDb.CreateQueryDef("", "SELECT * FROM [Table] WHERE Val = @Val")
    'set param vals
    queryD.Parameters("@Val").Value = "T"
    'execute query def
    Set rec = queryD.OpenRecordset
End Sub
4
ответ дан 1 December 2019 в 03:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: