"Operation must use an updateable query" error in MS Access - ms-access

I am getting an error message: "Operation must use an updateable query" when I try to run my SQL. From my understanding, this happens when joins are used in update/delete queries in MS Access. However, I'm a little confused because I have another query almost identical in my database which works fine.
This is my troublesome query:
UPDATE [GS] INNER JOIN [Views] ON
([Views].Hostname = [GS].Hostname)
AND ([GS].APPID = [Views].APPID)
SET
[GS].APPID = [Views].APPID,
[GS].[Name] = [Views].[Name],
[GS].Hostname = [Views].Hostname,
[GS].[Date] = [Views].[Date],
[GS].[Unit] = [Views].[Unit],
[GS].[Owner] = [Views].[Owner];
As I said before, I am confused because I have another query similar to this, which runs perfectly. This is that query:
UPDATE [Views] INNER JOIN [GS] ON
[Views].APPID = [GS].APPID
SET
[GS].APPID = [Views].APPID,
[GS].[Name] = [Views].[Name],
[GS].[Criticial?] = [Views].[Criticial?],
[GS].[Unit] = [Views].[Unit],
[GS].[Owner] = [Views].[Owner];
What is wrong with my first query? Why does the second query work when the first doesn't?

There is no error in the code, but the error is thrown due to the following:
- Please check whether you have given Read-write permission to MS-Access database file.
- The Database file where it is stored (say in Folder1) is read-only..?
suppose you are stored the database (MS-Access file) in read only folder, while running your application the connection is not force-fully opened. Hence change the file permission / its containing folder permission like in C:\Program files all most all c drive files been set read-only so changing this permission solves this Problem.

Whether this answer is universally true or not, I don't know, but I solved this by altering my query slightly.
Rather than joining a select query to a table and processing it, I changed the select query to create a temporary table. I then used that temporary table to the real table and it all worked perfectly.

I had the same error when was trying to update linked table.
The issue was that linked table had no PRIMARY KEY.
After adding primary key constraint on database side and re linking this table to access problem was solved.
Hope it will help somebody.

I had the same problem exactly, and I can't remember how I fond this solution but simply adding DISTINCTROW solved the problem.
In your code it will look like this:
UPDATE DISTINCTROW [GS] INNER JOIN [Views] ON <- the only change is here
([Views].Hostname = [GS].Hostname)
AND ([GS].APPID = [Views].APPID)
...
I'm not sure why this works, but for me, it did exactly what I needed.

To update records, you need to write changes to .mdb file on disk. If your web/shared application can't write to disk, you can't update existing or add new records. So, enable read/write access in database folder or move database to other folder where your application has write permission....for more detail please check:
http://www.beansoftware.com/ASP.NET-FAQ/Operation-Must-Use-An-Updateable-Query.aspx

set permission on application directory solve this issue with me
To set this permission, right click on the App_Data folder (or whichever other folder you have put the file in) and select Properties. Look for the Security tab. If you can't see it, you need to go to My Computer, then click Tools and choose Folder Options.... then click the View tab. Scroll to the bottom and uncheck "Use simple file sharing (recommended)". Back to the Security tab, you need to add the relevant account to the Group or User Names box. Click Add.... then click Advanced, then Find Now. The appropriate account should be listed. Double click it to add it to the Group or User Names box, then check the Modify option in the permissions. That's it. You are done.

I used a temp table and finally got this to work. Here is the logic that is used once you create the temp table:
UPDATE your_table, temp
SET your_table.value = temp.value
WHERE your_table.id = temp.id

I got this same error and using a primary key did not make a difference. The issue was that the table is a linked Excel table. I know there are settings to change this but my IT department has locked this so we cant change it. Instead, I created a make table from the linked table and used that instead in my Update Query and it worked. Note, any queries in your query that are also linked to the same Excel linked table will cause the same error so you will need to change these as well so they are not directly linked to the Excel linked table. HTH

This is a shot in the dark but try putting the two operands for the AND in parentheses
On ((A = B) And (C = D))

I was accessing the database using UNC path and occasionally this exception was thrown. When I replaced the computer name with IP address, the problem was suddenly resolved.

You have to remove the IMEX=1 if you want to update. ;)
"IMEX=1; tells the driver to always read "intermixed" (numbers, dates, strings etc) data columns as text. Note that this option might affect excel sheet write access negative."
https://www.connectionstrings.com/excel/

