SQL Server CTE中何处存在引用列?
我在SQL Server中有一个带有WHERE EXISTS子句的CTE,我正在尝试使用它,而不是使用联接SQL Server CTE中何处存在引用列?,sql,sql-server-2012,common-table-expression,exists,Sql,Sql Server 2012,Common Table Expression,Exists,我在SQL Server中有一个带有WHERE EXISTS子句的CTE,我正在尝试使用它,而不是使用联接 WITH Work_Info AS ( SELECT a.fName, a.lName, a.workID, a.carID FROM tbl_info a WHERE EXISTS (SELECT b.workID FROM tbl_work b WHERE a
WITH Work_Info AS
(
SELECT
a.fName,
a.lName,
a.workID,
a.carID
FROM tbl_info a
WHERE EXISTS (SELECT b.workID
FROM tbl_work b
WHERE a.workID = b.workID)
AND EXISTS (SELECT c.carID, dbo.age_function(a.startDate, c.DOB) AS AGE
FROM tbl_car c
WHERE a.carID = c.carID
)
我试图在CTE后面的语句中使用/引用别名为AGE的列,例如:
update tble_info a
SET adult =
CASE WHEN AGE < 18 THEN 'NO'
你的问题是你没有把年龄列在你的CTE里。它只在WHERE子句中使用,所以它只是作为更大的EXISTS过滤器的一部分
基本上,如果你想运行年龄函数并返回值,你必须将tbl_car加入tbl_info。在EXISTS语句的内部WHERE子句中,您已经在这样做了,因此实际加入a.carID=c.carID并将年龄列添加到CTE定义中不会对性能造成影响。我认为您误解了它的工作原理。不能从EXISTS子查询返回值。您需要使用联接: 您可以按如下方式进行更新:
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;
我更喜欢和建议使用合并的原因,即使您不是真正的合并,您只是在更新中讨论
附录
我更喜欢合并而不是仅仅使用更新的主要原因是它可以防止不确定的更新。使用以下示例架构:
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);
我们可以看到T1中的单个ID在T2中有两行,一行年龄超过18岁,另一行年龄低于18岁,因此如果我们运行此更新:
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;
T1.成人设置为是。使用“合并”运行时:
我得到以下错误:
MERGE语句多次尝试更新或删除同一行。当目标行与多个源行匹配时,会发生这种情况。MERGE语句不能多次更新/删除目标表的同一行。优化ON子句以确保目标行最多匹配一个源行,或使用GROUP BY子句对源行进行分组
提示我检查我的查询,并确保它是确定性的
链接文章中还提到了其他原因,例如ANSI合规性对我来说不是一个大问题,以及使用UPDATE更新视图。。在视图上使用INSTEAD OF触发器将失败,但不会使用MERGE,这也是我还没有睡过觉的事情
别误会,我仍然在使用更新。。有时,但仅适用于大型一次性更新,因为我确信重复项不是问题,因为它确实提供了一个具有较低IO的更好计划。显示您的表架构。不清楚您要使用的年龄是根据tbl_car.DOB计算的,还是存在于tbl_info中。抱歉,我刚才看到了这条评论,我有一个计算年龄的函数,一个参数startDate来自tbl_info,另一个参数DOB来自tbl_car。我意识到我写的一些名字有点让人困惑。任何我尝试过GarethD建议使用MERGE的人,它似乎在做我想做的事情。谢谢GarethD!我将尝试使用合并。+1进行加入更新,但我不明白为什么合并会更可取。@ypercube我已经添加了一个更好的描述合并提供的好处。不过,我怀疑这更多的是一个偏好问题,这就是为什么我提供了两种解决方案。尽管合并存在一些问题,但尚未解决。请参阅Aaron Bertrand的文章:Alex Kuznetsov在上的回答我以前没有听说过这些问题,尽管这种用法不适用于Aaron文章的主要抱怨,因为这一关键点没有得到满足:您使用MERGE对基表执行更新,其中包括UPDATE和DELETE或INSERT操作;。不过,这绝对是一件值得考虑的事情。
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;
INSERT T2 (ID, Age) VALUES (1, 20), (1, 5); -- order changed
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;