tags:

views:

1273

answers:

8

Occasionally, I have had to build a SQL string in VBA and execute it with Docmd.RunSql(). I have always built these strings by concatenating variables into the string, e.g:

Dim mysqlstring as String
mysqlstring = "INSERT INTO MyTable (Field1, Field2, Field3 ...) VALUES ("
mysqlstring = mysqlstring + Me.TextMyField1 + ", " 'parameter comments
mysqlstring = mysqlstring + Me.TextMyField2 + ", " 
mysqlstring = mysqlstring + Me.TextMyField3 + ", " 
...
mysqlstring = mysqlstring + ");"
Docmd.RunSql mysqlstring

VBA doesn't seem to have a unary concatenation operator (like +=) and while this doesn't look ideal, at least I can comment each of my parameters and change them independently. It makes it easier to read and to change than one monster concatenated string. But it still seems like a terrible way to build SQL strings. I have one with about 50 parameters at work, so 50 lines of mysqlstring = mysqlstring +.... Not cute.

Incidentally, that rules out the use of line-continuations to format the string, as there is a limit on the number of line-continuations you can use on a single string (hint: less than 50). Also, VBA doesn't let you put a comment after the line-continuation, grr!

Up until recently, I thought this was the only way to build these strings. But recently I have seen a different pattern, injecting the parameters in the string like this question (VB.NET) that I posted an answer on, and wondered if there was an equivalent of Parameters.AddWithValue() for VBA, or if that would even be any better than the string concatenation approach. So I figured that this deserves its own question. Maybe there's something I'm missing here.

Can some of the Access experts please clarify what are the best practices for building SQL strings in Access/VBA.

+6  A: 

OK, i think i know what your intensions are, and i think i got what you need

You can try this

    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
astander
+1  A: 

I would use the approach above, with each parameter on a separate line it is nice and easy to debug and add to.

If however you really did not like that way then you could look at a parameter query. Slightly less flexible but in some cases slightly quicker.

Or another way would be to define a public function for inserting into that table and pass the values to it as parameters.

I however would stick with what you have got but it would be nice if VBA would understand =+

Kevin Ross
There are more advantages to parameters (in both SQL code and data access middleware) than performance e.g. strong data typing, default parameter values, SQL injection protection, escaping special characters, etc. Also, I'm sure there are cases where a Access Database Engine PROCEDURE actually performs worse than dynamic SQL.
onedaywhen
Agreed that parameter queries do offer lots of benefits. I only mentioned the performance side of things as a possible side effect as access would hold the query plan and not have to work it out like it would with a SQL statement generated on the fly.Having said that with modern hardware I doubt you would notice any difference so there are lots of reasons to use parameter quires but performance very low on the list
Kevin Ross
I wold suggest editing your posting to change the wording of "I would use the approach above," to include the posters name. Depending on how the questions are viewed, newest, oldest and votes the sequence of the answers can change.
Tony Toews
Sorry Tony I'm a bit new to this site and I'm used to a normal forum where the order does not change. I will change my posting style to refer to posts by name
Kevin Ross
Kevin, I hear you. I'm a long time Fidonet BBS/NNTP guy myself so this online forum stuff takes a bit getting used to.
Tony Toews
+4  A: 

Adding to what @astander has said, you could create a querydef (with parameters) and save it as part of the database.

e.g.

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

Assume, you saved it with a name myTableInsert, you could write the code as below

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

Note: I have not tested this piece of code. But, I am guessing this should be it.
Hope this gives you enough info to get started.

shahkalpesh
Interesting. Will the saved querydef myTableInsert show up in the Queries list?
Dale Halliwell
Yes. You will have to create it with the INSERT query with PARAMETERS clause, as shown above.
shahkalpesh
As I stated in my post, you do not have to create a query, you can create a temporary query by using only the sql argument of CreateQueryDef. Please see the link provided for more details.
Remou
@Remou: I don't know, how is it different than writing SQL in the code. With an existing querydef, your SQL is part of the query which gets stored in the db. I like your example, but it still requires a big query to be written in the VB code, which is what I don't think is needed. I hope you read this :)
shahkalpesh
+1  A: 

You can store your sql strings in a table, which can make life easier.

