ALTER TABLE Syntax Error - ms-access

I'm having trouble with an update query in Access.
I'm trying to do two things, add a field to a table, and change all values in another field to the same value.
ALTER TABLE 103 ADD COLUMN test TEXT;
UPDATE 103 SET [103].Workcenter = "103";
When I run these two lines independently, they work fine, but when I put them in the same query I get "Syntax Error in ALTER TABLE" statement. Does anyone know why I can't do this?
It would also be great if I could add a column and update all values in that field to a default value. I've tried DEFAULT in the ALTER TABLE command but it's not working either.
Thanks in advance for suggestions!

AS ron tornambe said, you can't have more than a single command in an Access Query. They do not support batching.
VBA code is your friend when doing alterations on tables: The Data Definition Language used in Access is more limited than what is available from VBA when directly manipulating the database objects.
For instance, to do exactly what you seek:
Public Sub AddFieldAndUpdate()
' Initialise '
Dim db As DAO.Database
Dim tb As DAO.TableDef
Dim fd As DAO.Field
Set db = CurrentDb()
' Get the 103 table '
Set tb = db.TableDefs("103")
' Create a new 'test' field, 128 char long '
Set fd = tb.CreateField("test", dbText, 128)
' Set the Default value for the new field '
fd.DefaultValue = "000"
' Add the new field to the 103 table
tb.Fields.Append fd
' Now do the update
db.Execute "UPDATE 103 SET [103].Workcenter = '103';", dbFailOnError
Debug.Print "Number of Updated records: " & db.RecordsAffected
' Cleanup
Set fd = Nothing
Set tb = Nothing
Set db = Nothing
End Sub
This is the jest of it, although you probably want to do more than that, for instance, set indexes, default formatting, etc as required.

Some table design features are only available when using the DAO object model to modify the TableDef. Others are only available when executing a DDL statement from an ADO connection.
Your table design change involves features which are available with either method. Use whichever you wish, but I would personally choose this way:
Dim strDdl As String
strDdl = "ALTER TABLE 103 ADD COLUMN test TEXT(128) DEFAULT ""000"";"
CurrentProject.Connection.Execute strDdl

Related

Access with 1 MySQL Table asking for credentials

