在我没有设置自己的数据库上工作,我正在挖掘一些存储过程以找出它们在做什么。
在这里我发现许多变量是通过 SELECT @var = 设置的,我从来没有真正做过这样的事情并且经常只使用 SET @var =。
阅读文档Microsoft TSQL以及Stackoverflow在我看来它们在功能上相似但不完全相似。
所以我决定用
DECLARE @var1 varchar(200)
SELECT @var1 = 'Generic Name'
SELECT @var1 = (SELECT Name FROM Users)
SELECT @var1 AS 'Company Name'
DECLARE @var2 varchar(30)
SELECT @var2 = 'Generic Name'
SET @var2 = (SELECT Name FROM Users)
SELECT @var2 AS 'Company Name'
DECLARE @var3 varchar(200)
SELECT @var3 = 'Generic Name'
SELECT @var3 = Name FROM Users
SELECT @var3 AS 'Company Name'
DECLARE @var4 varchar(200)
SELECT @var4 = 'Generic Name'
SELECT @var4 = Name FROM Users WHERE Name = '2000'
SELECT @var4 AS 'Company Name'
DECLARE @var5 varchar(200)
SELECT @var5 = 'Generic Name'
SELECT @var5 = (SELECT Name FROM Users WHERE Name = '2000')
SELECT @var5 AS 'Company Name'
根据文档,我希望 var1 具有查询中的最后一个值,并且不会引发错误。但是 var 1 和 var 2 都抛出错误
子查询返回了 1 个以上的值。当子查询跟在 =、!=、<、<=、>、>= 或子查询用作表达式时,这是不允许的。
上面的结果是基于文档的 set 预期结果,但不是根据我的理解通过 select 分配变量。Var3 确实产生了采用返回的姓氏的预期结果。
同样,var4 和 var5 的行为也很奇怪。这两个查询都不返回结果,所以我希望两者都保留其通用名称的旧值。但是只有 var4 保留了它的旧值。Var5 改为设置为 NULL。我不明白为什么。对我来说,似乎在某些情况下 SELECT @var = 的行为与 SET @var = 完全相同,并且在某些情况下它根据文档进行操作。
SELECT
和之间的主要区别在于SET
前者可以同时执行多个分配,例如就我个人而言,我会更简洁地做到这一点,同时删除
SET
和SELECT
:SET
和as 赋值运算符都SELECT
具有相同的限制,如果您分配子查询的结果,该子查询必须恰好返回一行,因此您不会强制 SQL Server 尝试确定您指的是哪一行。当不涉及子查询时,此限制会放宽(并且根据标准,它的工作方式不同,而不是 Microsoft 做出的某些选择)。因此,您的前两个案例按设计工作,并且预期会出现错误消息。@var3
并且@var4
两者都按我预期的那样工作(尽管我个人会以不同的方式写这个 - 例如,如果您想要一些“最后”行的概念,请使用 ORDER BY,MIN,MAX 等告诉 SQL Server 您指的是“最后”行。 ). 正如所写,我的结果是:@var5
也按预期工作。是的,您首先分配了一个文字值,但是子查询结果的分配 - 在没有任何错误的情况下 - 覆盖了先前的值。如果是空集,则将值设置为NULL
。如果从子查询输出多于一行,则该结构会出现这种情况。我认为您所期望的是发生的事情
SELECT @var1 = Name FROM Users
- 请注意,这不再涉及子查询。在不确定最多需要一条记录时使用此构造时(例如,当通过唯一键查询时),我会特别要求给定记录,而不是让它碰碰运气,第一个使用
SELECT TOP 1
,最低/最高使用MIN()
/MAX()
聚合等。还要始终确保(聚合方法除外)包含一个排序,或者如果有多个排序,则您获得的值将是任意的,并且每次都可能不同。按照这些示例中的格式设置,当有多个匹配行时,含义不明确,我希望服务器出错。@var3
当多行匹配时,如上面的设置示例不返回错误的事实是 IMO 的错误。因为
@var5
这是同一个问题。子查询运行并返回零行,因为没有要设置@var5
的值被设置为NULL
。@Var4 示例确实看起来很奇怪,尽管它无论如何都是一个奇怪的构造。我已经测试了三种主要的表类型,但我没有得到你描述的行为,设置了 NULL,而是像我预期的那样让变量单独存在。虽然这是 SQL Server 2017,但我目前没有立即可用于测试的 2016 实例。