Set qdf = db.CreateQueryDef("", DLookup("SQLText", "SQLData", _
        "QueryName='AddCompany'"))

qdf.Parameters!txtCompany = Trim(frm!txtCompany)

Note

CreateQueryDef(""

Because the query is created without a name, it will not be stored - it is a temporary query (http://msdn.microsoft.com/en-us/library/bb243014.aspx).

The main disadvantage of parameters is that you cannot use them with memo data type as they will only accept 255 characters. This is quite a limitation. Because of this, when appending a record from a form, I would use a recordset.

Remou
Agreed about limitation of PROCEDURES with arguments of type MEMO but my experience is even more extreme in that I cannot get them to work with more than *two* characters!
onedaywhen
So why the down votes?
Remou
@Remou: "So why the down votes" -- not I. I can't say I like your approach to storing SQL code in a table, reinventing the wheel and all that (e.g. how to GRANT/REVOKE privileges?) You made a good point about MEMO parameter values so that's neutral in my book. Out of interest, do *you* always give a supporting comment when down-voting?
onedaywhen
The SQL store in the table is for use in code, which relates to the question, not for general use. There are a number of advantages including: the SQL can be set out neatly, comments can be included in such a table, it can be categorized, and it does not clutter up the code.
Remou
I voted it down because storing SQL strings in a table is a recipe for disaster. Use the provided facilities for storing SQL, i.e., in Access, QueryDefs, in another database, views and sprocs, or the SQL properties of Access objects (Recordsource of form/report) and controls (rowsource of Combobox/Listbox).
David-W-Fenton
Also, storing the SQL in a table doesn't really address the question here, which was constructing the VALUES clause of an INSERT statement.
David-W-Fenton
I should like to know which disasters could arise from getting string data from a table, after all, Acces queries are stored in system tables.
Remou
The queries stored in the system tables are accessible through the DAO object model. Those stored in your own tables are accessible only via code. This leads to a maintenance nightmare, in my opinion, and for no real benefit.
David-W-Fenton
A: 

One of the things I've done in the past is create a system for parsing SQL code to find parameters and storing the parameters in a table. I would write my MySQL queries outside of Access. Then all I had to do was open the file from Access and it would be ready to be updated on the fly each time I wanted to run it.

It was a really complicated process, but I'd be happy to dig up the code next week when I get back to work if you're interested.

Ben McCormack
+6  A: 

I have a timesheet app with a reasonably complex unbound labour transaction entry form. There is a lot of data validation, rate calculation and other code. I decided to use the following to create my SQL Insert/Update fields.

The variables strSQLInsert, strSQLValues, strSQLUpdate are form level strings.

Many lines of the following:

Call CreateSQLString("[transJobCategoryBillingTypesID]", lngJobCategoryBillingTypesID)

followed by:

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

Note that the Mid lines remove the leading ", ". lngTrans is the value of the 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

I see that the other posters are all using the Execute method. The problem with DoCmd.RunSQL is that it can ignore errors. Either of the following will display any error messages received by the query. If using DAO, use Currentdb.Execute strSQL,dbfailonerror.. For ADO use CurrentProject.Connection.Execute strCommand, lngRecordsAffected, adCmdText You can then remove the docmd.setwarnings lines.

If you're going to use docmd.setwarnings make very sure you put the True statement in any error handling code as well. Otherwise weird things may happen later on especially while you are working on the app. For example you will no longer get the "Do you wish to save your changes" message if you close an object. This may mean that unwanted changes, deletions or additions will be saved to your MDB.

Also performance can be significantly different between the two methods. One posting stated currentdb.execute took two seconds while docmd.runsql took eight seconds. As always YMMV.

Tony Toews
If you use CurrentDB, rather than assigning CurrentDB to a variable, you cannot return the records affected.
Remou
True enough, I keep forgetting about that detail. I have a snippet of code to deal with that situation.
Tony Toews
And you can't use SELECT @IDENTITY for getting the Autonumber PK of the last insert.
David-W-Fenton
+1  A: 

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.

David-W-Fenton
Sounds to me like you are reinventing the wheel. The Access Database Engine has strongly-typed PROCEDUREs with support for default values. The popular data access middleware (DAO, ADO, etc) already have support for parameters (DAO, OLE DB providers, etc) and their drivers/providers are already coded to convert values to SQL code (or lower). Why do you suppose you can do a better job?
onedaywhen
...ah, now I see you are recommending parameters after all!
onedaywhen
Your hostility to native Access terminology does not make your comments and answers more helpful. They aren't called "procedures" in Access. The only place involving Jet/ACE were that term comes in is in ADO DML or SQL92 DML statements. In Access the term is "parameter query." That has existed in Access/Jet as long as I've been using it, i.e., dating back to Access 2 (i.e., 1994).
David-W-Fenton
@David W. Fenton: you've missed the point: not 'hostility', I merely prefer the more explicit terms. For me, 'query' means something that returns a resultset, hence 'delete query' is an oxymoron. PROCEDURE (SQL keyword in upper case) makes it explicit this is a persistent SQL object, whereas you can implement a 'parameter query' in data access middleware. I suppose you could use 'Query' but this is an Access GUI convenience that groups VIEWs and PROCEDUREs into one tab but you lose granularity along the way.
onedaywhen
What I am 'hostile' to is terms that mislead: 'Table Validation Rule' is actually at the row level; the message in the Access GUI Table Design that tells you that a PK is required to define a Relationship (when you can use a UNIQUE constraint key when enforcing referential integrity and no key at all when not);...
onedaywhen
...plus many examples of functionality described in the documentation don't actually exist: CREATE TEMPORARY TABLE, LIMIT TO nn ROWS, ON UPDATE SET NULL, etc). Then there's all the functionality that does officially exist but has never been properly documented by Microsoft...
onedaywhen
But on the question of using 'VIEWs and PROCEDUREs' over 'Query objects' or similar I merely see it as a lifestyle choice. Sure, I happen to think my preference is best because it is more explicit but I try to avoid being hostile to other's usage of terminology. Now for you, David W. Fenton, who does not like people referring to what the Access Team calls the 'Access Database Engine' as 'Access', who has failed to embrace the terminology (and probably the functionality) introduced in Jet 4.0, what's your defense?
onedaywhen
You mis-use the term "Access Database Engine," i.e., using it too broadly to apply to past versions of Jet. It's also a bad choice on the part of the Access team to brand it with a name that confuses people (which it does -- the confusion between Access the development tool and Access's default database engine often makes it hard for people to get their questions answered). When the Access team shoved ADO down our throats and said we should use it, I ignored it, and it turned out I was right to do so in the long run, so I don't think everything they do is gospel.
David-W-Fenton
As to the issue of Access terminology, the fact that you find the terminology inconsistent with that which is used in other contexts is neither here nor there when the questions are being raised by people USING Access. Use of non-Access terms is as likely to confuse as clarify, and that's why I criticize you when you do it, because IT'S NOT HELPFUL.
David-W-Fenton
I believe I use the term "Access Database Engine" the same way as the Microsoft sites do i.e. to refer to the past, present and future versions of the engine. YOU use Access to refer to both the RAD development environment elements (Forms, VBA, etc) and the 'SQL management studio' elements (QBE, Table Design, etc) which I consider to be completely distinct because people in my office use it extensively for the latter and never for the former. But who cares what I say when Microsoft and the whole world use 'Access' to refer to everything, even engine-specific elements.
onedaywhen
So your opinion that PROCEDURE, VIEW, CHECK and anything else that takes your fancy is "not Access" is not only subjective, quite frankly, it's bogus (not to mention smart arse and boring). I think you only find it unhelpful yourself because you seem to have a 'psychological' problem when it comes to learning anything beyond your own experience e.g. you thought CHECK DDL maps to Validation Rule. I can easily demonstrate your ignorance but what I can't seem to do jolt you into action e.g. where you say to yourself, "Gosh, they're right. I'll find out about CHECK constraints today!"
onedaywhen
Again, you misread (seemingly willfully). The question is TERMINOLOGICAL -- PROCEDURE, VIEW, CHECK are not used in the Access UI or most of the Access documentation. Thus, your use of them is going to be foreign to users of Access, unless those users happen to be familiar with your pet terminological choices from outside exposure. If you're answering Access questions, at the very least, you should provide the Access "synonyms" for the non-native terminology that you are using.
David-W-Fenton
Table-level validation rules are a subset of CHECK constraints. Just as you have wrongly stated that Jet/ACE did not have "procedures" before Jet 4 (when it had "procedures" to exactly the same degree before as after, i.e., in Access terms, parameter queries), you again seem to think that everything that you seem to care about in Jet 4 did not exist until then. This blind spot is present in an awful lot of your posts, precisely because you're not an Access programmer. Because of that, your answers are often misleading and less helpful than they could be.
David-W-Fenton
When people use "Access" to refer to everything, they constantly confuse the discussion. That is quite obvious in thread after thread on Stackoverflow, and in many Access discussion forums I've participated in (starting in 1996, BTW). When people don't distinguish the development environment from the database engine, their questions are unclear and often require followup questions before someone can provide a useful answer. Microsoft may be using the term "Access Database Engine" but this is an unwise choice, in my opinion (just as ADO was unwise) and I'm not going to propagate it.
David-W-Fenton
"Table-level validation rules[sic]" -- if you are referring to Table Validation Rules (note the exact wording and casing) they are actually row-level validation rules. If they were table-level they would be able to refer to other rows in the same table. Because they cannot, they are row-level validation rules. Therefore, either use the term 'Table Validation Rule' or 'row-level validation rules' as you prefer (you may want to use 'record' in place of 'row').
onedaywhen
"[Table Validation Rules] are a subset of CHECK constraints." -- no, they are entirely different beasts. You can get a CHECK constraint to function fairly similarly to its equivalent Validation Rule but they have different semantics: their timing of their checking is different, the way the error is raised is different, etc. So what about your validation rules (lower case = logical meaning) that cannot be implemented using Validation Rules (upper case = physical object)? Do you simply miss them out, hoping your front end applications will refrain from attempting to write illegal values?
onedaywhen
"you have wrongly stated that Jet/ACE did not have "procedures" before Jet 4 (when it had "procedures" to exactly the same degree before as after, i.e., in Access terms, parameter queries)" -- the PROCEDURE SQL DDL adds the ability to include default values to parameters and that didn't existing before Jet 4.0.
onedaywhen
"non-native terminology" -- as I've pointed out, this is completely bogus. For example, can you tell me what the 'native' terminology for a CHECK constraint is? You cannot because, as we determined a while ago, when you say 'native' you really mean 'traditional' i.e. ANSI-89 Query Mode... oops, that's a modern term :) That is, 'traditional' as in 'before Jet 4.0'. The trouble is, you think 'traditional' is somehow superior. Do yourself a favour: update your skillset a little and find out how CHECK constraints work. Don't use tradition as an excuse for ignorance ;)
onedaywhen
"you should provide the Access "synonyms" for the non-native terminology that you are using" -- admittedly this is a good idea and something I used to do in the newsgroups. The problem is the 'synonyms' tend to be quite wordy e.g. a VIEW would be "a persisted database object defined using a non-parameterized SELECT query that returns a resultset (i.e. does not include an INTO clause) without an ORDER BY clause, which appears in the Access UI grouped together with PROCEDUREs on the 'Queries' tab" or similar. Perhaps better to hyperlink to the Wikipedia article for Standard SQL VIEW.
onedaywhen
Are you trying to help Access users or not? If not, then stop posting in Access discussions. I'm done with this, as it's impossible to address all the crap you're throwing out in comments.
David-W-Fenton
CHECK constraints blow your arguments out of the water, so run away: set the DeLorean for 1995, Doc Brown, ignorance is bliss ;)
onedaywhen
"Are you trying to help Access users": in the context of Stackoverflow, of course! Specifically, get the SQL layer right. Constraints, validation rules, etc in DDL not Forms. Use VIEWs and PROCEDUREs rather than SQL in VBA, control's properties, etc. This way you stand a chance of having something to port when the prototype moves to a 'proper' SQL product.
onedaywhen
Explain how Jet lacked CHECK CONSTRAINTS as defined in http://www.w3schools.com/Sql/sql_check.asp or http://www.sql.org/sql-database/postgresql/manual/ddl-constraints.html or http://en.wikipedia.org/wiki/Check_Constraint or http://www.aspfree.com/c/a/Database-Code/Constraints-In-Microsoft-SQL-SERVER-2000/6/ . These all look like Jet/ACE's field-level and table-level validation rules. None of those articles describes anything but row-level constraints.
David-W-Fenton
If I went to a forum with its own terminology and customs for help, I'd try to adopt to the terminology and customs of that forum. If I then started using non-customary terminology I don't think the users of that forum would be out of line in cricitizing me for doing so and asking me to conform with local custom. If you want Access users to understand what you mean in your campaign to educate the primitive natives, you should at least provide a translation into the language of the locals. You should also avoid the kind of false categoricals your comments are littered with.
David-W-Fenton
You are asking me to explain why those sources do not mention table-level CHECK constraints? I'll try. Open your copy of the ISO/ANSI SQL-92 spec, 11.9 'check constraint definition', Leveling Rules: "The following restrictions apply for Intermediate SQL: a) The search condition contained in a check constraint definition shall not contain a subquery." In layman's terms: for full SQL-92 compliance a CHECK constraint's definition must be able to include a subquery (with restrictions) but is not a requirement for intermediate or entry level compliance.
onedaywhen
...my guess is that that the committee realised that most SQL encubant vendors would not be easily would find it very difficult to support subqueries, therefore restricted it to full SQL-92 compliance. When the SQL Server team was driving Access Database Engine development they rose to the challenge and implemented section 11.9 to full SQL-92 compliance, yeah for them! I know of no other SQL product that has achieved this. So I guess the rarity of the situation is the reason why examples are hard to come by.
onedaywhen
...unless you look in the right places. Did you think to try Microsoft's own documentation? e.g."Description of the new features that are included in Microsoft Jet 4.0" (http://support.microsoft.com/kb/275561): "...Check Constraints. This new SQL grammar allows the user to specify business rules that can span more than one table..."
onedaywhen
"ACC2000: How to Create a Jet CHECK Constraint" (http://support.microsoft.com/kb/201888/EN-US/): " The new SQL grammar exposed by Microsoft Jet database engine version 4.0 allows users to specify business rules that can span more than one table. These are called check constraints and allow users to exceed a single validation rule per table..."
onedaywhen
"If I went to a forum with its own terminology and customs for help, I'd try to adopt to the terminology and customs of that forum." Sounds good to me. As you know, the typical Stackoverflow user has been exposed to other SQL products and will therefore have an appreciation of Standard SQL e.g a Query object won't mean much to them (especially in if you mistakenly use 'query'), whereas a VIEW will. I think that SO is for generic software engineers and that an Access-only Power User will have more luck in a dedicated Access forum. Otherwise, they can look up what a VIEW (or whatever) means.
onedaywhen
"your campaign to educate the primitive natives, you should at least provide a translation into the language of the locals" -- He he. This reminds me of something Joe Celko often quotes: "Pardon him. Theodotus: he is a barbarian, and thinks that the customs of his tribe and island are the laws of nature." Would I have to say 'records' rather than 'rows'? Would I have to say 'a DELETE Query' even though DELETE is a statement rather than a query? No, I use the 'proper' terms in the hope that folk will gravitate towards 'proper' SQL products.
onedaywhen
...I tell you what: how about a bit of give an take? You start using the generic/Standard/StackOverflow-friendly terms in addition to your Access ghetto speak and I'll try to reciprocate? Wadda ya say, dude? (Do we have an agreement, chum?)
onedaywhen
"You should also avoid the kind of false categoricals your comments are littered with" -- you should know that I'm willing to put in the time and effort to do research, post links, write code examples, explain in detail. But if you are going to make a general statement then run away I stand no chance of helping you. Maybe I did make a misstatement. Give me specifics!
onedaywhen
This is completely ridiculous. It is simply not possible to carry on this discussion in comments, as there's no threading and it's required to repeat your comments in order to address them. This is not worth it, as no reasonable discussion is possible here.
David-W-Fenton
In regard to false categoricals, the first 4 or 5 of your comments above demonstrate that you're using a non-standard definition of "CHECK CONSTRAINT," limiting it to ones that span tables. But everywhere I look, it means a lot more than that, including what Access terminology calls "field-level validation rules" and "table-level validation rules." Indeed, with the exception of the Wikipiedia article, the URLs I cited didn't even mention cross-table check constraints. YOU ARE WRONG IN WHAT YOU ASSERTED -- Jet did not first acquire CHECK CONSTRAINTS with v. 4, just one advanced form of them.
David-W-Fenton
I'm not here to help general SO users. I'm here to help people using Access. Thus, unless the question begins with "I'm familiar with Oracle/SQL Server/MySQL/blah, but I'm now working with Access. I need to do X. How do I do it?" I'm going to use Access terminology. In the case with that preface, I'd use generic SQL terminology (insofar as the question was a SQL question, which is not usually what people experienced with other DBs are going to be asking about in regard to Access), but for Access users, I'd use Access terminology. This seems like common sense to me.
David-W-Fenton
I see no utility in continuing this discussion in this forum. It's impossible in comments and not appropriate as a question on SO. You have clearly erred in what you've said so just admit it and let it go.
David-W-Fenton
'My' definition of CHECK constraints is indeed standard because it comes from the SQL-92 Standard. When you are referring to a generic concept, use loser case 'validation rules'; when you are referring to a specific Access object please use title case i.e. Validation Rule. A CHECK constraint is a validation rule (lower case) but it is not a Validation Rule (title case). The CHECK DLL cannot be used to create a Validation Rule, there is no direct mapping. I can write a CHECK constraint to be equivalent to a UNIQUE or PRIMARY KEY constraint but that does not mean they are the same thing!
onedaywhen
Sounds like you still haven't taken up my challenge of creating and using a CHECK constraint that cannot be achieved using a Validation Rule object (e.g. preventing overlapping periods). Until you use them you will not understand them. If you think my assertions are wrong then you still have some learning to do. Ignore them and you remain ignorant. You want to move to another forum? Send me a PM.
onedaywhen
There is no database engine that fully implementes SQL 92. This discussion is over.
David-W-Fenton
I thought you were the guy who likes people to use the correct language? You are again being ambiguous (on purpose?) Many (most?) SQLs are fully compliant with 'entry level SQL-92' e.g. Oracle and SQL Server. A few are fully compliant with 'intermediate level SQL-92' e.g. Mimer. Then there is 'full SQL-92'. I believe postgre is a close as any implementation can be to FULL-92 compliance (there are things in the Standard that even the writers in retrospect admit probably shouldn't have been included).
onedaywhen
This talk of Standard gets me thinking again... Validation Rules (title case = objects) presumably were added to the Access Database Engine before the SQL-92 Standard was something the product could aspire to. In other words, the CHECK constraint simply did not apply. However, from Jet 4.0, the SCHEMA INFORMATION (another SQL-92 introduction) exposes the CHECK_CONSTRAINTS rowset (http://msdn.microsoft.com/en-us/library/ms806250.aspx) and for both the Jet and ACE OLE DB providers this rowset does indeed include Validation Rules. So on some level Validation Rule equates to a CHECK constraint.
onedaywhen
However, on another level they are not the same. A row level Validation Rule (title case = object) can for example have the definition = 1. However, this is not a valid definition for a CHECK constraint. A Validation Rule is a *property* of a column or a table and is restricted to one per object, whereas a CHECK is a CONSRAINT (upper case = SQL keyword), hence a Validation Rule cannot be created using CREATE/ALTER TABLE DDL whereas a CHECK can and there is no notional restriction on the number of CHECKs per table.
onedaywhen
Each Validation Rule can have its own explicit failure message, whereas CHECK failures always result in a generic message (but you can give the CHECK a meaningful CONSTRAINT name which does appear in the message, hence conveys meaning).
onedaywhen
But the big difference is that a CHECK is truly table level, is always table level and can include a subquery. This is may sound like a small technical difference but is in fact of crucial significance because, without it, the Access Database Engine would be useless at creating certain keys e.g. a sequenced primary key in a valid-state temporal table, a very common construct. It goes without saying that an engine unable to create keys on base tables would not be fit for purpose.
onedaywhen
I haven't read any of your most recent comments and have no intention of doing so. You get to have the last word.
David-W-Fenton
A: 

FWIW, I use a slightly different format, using Access's line break character "_". I also use the concatenation operator "&". The main reason is for readability:

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
maxhugen