From: --CELKO-- on
The ANSI model of an UPDATE is that it acts as if

1) You go to the base table. It cannot have an alias because an alias
would create a working table that would be updated and then disappear
after the statement is finished, thus doing nothing.

2) You go to the WHERE clause. All rows (if any!) that test TRUE are
marked as a subset. If there is no WHERE clause, then the entire table
is marked. The name of this set/pseudo-table is OLD in Standard
SQL.

3) You go to the SET clause and construct a set/pseudo-table called
NEW. The rows in this table are build by copying values from the
columns are not mentioned from the original row to the NEW row. The
columns are assigned all at once. That is, the unit of work is a row,
not one column at a time.

4) The OLD subset is deleted and the NEW set is inserted. Those are
the proprietary terms used in SQL Server, too. This is why

UPDATE Foobar
SET a = b, b = a;

Swaps the values in the columns a and b. The engine checks constraints
and does a ROLLBACK if there are violations.

In full SQL-92, you can use row constructors to say things like:

UPDATE Foobar
SET (a, b)
= (SELECT x, y
FROM Floob AS F1
WHERE F1.keycol= Foobar.keycol);

The proprietary, non-standard UPDATE.. FROM.. syntax is a total
disaster in the ANSI model and in implementation, but that is another
rant.

Trying to UPDATE the temporary result of a JOIN syntax would be
useless that temporary result disappears at the end of the statement
and never touches the base tables.
From: tshad on
Got you.

It is like moving all values to a temporary location and them moving them
into the specified location. Obviously, it would be done a little more
efficiently.

I was pretty sure that was the case but wanted to make sure.

Thanks,

Tom

"Plamen Ratchev" <Plamen(a)SQLStudio.com> wrote in message
news:n4r3v51nrrnrfhh0rqpao9s6i41d8s4d1l(a)4ax.com...
> Think of having a snapshot of the column values before the update,
> then use the snapshot values to update the columns. All column values
> are update in a single step (using the snapshot values), there is no
> order of applying the update. This is a fundamental concept in SQL,
> which makes it differ from the procedural languages (where iteration
> and order rule).
>
> --
> Plamen Ratchev
> http://www.SQLStudio.com


From: J M De Moor on
>
> The proprietary, non-standard UPDATE.. FROM.. syntax is a total
> disaster in the ANSI model and in implementation
>
>

At it again, huh? (You know I will never let this go.) First of all
the above sentence makes no sense. Is there really a "proprietary,
non-standard UPDATE..FROM syntax"..."in the ANSI model"?

Either way, the fact is that UPDATE..FROM is NOT a disaster and,
besides, this assertion is completely off topic, given that the OP was
asking about swapping column values.

Joe De Moor
From: Marilyn on
Hi,

Just happen to "glance-in" in your discussions. This is very informative
for me. Thank you.

Marilyn

"--CELKO--" wrote:

> The ANSI model of an UPDATE is that it acts as if
>
> 1) You go to the base table. It cannot have an alias because an alias
> would create a working table that would be updated and then disappear
> after the statement is finished, thus doing nothing.
>
> 2) You go to the WHERE clause. All rows (if any!) that test TRUE are
> marked as a subset. If there is no WHERE clause, then the entire table
> is marked. The name of this set/pseudo-table is OLD in Standard
> SQL.
>
> 3) You go to the SET clause and construct a set/pseudo-table called
> NEW. The rows in this table are build by copying values from the
> columns are not mentioned from the original row to the NEW row. The
> columns are assigned all at once. That is, the unit of work is a row,
> not one column at a time.
>
> 4) The OLD subset is deleted and the NEW set is inserted. Those are
> the proprietary terms used in SQL Server, too. This is why
>
> UPDATE Foobar
> SET a = b, b = a;
>
> Swaps the values in the columns a and b. The engine checks constraints
> and does a ROLLBACK if there are violations.
>
> In full SQL-92, you can use row constructors to say things like:
>
> UPDATE Foobar
> SET (a, b)
> = (SELECT x, y
> FROM Floob AS F1
> WHERE F1.keycol= Foobar.keycol);
>
> The proprietary, non-standard UPDATE.. FROM.. syntax is a total
> disaster in the ANSI model and in implementation, but that is another
> rant.
>
> Trying to UPDATE the temporary result of a JOIN syntax would be
> useless that temporary result disappears at the end of the statement
> and never touches the base tables.
> .
>
From: --CELKO-- on
/*
DROP TABLE OrderDetails, Orders;
CREATE TABLE Orders
(order_nbr INTEGER NOT NULL PRIMARY KEY,
some_col DECIMAL (9,2) NOT NULL);

INSERT INTO Orders VALUES (1, 0);
INSERT INTO Orders VALUES (2, 0);
INSERT INTO Orders VALUES (3, 0);

CREATE TABLE OrderDetails
(order_nbr INTEGER NOT NULL,
sku INTEGER NOT NULL,
item_price DECIMAL (9,2) NOT NULL,
PRIMARY KEY(order_nbr, sku),
-- FOREIGN KEY(sku) REFERENCES Products(sku)
FOREIGN KEY(order_nbr) REFERENCES Orders(order_nbr));

INSERT INTO OrderDetails VALUES (1, 1, 500.00);
INSERT INTO OrderDetails VALUES (1, 2, 205.00);
INSERT INTO OrderDetails VALUES (2, 1, 490.95);
INSERT INTO OrderDetails VALUES (3, 1, 480.00);

SELECT * FROM Orders;

UPDATE Orders
SET Orders.some_col = OrderDetails.item_price
FROM Orders
INNER JOIN
OrderDetails
ON Orders.order_nbr = OrderDetails.order_nbr;

results -- see item #1; last physical value
1 205.00 - where is the $500.00?
2 490.95
3 480.00
*/

--repeat with new physical ordering
DELETE FROM OrderDetails;
DELETE FROM Orders;
DROP INDEX OrderDetails.foobar;

-- index will change the execution plan
CREATE INDEX foobar ON OrderDetails (order_nbr, item_price);

INSERT INTO Orders VALUES (1, 0);
INSERT INTO Orders VALUES (2, 0);
INSERT INTO Orders VALUES (3, 0);

INSERT INTO OrderDetails VALUES (1, 2, 205.00);
INSERT INTO OrderDetails VALUES (1, 1, 500.00);
INSERT INTO OrderDetails VALUES (2, 1, 490.95);
INSERT INTO OrderDetails VALUES (3, 1, 480.00);

UPDATE Orders
SET Orders.some_col = OrderDetails.item_price
FROM Orders
INNER JOIN
OrderDetails
ON Orders.order_nbr = OrderDetails.order_nbr;

SELECT * FROM Orders;

/*
Results
1 500.00
2 490.95
3 480.00
*/

What is the first property that you must have in an INDEX? It cannot
change the results of a statement, only the performance. See the
problem? That is the ANSI model, along with set-oriented updating as I
previously outlined.

This would not have happened with the ANSI syntax. That's the point
that I am trying to make. The ANSI equivalent of the incorrect query
above is

UPDATE Orders -- no alias allowed!
SET some_col
= (SELECT item_price
FROM OrderDetails
WHERE OrderDetails.order_nbr = Orders.order_nbr)
WHERE EXISTS
(SELECT *
FROM OrderDetails
WHERE OrderDetails.order_nbr = Orders.order_nbr);

Or I could use a MERGE. That is the direction that several MVPs and
language designers want Microsoft to take when the uPDATE.. FROM is
deprecated.

This will of course result in an error, and even the most junior of
junior programmers will eventually figure out (probably by asking a
senior) what's wrong. At that point, either the query is corrected to
match the request, or a note is sent back to management asking for a
clarification of the ambiguity in the request.

Bottom line: UPDATE FROM *can* be safely used - but only if you are
FOREVER certain that no single row in the target table can EVER be
joined to more than one row in the source table(s); FOREVER in the
ENTIRE LIFETIME of the schema; FOREVER across all programmers yet to
come.

I like to err on the safe side, I do not bet only an endless stream of
100% perfect programmers.