SQL Server:在存储过程中的变量中存储多个值
Posted
技术标签:
【中文标题】SQL Server:在存储过程中的变量中存储多个值【英文标题】:SQL Server : store multiple values in variable in stored procedure 【发布时间】:2021-06-02 16:13:52 【问题描述】:我正在尝试向存储过程中的变量添加多个值。 我的要求是将多个值存储在一个变量中,稍后再次使用它来删除这些值。
DECLARE @EmpID
SET @EmpID = (SELECT e.id
FROM employee e,Technology t
WHERE e.status = 'InActive'
AND e.id = t.Mainid
UNION
SELECT e.id
FROM employee e,Technology t
WHERE e.status = 'InActive'
AND e.id = t.AssociateID)
DELETE FROM Technology
WHERE Mainid IN (@EmpID) OR AssociateID IN (@EmpID)
当我尝试这个查询时,我得到一个错误
子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。
【问题讨论】:
一个标量变量只能包含一个原子值。使用表类型参数/变量。 即使在子查询错误之前,您也会收到错误“关键字'Set'附近的语法不正确”,因为没有为标量变量@987654324指定数据类型@. Bad habits to kick : using old-style JOINs - 旧式 逗号分隔的表格列表 样式已替换为 ANSI 中的 proper ANSIJOIN
语法-92 SQL 标准(近 30 年前),不鼓励使用它
最后,停止使用 1980 年的旧语法。显式 JOIN 语法于 1992 年问世;差不多30年前。 Bad Habits to Kick : Using old-style JOINs(Marc 以秒的优势击败了我,但今年离开是为了真正把钉子钉进去)。
如果除了删除之外您不需要任何 ID:WITH RowsToDelete AS (SELECT T.* FROM Technology T JOIN Employee E ON E.status = 'InActive' AND (E.id = T.Mainid OR E.id = T.AssociateID) DELETE RowsToDelete
。不需要联合、变量或其他更复杂的构造。作为奖励,您可以在删除之前先使用SELECT * FROM RowsToDelete
,看看实际会发生什么。
【参考方案1】:
如上所述,您不能将变量视为数组,您需要使用表变量或临时表。
这样做看起来像下面这样(注意我还使用了更可取且可读的join
语法)
declare @EmpId table (Id int)
insert into @EmdId(Id)
select e.id
from employee e join Technology t on e.id = t.Mainid
where e.status = 'InActive'
union
select e.id
from employee e join Technology t on e.id = t.AssociateID
where e.status = 'InActive'
delete from t
from @EmpId e join Technology t
on t.Mainid = e.Id or t.AssociateID=e.Id
但是,我认为不需要存储行的 ID 来删除它们。只需直接删除行 - 有多种方法可以这样做,一种是使用 exists
与 Employees
表关联:
delete from t
from Technology t
where exists (select * from employee e where e.id = t.Mainid and e.status 'InActive')
or exists (select * from employee e where e.id = t.AssociateID and e.status 'InActive')
您可以将上述内容作为select * from
运行以验证要删除的行。
【讨论】:
您可以简化:where exists (select 0 from employee e where e.status = 'InActive' and e.id in (t.mainId, t.associateId))
谢谢@pwilcox - 是的,这是可能的,我可能想调查生成的执行计划,可能会产生索引扫描而不是两个低成本索引搜索的风险;取决于数据和表索引。
谢谢@Stu ?。以上查询符合我的要求【参考方案2】:
鉴于您需要存储值以供以后使用,您可以使用 XML 数据类型来完成此操作。
SET NOCOUNT ON;
DECLARE @Employees table ( id int, [status] varchar(10) );
INSERT INTO @Employees VALUES ( 1, 'InActive' ), ( 2, 'Active' );
DECLARE @Technology table ( AssociateID int, MainID int );
INSERT INTO @Technology VALUES ( 1, 1 ), ( 2, 2 );
DECLARE @EmpIds xml = (
SELECT * FROM (
SELECT
e.id
FROM @Employees AS e, @Technology AS t
WHERE
e.[status] = 'InActive'
AND e.id = t.MainID
UNION
SELECT
e.id
FROM @Employees AS e, @Technology AS t
WHERE
e.[status] = 'InActive'
AND e.id = t.AssociateID
) AS x
FOR XML PATH ( '' ), ROOT ( 'employeeIds' )
);
DELETE FROM @Technology WHERE MainID IN (
SELECT x.f.value( '.', 'int' ) FROM @EmpIds.nodes( '//employeeIds/id' ) x( f )
) OR AssociateID IN (
SELECT x.f.value( '.', 'int' ) FROM @EmpIds.nodes( '//employeeIds/id' ) x( f )
);
【讨论】:
不知道为什么投反对票。该请求明确指出My requirement is to store multiple values in a variable and use it again later to delete the values.
这完成了。
抱歉没有解释。有时,如果要求本身在上下文中存在问题,那么满足规定的要求并不是一个好主意。在这里,我相信处于类似情况的 OP 和其他人最好被告知不要尝试他们的目标。向他们展示如何实现他们的目标,而不加任何警告说这是一个坏主意可能会导致他们走上一条坏路。这就是我投反对票的原因。
不确定你对表变量或临时表有什么,但xml
不是解决方案以上是关于SQL Server:在存储过程中的变量中存储多个值的主要内容,如果未能解决你的问题,请参考以下文章
我应该如何使用 sql server 中的存储过程将列名存储在变量中?