I have a access database using a local sql server backend for all tables except 1 web based MySQL table. The MySQL table has 50 rows or so, 3 fields, not big at all. I have a odbc connection setup and the table is linked with the password saved. This table is updated 30 times per day at most... Sometimes the connection breaks and the MySQL connection popup will appear... clicking test will result in a success, and clicking ok will allow the code to proceed. It is doing a 1 line update (SET LastUpdatedDate = #" & now() & "# WHERE ItemID = 'xyz').
I want to capture an error, or get it to continue without the connection if it is unavailable... but it appears no error is generated. I would rather not update the table when this happens, then have to physically select ok to get it running again. This problem exists from multiple locations, on multiple PCs around the US. I assume it is the server the MySQL db is hosted on that is having problems - I just want to know how to ignore them and move on with the other code... again, no error generated (So On Error ... won't work). Any Ideas? Using Access 2016.
UPDATE: My current setup is to ping the server... and if the ping gets a response, I assume it is up... then I run 'CurrentDb.Execute "UPDATE XYZ SET ABC = 'DEF' WHERE GHI = 'JKL'". That simple. If I try to query the table XYZ and it isn't available, I get the same connection popup. How should I go about refreshing the table? Delete the link and recreate?
NEW UPDATE
Finally got around to try out the DSN-less pass through query proposed by Andre below. When I get to the 'execute' step I get an error saying I cannot execute a select query... but it is an update query. Here is the SQL string... .SQL = "UPDATE [Status] SET ItemDate = NOW() WHERE PlantID = '" & PlantID & "' AND ItemID = '" & ItemID & "'"
I suggest that instead of running an Access query on the linked table, you use a DSN-less Pass-Through query that you create on the fly.
This should either always work, or raise a trappable error.
Const ConnectString = "ODBC;DRIVER={MySQL ODBC 5.1 Driver};SERVER=your.server.com;PORT=3306;DATABASE=mydatabase;UID=myuserid;PWD=mypassword"
Dim qdf As DAO.QueryDef
Set qdf = CurrentDb.CreateQueryDef("")
With qdf
' Setting .Connect turns it into a Pass-Through query
.Connect = ConnectString
' Need to set this for non-SELECT queries
.ReturnsRecords = False
' Note: you need to use MySql syntax here, not Access SQL, especially the correct date format
.SQL = "UPDATE XYZ SET ABC = 'DEF' WHERE GHI = 'JKL'"
' or since MySql has a NOW() function too, just this:
.SQL = "UPDATE foo SET LastUpdatedDate = NOW() WHERE ItemID = 'xyz'"
.Execute
End With
You can also try a saved Pass-Through query, it might work as well. Then you would only need to supply the current .Sql, not the connect string.
Maybe you will get an helpful error if you execute your SQL command with the option dbFailOnError ? Like CurrentDB.Execute("Your SQL", dbFailOnError)
Before trying the UPDATE, do a simple SELECT. If it does not return a reasonable result, assume that the connection is down.

Howto write DDL ALTER TABLE Modify statement using string variable for TABLE name

In a loop I want to change for some fields the Type and Length programmatically.
With the DDL Statement ALTER Table Alter Column I was successful,
but only with the hardcoded table name. For the Field Name I could use
the a string variable.
As I wrote the table name TDF.Name, which was the product
of a "For each TDF" statement, and running this code:
Set dbs = CurrentDb()
For Each TDF In dbs.TableDefs
strfield = "M1"
strSQL = "ALTER TABLE TDF.Name ALTER COLUMN strField TEXT(5);"
DBEngine(0)(0).Execute strSQL, dbFailOnError
an error occured. "TDF.MDB" could not be found.
Please can somebody tell me the right Syntax for the
variables for the target database and table
table e.g. -> "databasename.MDB / tablename" ?
Many thanks in advance
Helmut Steinecker
The db engine doesn't know anything about TDF.Name and strField, so include their values in your DDL statement ...
strSQL = "ALTER TABLE [" & TDF.Name & "] ALTER COLUMN [" & strField & "] TEXT(5);"
Beware For Each TDF In dbs.TableDefs means the code will attempt to execute an ALTER TABLE against every table in the database, including system tables such as MSysObjects. I suggest you should not attempt to alter system tables ...
For Each TDF In dbs.TableDefs
If Not (TDF.Name Like "MSys*") Then
' ALTER TABLE
End If
Next
Many Thanks, HansUp,
Since I have read so many answers of yours,
I was hoping, you will answer and so:
You gave me the solution.
May I append a database Name to the table variable?
Since I had 255 fields, I got the famous - too many fields error message.
I will reduce the fields, and then, slowly, increase by
adding fields. With 600 tables, this will be another DDL statement.
but now I am on the way to success.
Many thanks from Bavaria, Ottobrunn, south of Munich.
Reducing the number of fields, mostly MEMO fields - for me, better than Text fields, for my purposes, did work. Now I have 6xLongInteger, 1xText, 241xMEMO fields and now I get no more the "Too Many Fields" message.

Corrupted Access 2010 database - recover query definitions

I have an Access DB, it's a local development copy, not production, and corrupted during (ironically) compact and repair, a large amount of data. Unfortunately I did a lot of work on it and I do have a backup plan but it failed me..
When I start it up it gives me useless error messages like:
'Id' is not an index in this table.
'ParentIdName' is not an index in this table.
I suppose these indexes are part of the hidden MSys* tables in the DB. I managed to read those and they're mostly empty while my older healthy backup has a lot of data in these tables.
First I tried to restore the healthy tables into the destroyed ones using VBA and an ADO connection (made a copy beforehand), I get a lot of errors saying I don't have write permissions on the tables.
Next attempt, still ongoing, is to recover the query definitions (90%+ of my changes) through the same ADO connection (tried ADOX and DAO too).
The most successful attempt was ADO:
Sub DebugPrintQueryDefsADO()
Dim dmgDB As DAO.Database
Dim dmgQD As DAO.QueryDef
Set dmgDB = DBEngine.OpenDatabase("C:\Database.accdb", , True)
For Each dmgQD In dmgDB.QueryDefs
If Left(dmgQD.Name, 1) <> "~" Then ' ~ Query defs seem to be the form views'
Debug.Print "---------------------------------"
Debug.Print dmgQD.Name
Debug.Print "---------------------------------"
Debug.Print dmgQD.SQL
End If
Next dmgQD
Set dmgQD = Nothing
Set dmgDB = Nothing
End Sub
This actually works! As long as the Query definition evaluation runs fine first. Which in my case cannot be true for most QD's since the tables are imported when required and then deleted. This means that the fields defined in the QD's cannot be found because the tables aren't there. Then Access presents me an error:
3258: The SQL Statement could not be executed because it contains ambiguous outer joins. To force one of the joins to be performed first, create a separate query that performs the first join and then include that query in your SQL statement.
Go home Access, you're drunk.
Next quest was to figure out how to not evaluate the SQL statement (I only need the SQL statement, not the result). I found that there is a property: Querydef.Prepare in this Access 2007 doc: http://msdn.microsoft.com/en-us/library/office/bb208511(v=office.12).aspx
According to the documentation (of Access 2007, I have 2010), I should set
Querydef.Prepare = dbQUnprepare. But that does not work..
So long problem short..
Is anyone aware of a way to fix the corrupted DB?
OR..
Does anyone know how to retrieve my SQL statements from the query definitions without the need to evaluate them?
Thanks!
One option you could try would be
Application.SaveAsText acQuery, "QueryName", "C:\path\QueryName.txt"
At least in some cases it dumps the SQL string at the beginning of the file (with some arbitrary breaks and escaped characters, just to keep things interesting). For example:
dbMemo "SQL" ="SELECT YEAR(Assigned.[Date]) AS Yr, MONTH(Assigned.[Date]) AS Mo, SUM(Assigned.["
"Hours Worked]) AS Hrs\015\012FROM Assigned INNER JOIN Projects ON Projects.[Proj"
"ect Name] = Assigned.[Project Name]\015\012WHERE Projects.Billable\015\012GROUP "
"BY YEAR(Assigned.[Date]), MONTH(Assigned.[Date]);\015\012"
dbMemo "Connect" =""
dbBoolean "ReturnsRecords" ="-1"
dbInteger "ODBCTimeout" ="60"
dbBoolean "OrderByOn" ="0"
dbByte "Orientation" ="0"
dbByte "DefaultView" ="2"
dbBinary "GUID" = Begin
0x1304ebdf78bef2459211d478954077cd
End
dbBoolean "FilterOnLoad" ="0"
dbBoolean "OrderByOnLoad" ="-1"
dbLongBinary "DOL" = Begin
0x0acc0e5500000000534cc617867b4d43b98002a1b002c8eb00000000c732603a ,
0xa958e4400000000000000000410073007300690067006e006500640000000000 ,
0x00006b84dfe37aec2248a1ccfe3e157361df0000000040b3affda358e4400000 ,
0x000000000000500072006f006a006500630074007300000000000000d5b092f5 ,
0x1c13394884636d668e066e66070000001304ebdf78bef2459211d478954077cd ,
0x59007200000000000000efa363bc29cbfc478a958e7b935d03da070000001304 ,
0xebdf78bef2459211d478954077cd4d006f00000000000000b1174c1abe1d3d4c ,
0xb9a1a7e5915a2e47070000001304ebdf78bef2459211d478954077cd48007200 ,
0x7300000000000000b2e4aa9aab3a9e479c47b2772754fce107000000534cc617 ,
0x867b4d43b98002a1b002c8eb4400610074006500000000000000404c3a80ef29 ,
0xa4498e153e354319e84c07000000534cc617867b4d43b98002a1b002c8eb4800 ,
0x6f00750072007300200057006f0072006b0065006400000000000000a3a95acb ,
0xe7ec994bab8df870ce5b3d98070000006b84dfe37aec2248a1ccfe3e157361df ,
0x500072006f006a0065006300740020004e0061006d006500000000000000f5cb ,
0xefb11bcf5e4da4b2806eed09a70207000000534cc617867b4d43b98002a1b002 ,
0xc8eb500072006f006a0065006300740020004e0061006d006500000000000000 ,
0x453445bf7e67b54ead2c9317ca29d906070000006b84dfe37aec2248a1ccfe3e ,
0x157361df420069006c006c00610062006c006500000000000000000000000000 ,
0x000000000000000000000c000000050000000000000000000000000000000000
End
dbByte "PublishToWeb" ="1"
Begin
Begin
dbText "Name" ="Yr"
dbLong "AggregateType" ="-1"
dbBinary "GUID" = Begin
0xd5b092f51c13394884636d668e066e66
End
End
Begin
dbText "Name" ="Mo"
dbLong "AggregateType" ="-1"
dbBinary "GUID" = Begin
0xefa363bc29cbfc478a958e7b935d03da
End
End
Begin
dbText "Name" ="Hrs"
dbLong "AggregateType" ="-1"
dbBinary "GUID" = Begin
0xb1174c1abe1d3d4cb9a1a7e5915a2e47
End
End
End
You can use Access Fix from AccessFix.com, if you have a copy of the database, which just got corrupted, and you didn't try anything on it that may have changed the data. Like, if you tried to compact and repair, your objects are gone after that. I use it at work and it fixes dbs for me in most cases. I would also try http://allenbrowne.com/tips.html, can't quite remember, but he had a set of steps there that you can use to recover the entire database from text. I think he explained it in his tips and tricks book, with Dough Steele, also

Microsoft Access (MySQL back end) queries with parameters

I am trying to convert the back end of an Access database to MySQL. So far, I have no problems converting the tables, and updating the queries with no parameters to pass through queries.
However, I am at a lost at figuring out how to deal with queries with parameters requiring inputs from users.
Anyone could give me some pointers?
If you are inheriting back-end code that sends data to an Access DB there are few things to look out for.
Dates are handled differently in Access to MySQL.
Access requires that you enclose dates in ## like #05/05/2012#. In MySQL, just enclose them in single quotes, '05/05/2012'.
Column and table names that contain spaces are enclosed in squared brackets like [table name] in Access and backsticks like table name in MySQL.
For linked tables, something like:
SELECT ID, AText
FROM LinkedTable
WHERE AText=[Forms]![Form1]![txtText]
Should work quite well. There are limitations, in which case you will need a pass-through, but most queries can be written at the Access end just as if the table was a local MS Access table.
To code a pass-through, you might say:
Dim objconn As Object
Dim cmd As Object
''Late binding
Set objconn = CreateObject("ADODB.Connection")
objconn.Open ServerCon
Set cmd = CreateObject("ADODB.Command")
Set cmd.ActiveConnection = objconn
cmd.CommandText = "InsertUser"
cmd.Parameters.Append _
cmd.CreateParameter("UserName", adVarChar, adParamInput, 50, "param1")

Select ##Identity returning 0 for linked table in Access

I am using Access 2007 and have some linked tables to a mySQL database. I am using DAO to insert a record into a mySQL linked table and trying to retrieve the inserted PK using Select ##identity, but that select is returning 0.
Dim sql As String
Dim oDB As Database
Set oDB = CurrentDb
sql = "INSERT INTO Quotes ( CustomerID ) SELECT 1 AS Expr1;"
oDB.Execute sql
If oDB.RecordsAffected <> 1 Then
MsgBox "cannot create new quote"
Exit Function
End If
Dim rsNewID As DAO.Recordset
Set rsNewID = oDB.OpenRecordset("SELECT ##IDENTITY") ' Create a recordset and SELECT the new Identity
Dim intNewID As Long
intNewID = rsNewID(0).Value ' Store the value of the new identity in variable intNewID
'This value is 0, why?
I've seen another question like this, that has not been satisfactorily answered for me
SELECT LAST_INSERT_ID()
fredrik gets partial credit, for the mySQL statement. It's important to note that I am using DAO, so statements are processed by the JET engine and it does not support this statement. This needs to be run as a pass through query in Access in order to work though. After I made a pass through query with fredrik's select statement, that did the trick. I called this Access passthrough query from my DAO code and it worked.
I have not used mysql. So, translate what I say for mysql.
Is CustomerID an identity column (i.e. does it generate ID on its own)?
If so, use the function that returns the last generated ID.
##Identity function is what people use in SQL Server. I don''t know of equivalent in mysql.
See this
Looking at the code above, you need not open the 2nd recordset. The rsNewID1 should help you get the last inserted ID.
Hope this helps.