I think you are misunderstanding how EXISTS works. You cannot return values from the EXISTS subquery. You would need to use JOINs:
You can do your update as follows:
WITH Work_Info AS
( SELECT a.fName,
a.lName,
a.workID,
a.carID
Age = dbo.age_function(a.startDate, c.DOB)
FROM tbl_info a
INNER JOIN tbl_car c
ON c.CarID = a.CarID
WHERE EXISTS
( SELECT 1
FROM tbl_work b
WHERE a.workID = b.workID
)
)
UPDATE Work_Info
SET adult = CASE WHEN AGE < 18 THEN 'NO' ELSE 'YES' END;
However, I recommend not using this method (it may not even work as an updateable CTE, I haven't tested). I would instead use MERGE
(I have had to assume the existance of an ID column as the PK in tbl_info):
WITH Work_Info AS
( SELECT a.ID,
Age = dbo.age_function(a.startDate, c.DOB)
FROM tbl_info a
INNER JOIN tbl_car c
ON c.CarID = a.CarID
WHERE EXISTS
( SELECT 1
FROM tbl_work b
WHERE a.workID = b.workID
)
)
MERGE tbl_Info a
USING Work_Info w
ON a.ID = w.ID
WHEN MATCHED THEN UPDATE
SET adult = CASE WHEN w,Age < 18 THEN 'NO' ELSE 'YES' END;
The reasons I prefer (and suggest) to use MERGE
even though you are not really merging you are only updating are discussed on sqlblog.com
ADDENDUM
To elaborate further on the main reason I prefer MERGE
over just using UPDATE
is that it safeguards against non deterministic updates. With the following sample schema:
CREATE TABLE T1 (ID INT, Adult CHAR(3));
CREATE TABLE T2 (ID INT, Age INT);
INSERT T1 (ID) VALUES (1);
INSERT T2 (ID, Age) VALUES (1, 5), (1, 20);
We can see that a single ID in T1 has two rows in T2, one where the age is over 18 and one where it is under, so if we run this update:
WITH CTE AS
( SELECT T1.ID, T1.Adult, T2.Age
FROM T1
INNER JOIN T2
ON T1.ID = T2.ID
)
UPDATE CTE
SET Adult = CASE WHEN Age < 18 THEN 'NO' ELSE 'YES' END;
There will be no error, and the T1 will be updated, but we don't know whether it would be set to NO
or YES
, since we don't know which reford of T2 will be the last encountered and "stick" in T1, when I ran the above Adult was set to NO
, however when I change the insert to:
INSERT T2 (ID, Age) VALUES (1, 20), (1, 5); -- order changed
T1.Adult
is set to YES
. When I run using MERGE
:
WITH CTE AS
( SELECT T1.ID, T1.Adult, T2.Age
FROM T1
INNER JOIN T2
ON T1.ID = T2.ID
)
MERGE T1
USING CTE
ON CTE.ID = #T1.ID
WHEN MATCHED THEN UPDATE
SET Adult = CASE WHEN Age < 18 THEN 'NO' ELSE 'YES' END;
I get the following error:
The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.
Prompting me to review my query, and ensure that it is deterministic.
There are other reasons mentioned in the linked article, such as ANSI compliance (not a huge concern to me), and also updating a view using UPDATE .. FROM
with an INSTEAD OF TRIGGER
on the view will fail, but won't with MERGE, this is again something I have not yet lost any sleep over.
Don't get me wrong, I still use UPDATE .. FROM
on occasion, but only really for large one off updates when I know for sure duplicates are not an issue as it does offer a better plan with lower IO.