views:

14999

answers:

6

I have a select query which does some text manipulation to essentially reformat a field so that I can look it up in another table:

If my first table if I have a field like "J1/2" it looks up the ID of a record in a different table with J1 and J2 in the appropriate fields.

This all works well.

Now I want to update the original table so I don't have to do lookups using this string manipulation anymore, but my attempts at update queries end with "Operation must use an updateable query"

Any ideas?

My SELECT statement:

SELECT DISTINCT
t1.DD,
t1.TN,
t1.DD & " J" & MID(t1.TN,2,1) AS CalculatedStart,
t1.DD & " J" & MID(t1.TN,4,1) AS CalculatedEnd,
t2.ID
FROM t1 INNER JOIN t2
ON (t1.DD & " J" & MID(t1.TN,2,1)=t2.StartLink)
AND (t1.DD & " J" & MID(t1.TN,4,1)=t2.EndLink)
WHERE t1.TN Like "J?/?"
AND t1.DD Like "M*";

Recall - this works fine and I get the necessary t2.ID out the other end.

So I want to do something like:

UPDATE t1 SET t2ID = (
    SELECT Query1.ID
    FROM Query1
    WHERE t1.DD=Query1.DD
    AND t1.TN=Query1.TN
    )
WHERE t1.TN Like "J?/?"
AND t1.DD Like "M*";

Only this fails. This is within MS Access itself so I can't imagine an actual permissions problem like most of the "Operation must use an updateable query" problems seem to be.

EDIT: Trying to simplify the case that doesn't work.

This UPDATE query is fine:

UPDATE t1
SET t2ID="Unknown"
WHERE TN LIKE "J?/?"
AND DD LIKE "M*";

This one fails (Thanks Goedke - this example obviously fails because the subquery returns more than 1 result. I had oversimplified to try to find my problem)

UPDATE t1
SET t2ID=(SELECT ID FROM t2)
WHERE TN LIKE "J?/?"
AND DD LIKE "M*";

So do I just have my subquery syntax wrong in some way?

EDIT: This SELECT statement is fine too:

SELECT t1.OA, t1.DD, t1.TN, t1.HATRIS,
    query1.DD, query1.TN, query1.ID
FROM t1 INNER JOIN query1
ON t1.DD=query1.DD
AND t1.TN=query1.TN

Furthermore, using count on the select statement above shows that there is exactly 1 ID being returned per (DD,TN) combination

EDIT:

The simplest case I've now got to - using various SELECT statements I now have a table with just 2 columns - the primary key of t1 and the value I want to insert into t1.

I still can't seem to write

UPDATE t1 SET t1.f2 = (SELECT t2.f2 FROM t2 WHERE t2.f1 = t1.f1)

where t1's primary key is f1. Even adding WHERE t1.f1 IN (SELECT f1 FROM t2) doesn't help. (Added to eliminate the possibility that the subquery returns 0 results)

+2  A: 

A subquery of (SELECT ID FROM t2) can't work unless there is only one record in t2. Which ID are you expecting to be used?

The error message that is being reported normally occurs when you have joins and are not including all of the primary keys necessary to update back to tables in a data bound form (for example, your original DISTINCT destroys information about keys, so if it was bound to a form, the form would not be able to save back).

The fact you are using DISTINCT there would make me suspicious that the sub query is returning more than one row in your more complex example. This is probably the most common problem with assigning out of a sub query result: under-constraining the where clause.

Another problem I have seen with assigning out of a subquery is if the syntax of the inner query is incorrect. At least with SQL 2000 and 2005 back ends, the query processor will silently fail and return NULL in such cases. (This is, as far as I can tell, a bug: I see no reason why something that will return an error at the top level would be silently permitted in a subquery... but there it is.)

EDIT: Just to ensure that neither Paul or I wasn't going crazy, I created the following tables:

t1 | ID, FK, Data
t2 | ID2, Data2

I did not put any constraints except a primary key on ID and ID2. All fields were text, which is different from what I normally use for IDs, but should be irrelevant.

t1:

ID  FK Data
Key1     Data1
Key2     Data2
Key3     Data3

t2:

ID2 Data2
Key1    DataA
Key2    DataB
Key3    DataC

A query of the form:

UPDATE t1 SET t1.FK = (select ID2 from t2 where t2.ID2 = t1.ID);

Failed with the same message Paul got.

select *, (select ID2 from t2 where t2.ID2 = t1.ID) as foreign from t1,

works as expected, so we know the subquery syntax is not to blame.

UPDATE t1 SET t1.FK = 'Key1'

also works as expected, so we don't have a corrupt or non updateable destination.

Note: if I change the database backend from native to SQL 2005, the update works! A bit of googling around, and I find Access MVPs suggesting DLOOKUP to replace a subquery:

http://www.eggheadcafe.com/software/aspnet/31849054/update-with-subquerycomp.aspx

Apparently this is a bug in Access SQL, one that is avoided when using a SQL Express 2000 or higher back end. (The google results for "access update subquery" support this theory).

See here for how to use this workaround: http://www.techonthenet.com/access/functions/domain/dlookup.php

