I keep forgetting how this concept works each time I go to do it. I always start off with a simple update, then find I need a quick join to another table to use a value there to complete the update. What I forget is how the table referenced after UPDATE relates to the tables/columns in the FROM (and SET) areas.
From what I understand now, the "x" in "UPDATE x" either directly matches a table referenced in the FROM clause, or directly matches an alias for a table in the FROM. In the example below, there are 3 updates that are functionally equivalent.
CREATE TABLE #table1 (t1_pk int, t1_months smallint);
CREATE TABLE #table2 (t2_pk int, t2_t1_pk int, t2_starts datetime, t2_ends datetime);
INSERT INTO #table1 VALUES (1, 2);
INSERT INTO #table1 VALUES (2, 5);
INSERT INTO #table2 VALUES (1, 1, '2000-01-01 11:45 PM', NULL);
INSERT INTO #table2 VALUES (2, 1, '2001-01-01 02:50 AM', NULL);
INSERT INTO #table2 VALUES (3, 2, '2004-01-04 06:45 PM', NULL);
INSERT INTO #table2 VALUES (4, NULL, '2005-01-08 03:21 PM', NULL);
SELECT * FROM #table1;
SELECT * FROM #table2;
/* Version 1 */
UPDATE #table2
SET t2_ends = DATEADD(month, t1_months, t2_starts)
FROM #table2
INNER JOIN #table1 ON t1_pk = t2_t1_pk
;
/* Version 2 */
UPDATE t
SET t2_ends = DATEADD(month, t1_months, t2_starts)
FROM #table2 AS t
INNER JOIN #table1 ON t1_pk = t2_t1_pk
;
/* Version 3 */
UPDATE #table2
SET t2_ends = DATEADD(month, t1_months, t2_starts)
FROM #table1
WHERE t1_pk = t2_t1_pk
;
SELECT * FROM #table2;
DROP TABLE #table1;
DROP TABLE #table2;
Abbreviated results:
--#table1 BEFORE
t1_pk t1_months
----------- ---------
1 2
2 5
--#table2 BEFORE
t2_pk t2_t1_pk t2_starts t2_ends
----------- ----------- ----------------------- -----------------------
1 1 2000-01-01 23:45:00.000 NULL
2 1 2001-01-01 02:50:00.000 NULL
3 2 2004-01-04 18:45:00.000 NULL
4 NULL 2005-01-08 15:21:00.000 NULL
--#table2 AFTER (any of the 3 updates)
t2_pk t2_t1_pk t2_starts t2_ends
----------- ----------- ----------------------- -----------------------
1 1 2000-01-01 23:45:00.000 2000-03-01 23:45:00.000
2 1 2001-01-01 02:50:00.000 2001-03-01 02:50:00.000
3 2 2004-01-04 18:45:00.000 2004-06-04 18:45:00.000
4 NULL 2005-01-08 15:21:00.000 NULL
This was done against Sql Server 2008, and all 3 update statements had identical query plans too.
From what I understand now, the "x" in "UPDATE x" either directly matches a table referenced in the FROM clause, or directly matches an alias for a table in the FROM. In the example below, there are 3 updates that are functionally equivalent.
CREATE TABLE #table1 (t1_pk int, t1_months smallint);
CREATE TABLE #table2 (t2_pk int, t2_t1_pk int, t2_starts datetime, t2_ends datetime);
INSERT INTO #table1 VALUES (1, 2);
INSERT INTO #table1 VALUES (2, 5);
INSERT INTO #table2 VALUES (1, 1, '2000-01-01 11:45 PM', NULL);
INSERT INTO #table2 VALUES (2, 1, '2001-01-01 02:50 AM', NULL);
INSERT INTO #table2 VALUES (3, 2, '2004-01-04 06:45 PM', NULL);
INSERT INTO #table2 VALUES (4, NULL, '2005-01-08 03:21 PM', NULL);
SELECT * FROM #table1;
SELECT * FROM #table2;
/* Version 1 */
UPDATE #table2
SET t2_ends = DATEADD(month, t1_months, t2_starts)
FROM #table2
INNER JOIN #table1 ON t1_pk = t2_t1_pk
;
/* Version 2 */
UPDATE t
SET t2_ends = DATEADD(month, t1_months, t2_starts)
FROM #table2 AS t
INNER JOIN #table1 ON t1_pk = t2_t1_pk
;
/* Version 3 */
UPDATE #table2
SET t2_ends = DATEADD(month, t1_months, t2_starts)
FROM #table1
WHERE t1_pk = t2_t1_pk
;
SELECT * FROM #table2;
DROP TABLE #table1;
DROP TABLE #table2;
Abbreviated results:
--#table1 BEFORE
t1_pk t1_months
----------- ---------
1 2
2 5
--#table2 BEFORE
t2_pk t2_t1_pk t2_starts t2_ends
----------- ----------- ----------------------- -----------------------
1 1 2000-01-01 23:45:00.000 NULL
2 1 2001-01-01 02:50:00.000 NULL
3 2 2004-01-04 18:45:00.000 NULL
4 NULL 2005-01-08 15:21:00.000 NULL
--#table2 AFTER (any of the 3 updates)
t2_pk t2_t1_pk t2_starts t2_ends
----------- ----------- ----------------------- -----------------------
1 1 2000-01-01 23:45:00.000 2000-03-01 23:45:00.000
2 1 2001-01-01 02:50:00.000 2001-03-01 02:50:00.000
3 2 2004-01-04 18:45:00.000 2004-06-04 18:45:00.000
4 NULL 2005-01-08 15:21:00.000 NULL
This was done against Sql Server 2008, and all 3 update statements had identical query plans too.
Comments