То, что мы сделали, сделано, C ++\CLI возражают, что содержал строку в коде unmangaed и выделит manged копии объекта. Код преобразования смотрит очень как то, что Stan имеет на своем блоге (я не могу помнить его точно) (Если Вы используете его код, удостоверяются, что Вы обновляете его для использования, удаляют []), но мы удостоверились, что деструктор обработает выпуск всех unmanged элементов объекта. Это немного раздуто, но у нас не было утечек, когда мы набросились на модули кода C++ прежней версии.
У меня есть приложение для расписания с достаточно сложной формой записи несвязанных трудовых транзакций. Есть много проверок данных, расчета ставок и прочего кода. Я решил использовать следующее для создания полей для вставки и обновления 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.
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, "&", "&")
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.
Одна из вещей, которые я делал в прошлом, - это создание системы для синтаксического анализа кода SQL с целью поиска параметров и сохранения параметров в таблице. Я бы писал свои MySQL-запросы вне Access. Тогда все, что мне нужно было сделать, это открыть файл из Access, и он будет готов к обновлению на лету каждый раз, когда я захочу его запустить.
Это был действительно сложный процесс, но я был бы счастлив откопать код на следующей неделе, когда я вернусь к работе, если вам интересно.
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
Добавив к тому, что сказал @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
Примечание: я не тестировал этот фрагмент кода. Но, думаю, это должно быть так.
Надеюсь, это даст вам достаточно информации, чтобы начать работу.
Я бы использовал подход, описанный выше, с каждым параметром в отдельной строке, это приятно и легко отлаживать и добавлять к.
Однако если вам действительно не нравится этот способ, вы можете посмотрите на запрос параметров. Немного менее гибкий, но в некоторых случаях немного быстрее.
Другой способ - определить общедоступную функцию для вставки в эту таблицу и передать ей значения в качестве параметров.
Я бы, однако, придерживался того, что у вас есть, но было бы неплохо, если бы VBA понимал = +
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