Godeke
Good point - I oversimplified...
Paul Smith
Are you sure that your less simplified queries are returning single results?
Godeke
I'm just checking that out - having said that the original query should be returning a single result.
Paul Smith
The original query only returns a single result
Paul Smith
Your original query uses DISTINCT (if you mean the top of the question...) but your sub query is not (nor should it). The "AND t2.TN=Query.TN" looks very odd to me: where is T2?
Godeke
In my original attempt at the UPDATE query, the subquery returns a single result. It has to, because the subqueries WHERE clause uses the fields which are DISTINCT in the source query. i.e., the combination (DD,TN) is unique in the first query
Paul Smith
Updated the subquery - I think I typoed when trying to type the code out
Paul Smith
You might try adding a TOP 1 to the subquery to see if that ques Access in to the fact that only one row will be returned.
JohnFx
Anyway, I'm out of ideas. If you are sure that "DD+TN" returns a single row in all cases, and there is no join on the update side to block it... I just ran a nearly exact clone in 2007.
Godeke
As a last grasp at straws: are the IDs the same datatype (i.e., we don't have a numeric and an integer?)
Godeke
Actually the ID fields are Text with a field size of 25. For some reason the incoming IDs use characters
Paul Smith
PS How can I give Godeke rep for being so helpful without actually solving my problem (which may of course be my fault!)
Paul Smith
No worries, I have all the REP I need. One last idea: could your destination "table" actually be a view/query?
Godeke
The destination table is definitely as actual table. I'm using Microsoft Access 2003 SP3 by the way, but I can't imagine this would be an issue?
Paul Smith
2003 works fine for me... I use 2007 only on a few machines; most are 2003. Would t1.f2 happen to be part of the primary key or some other constraint?
Godeke
It was part of another constraint, but removing that constraint doesn't seem to help
Paul Smith
OK, I have reproduced your problem... testing what's going on.
Godeke
Well, now I know something I didn't know before: subqueries on Access SQL are bugged for update queries. See my edit for details.
Godeke
Thank you so much Godeke!
Paul Smith
Sadly I don't have the luxury of changing the backend - this really is just a small Access database and I'm using an UPDATE query to try to avoid having to do lots of manual data entry! Many many thanks for your investigations!
Paul Smith
A: 

For this one: UPDATE t1 SET t1.f2 = (SELECT t2.f2 FROM t2 WHERE t2.f1 = t1.f1)

UPDATE t1 INNER JOIN t2 ON t1.f1 = t2.f1 SET t1.f2 = [t2].[f2];
Jeff O
Nope, still get "Operation must use an updateable query"
Paul Smith
FWIW I worked around this by copying "t2" which was actually a query, into a temporary table, giving that temporary table a primary key on f1 (the join column)
Paul Smith
+2  A: 

I havent't read the whole thread, but this is the solution that I am using:

update (select * from t1 inner join t2 on t1.key = t2.key) set t1.field1 = t2.field2

and that works fine in MS Access for me.

Sandip

Sandip
+3  A: 

I have to weigh in with David W. Fenton's comment on the OP.

This is highly annoying problem with Jet/ACE. But try either:

  1. go to the query properties (click the background of the pane where the tables are displayed) and set 'Unique Records' to 'Yes'
  2. Option 1 is the equivalent of adding the somewhat strange looking DISTINCTROW keyword to the SELECT clause, eg

:

UPDATE DISTINCTROW tblClient 
       INNER JOIN qryICMSClientCMFinite 
          ON tblClient.ClientID = qryICMSClientCMFinite.ClientID
   SET tblClient.ClientCMType = "F";

This solves so many problems involving this error message that it is almost ridiculous.

That's MS Access in a nutshell - if you don't know the trade-secret workaround for problem x, you can take days trying to find the answer. To know the 10,000 workarounds IS to program Access. Is that enough of a warning for the uninitiated ?

Ben

Ben McIntyre
+1 just for the warning to the uninitiated. That's gold.
Paul Smith
I do believe that Jet 3.x was more forgiving of updatability, but in ways that were out of synch with other SQL implementations. I think the Jet 4 changes to updatability (which annoyed the hell out of us experienced Access developers) were actually a step in the direction of making Jet SQL less weird, even if it still has some things that don't behave the way other SQL dialects do.
David-W-Fenton
And, BTW: In Access 2, the default for SELECT queries was DISTINCTROW instead just SELECT. I can always tell when I encounter an app with SELECT DISTINCTROW all over the place that is was likely created way back in Access 2.
David-W-Fenton
@David W. Fenton: "'Jet/ACE' ... applies to historic versions of Jet before the term 'Access Database Engine' existed in MS's documentation" -- You've misunderstood: the term 'Access Database Engine' is the collective term for Jet and ACE (and whatever comes next). If you take a look at the Access2007 documentation, MS use the term 'Access Database Engine' retrospectively, even for features specific to Jet (e.g. ULS). So are merely 'correcting' MS's collective term to use the your own collective term.
onedaywhen
+1  A: 

This worked for me (Access 2000)

UPDATE DISTINCTROW T1 inner join T2 on T2.f1 = T1.f1  SET f2 = f2;
David Leigh
A: 

My solution was to change my sql on that way.

  update (select o.pricein, g.pricein from operations o left join goods g on g.id = o.goodid where o.opertype = 4 and o.acct = 1) 
  set o.pricein = g.pricein
Plamen
You're saying that SQL was executed by Jet/ACE? I'm surprised, as it looks to me like it's missing the table after UPDATE. And whether an update works with a JOIN in the SELECT depends entirely on what tables you're joining and the indexes on the joined fields.
David-W-Fenton