UPDATE [GS] INNER JOIN [Views] ON
([Views].Hostname = [GS].Hostname)
AND ([GS].APPID = [Views].APPID) <------------ This is the difference
SET
[GS].APPID = [Views].APPID,
[GS].[Name] = [Views].[Name],
[GS].Hostname = [Views].Hostname,
[GS].[Date] = [Views].[Date],
[GS].[Unit] = [Views].[Unit],
[GS].[Owner] = [Views].[Owner];

Related

Is there a way to store database modifications with a versioning feature (for eventual versions comparaison)?

I'm working on a project where users could upload excel files into a MySQL database. Those files are the main source of our data as they come directly from the contractors working with the company. They contain a large number of rows (23000 on average for each file) and 100 columns for each row!
The problem I am facing currently is that the same file could be changed by someone (either the contractor or the company) and when re-uploading it, my system should detect changes, update the actual data, and save the action (The fact that the cell went from a value to another value :: oldValue -> newValue) so we can go back and run a versions comparison (e.g 3 re-uploads === 3 versions). (oldValue Version1 VS newValue Version5)
I developed a tiny mechanism for saving the changes => I have a table to save Imports data (each time a user import a file a new row will be inserted in this table) and another table for saving the actual changes
Versioning data
I save the id of the row that have some changes, as well as the id and the table where the actual data was modified (Uploading a file results in a insertion in multiple tables, so whenever a change occurs, I need to know in which table that happened). I also save the new value and the old value which is gonna help me with restoring the "archives data".
To restore a version : SELECT * FROM 'Archive' WHERE idImport = ${versionNumber}
To restore a version for one row : SELECT * FROM 'Archive' WHERE idImport = ${versionNumber} and rowId = ${rowId}
To restore all version for one row : SELECT * FROM 'Archive' WHERE rowId = ${rowId}
To restore version for one table : SELECT * FROM 'Archine' WHERE tableName = ${table}
Etc.
Now with this structure, I'm struggling to restore a version or to run a comparaison between two versions, which makes think that I've came up with a wrong approach since it makes it hard to do the job! I am trying to know if anyone had done this before or what a good approach would look like?
Cases when things get really messy :
The rows that have changed in a version might not have changed in the other version (I am working on a time machine to search in other versions when this happens)
The rows have changed in both versions but not the same fields. (Say we have a user table, the data of the user with id 15 have changed in 2nd and 5th upload, great! Now for the second version only the name was changed, but for the fifth version his address was changed! When comparing these two versions, we will run into a problem constrcuting our data array. name went from "some"-> NULL (Name was never null. No name changes in 5th version) and address went from NULL -> "some' is which obviously wrong).
My actual approach (php)
<?php
//Join records sets and Compare them
foreach ($firstRecord as $frecord) {
//Retrieve first record fields that have changed
$fFields = $frecord->fieldName;
//Check if the same record have changed in the second version as well
$sId = array_search($frecord->idRecord, $secondRecord);
if($sId) {
$srecord = $secondRecord[$sId];
//Retrieve straversee fields that have changed
$sFields = $srecord->fieldName;
//Compare the two records fields
foreach ($fFields as $fField) {
$sfId = array_search($fField, $sFields);
//The same field for the same record was changed in both version (perfect case)
if($sfId) {
$sField = $sFields[$sfId];
$deltaRow[$fField]["oldValue"] = $frecord->deltaValue;
$deltaRow[$fField]["newValue"] = $srecord->deltaValue;
//Delete the checked field from the second version traversee to avoid re-checking
unset($sField[$sfId]);
}
//The changed field in V1 was not found in V2 -> Lookup for a value
else {
$deltaRow[$fField]["oldValue"] = $frecord->deltaValue;
$deltaRow[$fField]["newValue"] = $this->valueLookUp();
}
}
$dataArray[] = $deltaRow;
//Delete the checked record from the second version set to avoid re-checking
unset($secondRecord[$srecord]);
}
I don't know how to deal with that, as I said I m working on a value lookup algorithm so when no data found in a version I will try to find it in the versions between theses two so I can construct my data array. I would be very happy if anyone could give some hints, ideas, improvements so I can go futher with that.
Thank you!
Is there a way to store database modifications with a versioning feature (for eventual versions comparaison [sic!])?
What constitutes versioning depends on the database itself and how you make use of it.
As far as a relational database is concerned (e.g. MariaDB), this boils down to the so called Normal Form which is in numbers.
On Database Normalization: 5th Normal Form and Beyond you can find the following guidance:
Beyond 5th normal form you enter the heady realms of domain key normal form, a kind of theoretical ideal. Its practical use to a database designer os [sic!] similar to that of infinity to a bookkeeper - i.e. it exists in theory but is not going to be used in practice. Even the most demanding owner is not going to expect that of the bookkeeper!
One strategy to step into these realms is to reach the 5th normal form first (do this just in theory, by going through all the normal forms, and study database normalization).
Additionally you can construe versioning outside and additional to the database itself, e.g. by creating your own versioning system. Reading about what you can do with normalization will help you to find better ways to decide on how to structure and handle the database data for your versioning needs.
However, as written it depends on what you want and need. So no straight forward "code" answer can be given to such a general question.

trigger update copy information

I want to create a trigger that does the following:
copy one column of info jobnumber from one table (jobs) to another (materials) on an existing record to attachedjobnumber.
I haven't found the correct syntax to say this. when I insert a new job - nothing gets update and no new row is inserted,,, but there are no error messages in the logs.
I also need to set the bool (hasjobnumber) equal to true - when I test that trigger - it works fine.
which makes me think that setting the value of material.attachedjobnumber = jobs.jobnumber is the problem, my guess is that jobs.jobnumber isn't in reference when updating table material...
if that's true - what's the proper syntax for this?
I've tested separate triggers, and so far this trigger works fine.
UPDATE material
SET isjobyet = "HAS"
WHERE barcode1 IN (
SELECT primaryRFID
FROM jobs
WHERE jobs.primaryRFID = material.barcode1
)
since this code does work - I make the assumption that the non-static JobNumber value is the source of the problem. since "HAS" is correctly updated.
UPDATE material
SET material.AttachedJobNumber = jobs.JobNumber
WHERE barcode1 IN (
SELECT primaryRFID
FROM jobs
WHERE jobs.primaryRFID = material.barcode1
)
from this - I expect that after each inserts on the table jobs:
jobs.JobNumber be assigned to the material.AttachedJobName
this updates only the material row where the material.barcode1 =jobs.primaryrfid.
but no new row is inserted at all.
Before you perform UPDATE,
Actually you can use the same script using SELECT [skip the UPDATE SYNTAX]
That way you can monitor your script without committing anything yet.
And also I dont recommend using this inside the subquery
WHERE jobs.primaryRFID = material.barcode1
This condition connecting a table works on IN-SELECT subquery.
If you are performing subqueries inside the [WHERE] clause, try to treat it as different buffer, dont connect them first.

Where are these tables coming from? Access VBA

I have created a procedure that stores the names of all the tables in an external database inside an array. The reason for this is that, ultimately, I will be using this as a reference point for determining what tables need to be relinked.
The code below returns a total of 13 tables:
For Each tb In db.TableDefs
If Left(tb.Name, 4) <> "MSys" Then
'Store these accepted table names in an array
astrTableNames(intArryPosition) = tb.Name
intArryPosition = intArryPosition + 1
End If
Next tb
and stores their names in an array. Here is a list of the results, when I print the array:
1: DispenseStaging
2: DispenseSummary_All
3: DrugBrand
4: NDC
5: Programs
6: StateCodes
7: StoreInfo
8: tblCompany
9: tblGetProgramDispense
10: Users
11: Users1
12: Version
13: Zipcodes
Here's the problem - when I open the database - it only has 4 tables. There are no more - no references to links or anything.
So where are these tables actually coming from? Does this mean that they were once there but then were deleted but the reference is still there?
Thanks
P.S. This is the procedure I'm using to print the array:
'Procedure to print the contents of a string array
Public Sub PrintArrayContents(ArryStrg() As String)
Dim i As Integer
For i = LBound(ArryStrg) To UBound(ArryStrg)
Debug.Print i & ": "; ArryStrg(i)
Next i
End Sub
These are probably hidden tables.
You can display them in Access 2007 by going to the Navigation pane, then right-click on the All Access Objects and select Navigation options.
That will open a dialog for you to show hidden objects.
Those tables can be garbage or linked tables invisble on UI as either link is broken or garbage and linked tables at the same time.
Try a "compact and repair" on the DB (backup DB file first!) and re-exec your function to see if you get the same result set. If you do, read table properties' to try to figure out where the tables belong to and what are they (linked or base table). Check LastUpdated, Updatable, SourceTableName, maybe RecordCount properties to get some info about the weirdos :)
If you still can't see what's going on, first, read system tables to figure out the "extra tables'" meta-data (e.g. MSysObjects tells you the obj.type which can help) and second, try to execute a query against those tables, values -or error- returned may inform you about where those guys belong to.
I doubt but it's possible (as it's access :P) that some tables are just "hidden". You can turn on/off 'show hidden tables' in Navigation pane.
Please come back with your findings, I'm very curious about the results.
Just thought I'd add this answer to cover MS Access 2003. To view hidden objects, do the following:
Tools
Options
Select the View tab
Under the Show option, check the 'Hidden Objects' option
You should now beable to see hidden tables etc in the database.

Define custom POST method for MyDAC

I have three tables objects, (primary key object_ID) flags (primary key flag_ID) and object_flags (cross-tabel between objects and flags with some extra info).
I have a query returning all flags, and a one or zero if a given object has a certain flag:
SELECT
f.*,
of.*,
of.objectID IS NOT NULL AS object_has_flag,
FROM
flags f
LEFT JOIN object_flags of
ON (f.flag_ID = of.flag_ID) AND (of.object_ID = :objectID);
In the application (which is written in Delphi), all rows are loaded in a component. The user can assign flags by clicking check boxes in a table, modifying the data.
Suppose one line is edited. Depending on the value of object_has_flag, the following things have to be done:
If object_has_flag was true and still is true, an UPDATE should be done on the relevant row in objects_flags.
If object_has_flag was false but is now true, and INSERT should be done
If object_has_flag was true, but is now false, the row should be deleted
It seems that this cannot be done in one query https://stackoverflow.com/questions/7927114/conditional-replace-or-delete-in-one-query.
I'm using MyDAC's TMyQuery as a dataset. I have written separate code that executes the necessary queries to save changes to a row, but how do I couple this to the dataset? What event handler should I use, and how do I tell the TMyQuery that it should refresh instead of post?
EDIT: apparently, it is not completely clear what the problem is. The standard UpdateSQL, DeleteSQL and InsertSQL cannot be used because sometimes after editing a line (not deleting it or inserting a line), an INSERT or DELETE has to be done.
The short answer is, to paraphrase your answer here:
Look up the documentation for "Updating Data with MyDAC Dataset Components" (as of MyDAC 5.80).
Every TCustomDADataSet (such as TMyQuery) descendant has the capability to set update SQL statements using SQLInsert, SQLUpdate and SQLDelete properties.
TMyUpdateSQL is also a promising component for custom update operations.
It seems that the easiest way is to use the BeforePost event, and determine what has to be done using the OldValue and NewValue properties of several fields.

Classic ASP/MySQL - Parameter Issue

I have been trying to insert a huge text-editor string in to my database. The application I'm developing allows my client to create and edit their website terms and conditions from the admin part of their website. So as you can imagine, they are incredibly long. I have got to 18,000+ characters in length and I have now received an error when trying to add another load of text.
The error I am receiving is this:
ADODB.Command error '800a0d5d'
Application uses a value of the wrong type for the current operation
Which points to this part of my application, specifically the Set newParameter line:
Const adVarChar = 200
Const adParamInput = 1
Set newParameter = cmdConn.CreateParameter("#policyBody", adVarChar, adParamInput, Len(policyBody), policyBody)
cmdConn.Parameters.Append newParameter
Now this policy I am creating, that is currently 18,000+ characters in length, is only half complete, if that. It could jump to 50 - 60,000! I tried using adLongVarChar = 201 ADO type but this still didn't fix it.
Am I doing the right thing for such a large entry? If I am doing the right thing, how can I fix this issue? ...or if I'm doing the wrong thing, what is the right one?
Try to avoid putting documents in your database if you can. Sometimes it's a reasonable compromise, serialised objects, mark up snippets and such.
If you don't want to query the document with sql the only benefit is the all in one place thing. ie back up your db, you back up your documents as well, and you can use your db connectivity exclusively.
That said nothing is free, carting all that stuff about in your database costs you.
If you can.
have a documents table, User name for the file, and internal name in your documents directory, so the file name is unique in the file system, and a path description, if there could be more than one.
Then just upload and download the selected document as a file, on a get or set of the related database entity.
You'll need to dal with deployment issues, document directory exists, and the account you are running mysql daemon as can see it, but most of the time, the issues you have keeping documents seperate fromthe db, are much easier to deal with than the head scratchers you are running into now.