I've got an Access application with an update query with the following syntax:
UPDATE TABLE1, TABLE2 SET
TABLE2.VALUE1 = TABLE1.VALUE1,
TABLE2.VALUE2 = TABLE1.VALUE2,
TABLE2.VALUE3 = TABLE1.VALUE3,
TABLE2.VALUE4 = TABLE1.VALUE4
The query is working but I do not understand what's going on here.
I'm trying to convert this query to SQL Server.
Can somebody please explain what this query does? My guess is that it's a special Access syntax.
Thanks,
Sven
It uses the older implicit JOIN syntax, although SQL Server should understand that syntax too.
It's INNER JOINing table1 and table2, then moving the values from table1 to table2. Because of the lack of JOIN conditions, if table1 has more than 1 row it may have unpredictable results.
Essentially it is:
UPDATE Table1 INNER JOIN Table2 <<ON Missing Conditions Here>>
SET Table2.Value1 = Table1.Value1
Table2.Value2 = Table1.Value2
Table2.Value3 = Table1.Value3
Table2.Value4 = Table1.Value4
You can convert this to SQL Server with something like this:
UPDATE Table2
SET Table2.Value1 = Table1.Value1
Table2.Value2 = Table1.Value2
Table2.Value3 = Table1.Value3
Table2.Value4 = Table1.Value4
FROM Table1 INNER JOIN Table2 <<ON Missing Conditions Here>>
Every field from TABLE2 will override corresponded field from TABLE1 with records from TABLE1 one by one. Result will be TABLE2 with all replaced records by last row from TABLE1. If TABLE1 has no records - no changes happens.
Sorry for my english.
And... it is SQL.
Try to avoid the "UPDATE with join" syntax in SQL Server. It is completely non-standard SQL but more seriously it gives unpredictable results without any error or warning if the joining criteria is not correct. Use the MERGE statement instead or use the standard version of the UPDATE statement (with a subquery) if you can.
Related
I maintain an application developed in Access. And I have to implement an update query, but I'm quite stuck at the moment and I don't understand why.
Basically, the query must update a record from table X following another record from that same table, but the query I wrote does nothing, I did test separately the update and the select and they both work, but together, no.
I hope some of you may found my problem.
Here is the query I wrote (I did remove some fields to avoid to be too long, and of course, the query you will see was tested to be sure it was not the missing fields the issue)
UPDATE
TABLE_X AS recordToUpdate,
(
SELECT
DUP_C2B_From_CPL.[NUM-GrpHdr],
DUP_C2B_From_CPL.[NUM-LOT],
DUP_C2B_From_CPL.[SINGLE-SCENARIO],
DUP_C2B_From_CPL.EqvtAmt,
DUP_C2B_From_CPL.EqvtAmtCur,
DUP_C2B_From_CPL.EqvtAmtCurTft,
DUP_C2B_From_CPL.XchgRateInfExchangeRate,
DUP_C2B_From_CPL.XchgRateInfRateType,
DUP_C2B_From_CPL.XchgRateInfContractId,
DUP_C2B_From_CPL.ChqTp
FROM DUP_C2B_From_CPL
) AS originalRecord
SET
recordToUpdate.EqvtAmt = originalRecord.EqvtAmt,
recordToUpdate.EqvtAmtCur = originalRecord.EqvtAmtCur,
recordToUpdate.EqvtAmtCurTft = originalRecord.EqvtAmtCurTft,
recordToUpdate.XchgRateInfExchangeRate = originalRecord.XchgRateInfExchangeRate,
recordToUpdate.XchgRateInfRateType = originalRecord.XchgRateInfRateType,
recordToUpdate.XchgRateInfContractId = originalRecord.XchgRateInfContractId,
recordToUpdate.ChqTp = originalRecord.ChqTp
WHERE
recordToUpdate.[SINGLE-SCENARIO] = 112811
DUP_C2B_From_CPL here is a subQuery that is retrieving the record I'm interested in so I can take its values to update the other one.
In the last WHERE closure, I hardcoded the id for more readability for you (and yes it exists :))
And also the designer is rendering correctly, so no error on this side. But as I said, it seems that it is not updating anything.
Don't hesitate to tell me if you nee more information.
You can try something like below.
UPDATE
Table1 AS t1
INNER JOIN Table1 AS t2
ON t1.Field1 = t2.Field2
SET
T1.Field1 = t2.field1
If there is not any join then you can try like below
UPDATE Table1 t1 , Table1 t2
SET T1.Field1 = t2.field1
where t1.field1 = 'aa' and t2.field1 = 'bb'
Well, for some reason, I had to restart my laptop, and the query is now working.
Thank you for your help.
Strangely, it seems that the EXISTS clause is not supported by DBISAM's sql engine, as it's always resulting in an SQL error. The following is a sample where EXISTS is being used. Am i missing anything here?
update Table1 set HASXACTION = False
WHERE EXISTS (SELECT SERIALID
From Table2
LEFT JOIN Table1 ON (Table2 .AUXILACT = Table1 .CODE)
AND (Table2 .CHARTACT = Table1 .CHARTACT) )
Never mind people, i just learned that DBISAM does not support EXISTS operator for specifying sub-select predicates in WHERE clauses. It's documented within DBISAM's help file(screenshot attached).
I presume that you don't really want the join in the subquery. You probably intend a correlated subquery:
UPDATE Table1
SET HASXACTION = False
WHERE EXISTS (SELECT SERIALID
FROM Table2
WHERE Table2.AUXILACT = Table1.CODE AND Table2.CHARTACT = Table1.CHARTACT
);
This should also fix the problem you are having, which is the reference to Table1 both in the update clause and the subquery. (This is a MySQL limitation.)
EDIT:
I cannot find any reference to EXISTS (or even subqueries) for dbisam. But, you can do updates with joins, so this should be equivalent:
UPDATE Table1
SET HASXACTION = False
FROM Table1 JOIN
Table2
ON Table2.AUXILACT = Table1.CODE AND Table2.CHARTACT = Table1.CHARTACT;
As you've already found, you can do it with the IN. However, there is a limitation that IN can only work with one field. So you can get around it by concatenating two fields to make expressions that fit the criteria. One for the inner, and one for the outer.
update Table1 set HASXACTION = False
WHERE Code+'.'+CHARTACT IN
(
SELECT AUXILACT+'.'+CHARTACT From Table2
)
I have an update query for an Oracle SQL db. Upon execution the query returns ORA-00904: "t1"."sv_id": invalid identifier
So, why do I get an "invalid identifier" error message although the column exists?
Here is the complete query (replaced actual table and column names by dummies in np++)
UPDATE table_1 t1 SET (type) =
CASE
WHEN
((SELECT COUNT(dateCheck.id) FROM table_2 dateCheck
WHERE dateCheck.s_id = t1.s_id AND dateCheck.sv_id = t1.sv_id) = 0)
THEN
(SELECT sv.type FROM table_3 sv WHERE sv.id = t1.sv_id)
ELSE
(SELECT type FROM
(SELECT d.type as type FROM table_2 d
WHERE d.s_id = t1.s_id AND d.sv_id = t1.sv_id
ORDER BY d.creationTimestamp ASC)
WHERE ROWNUM = 1)
END
Now I don't understand why that error occurs.
Here is what I already know:
The Queries in the CASE statement work when executed separately, provided they are wrapped into a query that provides table_1 t1 for sure.
t1.s_id seems to work since oracle doesn't complain about that. When i change it to a column that really doesn't exist, oracle starts complaining about that non existent column before returning something about t1.sv_id. So somehow the alias might work, although I'm not sure about it.
I'm 100% sure that the column t1.sv_id exists and no typo was made. Executed a query on t1 directly and doublechecked everything in notepad by marking all occurences.
An (completely unrelated) update query like the following works as well (note the alias t1 is used in the select query). Don't assume table_1/2 to be the same as in the update query above, just reused the names. This should just illustrate that I successfully used an alias in an update query before.
update table_1 t1 set (t2_id) = (select id from table_2 t2 where t1.id = t2.t1_id)
UPDATE
Thx a lot for pointing me to the "you don't have access to alises in deeper suquery layers" issue. That got me on track again pretty fast.
So here is the query I ended up with. This seems to work fine. Eliminates the acces to t1 in the deeper layers and selects the oldest row, so that the same result should be returned from the query I expected from the original query in the ELSE part.
UPDATE table_1 t1 SET (type) =
CASE
WHEN
((SELECT COUNT(dateCheck.id) FROM table_2 dateCheck
WHERE dateCheck.s_id = t1.s_id AND dateCheck.sv_id = t1.sv_id) = 0)
THEN
(SELECT sv.type FROM table_3 sv WHERE sv.id = t1.sv_id)
ELSE
(SELECT d.type as type FROM table_2 d
WHERE d.s_id = t1.s_id
AND d.sv_id = t1.sv_id
AND d.creation = (SELECT MIN(id.creation) FROM table_2 id
WHERE d.s_id = id.s_id AND d.sv_id = id.sv_id))
END
You can't reference a table alias in a subquery of a subquery; the alias doesn't apply (or doesn't exist, or isn't in scope, depending on how you prefer to look at it). With the code you posted the error is reported against line 11 character 24, which is:
(SELECT type FROM
(SELECT d.type as type FROM table_2 d
WHERE d.s_id = t1.s_id AND d.sv_id = t1.sv_id
^^^^^^^^
If you change the t1.s_id reference on the same line to something invalid then the error doesn't change and is still reported as ORA-00904: "T1"."SV_ID": invalid identifier. But if you change the same reference on line 5 instead to something like
((SELECT COUNT(dateCheck.id) FROM table_2 dateCheck
WHERE dateCheck.s_id = t1.s_idXXX AND dateCheck.sv_id = t1.sv_id) = 0)
... then the error changes to ORA-00904: "T1"."S_IDXXX": invalid identifier. This is down to how the statement is being parsed. In your original version the subquery in the WHEN clause is value, and you only break it by changing that identifier. The subquery in the ELSE is also OK. But the nested subquery in the ELSE has the problem, and changing the t1.s_id in that doesn't make any difference because the parser reads that part of the statement backwards (I don't know, or can't remember, why!).
So you have to eliminate the nested subquery. A general approach would be to make the whole CASE an inline view which you can then join using s_id and sv_id, but that's complicated as there may be no matching table_2 record (based on your count); and there may be no s_id value to match against as that isn't being checked in table_3.
It isn't clear if there will always be a table_3 record even then there is a table_2 record, or if they're mutually exclusive. If I've understood what the CASE is doing then I think you can use an outer join between those two tables and compare the combined data with the row you're updating, but because of that ambiguity it needs to be a full outer join. I think.
Here's a stab at using that construct with a MERGE instead of an update.
MERGE INTO table_1 t1
USING (
SELECT t2.s_id,
coalesce(t2.sv_id, t3.id) as sv_id,
coalesce(t2.type, t3.type) as type,
row_number() over (partition by t2.s_id, t2.sv_id
order by t2.creationtimestamp) as rn
FROM table_2 t2
FULL OUTER JOIN table_3 t3
ON t3.id = t2.sv_id
) tmp
ON ((tmp.s_id is null OR tmp.s_id = t1.s_id) AND tmp.sv_id = t1.sv_id AND tmp.rn = 1)
WHEN MATCHED THEN UPDATE SET t1.type = tmp.type;
If there will always be a table_3 record then you could use that as the driver and have a left outer join to table_2 instead, but hard to tell which might be appropriate. So this is really just a starting point.
SQL Fiddle with some made-up data that I believe would have hit both branches of your case. More realistic data would expose the flaws and misunderstandings, and suggest a more robust (or just more correct) approach...
Your query and your analysis seems sound to me. I have no solution but a few things you can try to maybe trigger something that explains this odd behavior:
Quote the column (just in case it happens to be a SQL keyword).
Use table_1.sv_id - this works as long as the whole query contains this table only once.
Make sure that the alias t1 exists only once
Run the query with a query tool like SQuirrel SQL - the tool can examine the exact position where Oracle reports the problem. Maybe it's in a different place of the query than you think
Check () and make sure they are around the parts where they should be.
Swap the order of expressions around =
I have a scenario where I would like to update multiple fields in multiple Tables using just one instuction. I need a Syntax to perform such opperations on multiple Databases (Oracle and MSSQL).
At the moment I am stuck at the following statement from MSSQL:
update table1
set table1.value = 'foo'
from table1 t1 join table2 t2 on t1.id = t2.tab1_id
where t1.id = 1234
I would like to update a field in t2 aswell in the same statement.
Further I would like to perform the same Update(s) on Oracle.
EDIT:Seems like I can not update multiple Tables in just one statement. Is there a syntax that works for Oracle and MSSql when updating using a Join?
Regards
Seems like I can not update multiple
Tables in just one statement.
Is there a syntax that works for
Oracle and MSSql when updating using a
Join?
I assume when you re-posed the question you want syntax that will work on both Oracle and SQL Server even though it will inevitably affect only one table.
Entry level SQL-92 Standard code is supported by both platforms, therefore the following 'scalar subqueries' SQL-92 code should work:
UPDATE table1
SET my_value = (
SELECT t2.tab1_id
FROM table2 AS t2
WHERE t2.tab1_id = table1.id
)
WHERE id = 1234
AND EXISTS (
SELECT *
FROM table2 AS t2
WHERE t2.tab1_id = table1.id
);
Note that while using the correlation name t1 for Ttble1 is valid syntax according to the SQL-92 Standard this will materialize a table and the UPDATE will then target the materialized table 't1' and leave your base table 'table1` unaffected, which I assume is not the desired affect. While I'm fairly sure both Oracle and SQL Server are non-compliant is this regard and that in practise would work as expected, there's no harm in being ultra cautious and sticking to the SQL-92 syntax by fully qualifying the target table.
Folk tend not to like the 'repeated' code in the above subqueries (even though the optimizer should be smart enough to evaluate it only once).
More recent versions of Oracle and SQL Server support both support Standard SQL:2003 MERGE syntax, would may be able to use something close to this:
MERGE INTO table1
USING (
SELECT t2.tab1_id
FROM table2 AS t2
) AS source
ON id = source.tab1_id
AND id = 1234
WHEN MATCHED THEN
UPDATE
SET my_value = source.tab1_id;
I just noticed your example is even simpler than I first thought and merely requires a simple subquery that should run on most SQL products e.g.
UPDATE table1
SET my_value = 'foo'
WHERE EXISTS (
SELECT *
FROM table2 AS t2
WHERE t2.tab1_id = table1.id
);
on Oracle, you can update only one table , but you could think of using a trigger .
SELECT * FROM table1, table2
WHERE table1.user_id = table2.id
AND table1.content = news
AND table1.content_id = 1
that wont work. cant u have two "AND" in a sql statement??
//Tomek
you probably want to quote 'news' as a string...
You also probably want to use an inner join instead (much more efficient)
SELECT * FROM table1
INNER JOIN table2 ON table1.user_id = table2.id
WHERE table1.content = 'news'
AND table1.content_id = 1
news is what? Some sort of parameter? Value of the field? A word which should occur in the field? Most likely your syntax is wrong, see W3Schools WHERE and W3Schools AND/OR operators pages for more information.
let me rewrite that for you with a JOIN statement since it is not 1995 anymore, you also need quotes around news
SELECT * FROM table1 t1
inner join table2 t2 on t1.user_id = t2.id
AND t1.content = 'news'
AND t1.content_id = 1
First let's start with getting rid of that old-style join so that the join and where clauses are clearly separated to make understanding much easier.
SELECT * FROM table1 t1.
JOIN table2 t2
ON t1.user_id = t2.id
WHERE t1.content = news
AND t1.content_id = 1
Now let's discuss what the problem might be. First what error are you receiving as this could be perfectly acceptable syntax? Could the problem be that you have not noted which table news is to come from? If it is in both tables you could be getting an error there. If news is meant to be the value of the column you would want it to be 'news' instead of news. It could also simply be that no records meet your conditions.
Further it is a bad practice to ever use select * and it should never be used in a join as you are returning at least one field twice and that is wasteful of both database and network resources. Always specify only the columns you need. This wastes lots of resources every day when lazy programmers do this in every query.
What do table1 and table2 look like? Can you paste a create script?
I would STRONGLY recommend to use the proper JOIN syntax:
select * from table1
inner join table2 on table1.user_id = table2.id
......
what datatypes is "table1.content" ?
You can most definitely have a lot more than just 2 AND statements in a SQL query - any database that really support any of the SQL-xx standards will support this...
I liked cmartin's response. Also, you can use more than one AND, if needed.