Sql 参数来填充“IN”子句
在此过程中,用户传递一个项目ID。我希望能够传递不确定数量的项目ID,以便可以将where子句从projectd=@projectd更改为@projectd中的projectd 这样,我可以通过一次对DB的调用删除十几个项目,而不是重复调用DB 有没有一个好的策略?我正在从Access呼叫SPSql 参数来填充“IN”子句,sql,tsql,stored-procedures,ms-access-2007,Sql,Tsql,Stored Procedures,Ms Access 2007,在此过程中,用户传递一个项目ID。我希望能够传递不确定数量的项目ID,以便可以将where子句从projectd=@projectd更改为@projectd中的projectd 这样,我可以通过一次对DB的调用删除十几个项目,而不是重复调用DB 有没有一个好的策略?我正在从Access呼叫SP create procedure dbo.cpas_DeleteProject @ProjectID INt = 0, @errorFlag int OUTPUT AS set @errorFlag=0
create procedure dbo.cpas_DeleteProject
@ProjectID INt = 0,
@errorFlag int OUTPUT
AS
set @errorFlag=0
BEGIN TRY
BEGIN TRANSACTION
DELETE FROM tblWOTasks WHERE tblWOTasks.WorkOrderID IN (SELECT ID FROM tblWorkOrders WHERE ProjectID=@ProjectID)
DELETE FROM tblELaborSpread WHERE tblELaborSpread.WorkOrderID IN (SELECT ID FROM tblWorkOrders WHERE ProjectID=@ProjectID)
DELETE FROM tblWorkOrders WHERE tblWorkOrders.ProjectID IN (SELECT ID FROM tblWorkOrders WHERE ProjectID=@ProjectID)
DELETE FROM tblCPTransactiON WHERE tblCPTransactiON.CPProjectID=@ProjectID
DELETE FROM tblCPJE WHERE tblcpje.jeid IN
(SELECT tblcpje.JEID FROM tblCPJE left joIN tblCPTransactiON as CR ON CR.CPTransID = tblCPJE.JECreditID
left joIN tblCPTransactiON as DR ON DR.CPTransID = tblCPJE.JEDebitID
WHERE DR.CPTransID is null AND cr.CPTransID is null)
DELETE FROM tblProjectTasks WHERE tblProjectTasks.ProjectID=@ProjectID
DELETE FROM xrefProjectMICAP WHERE xrefProjectMICAP.ProjectID=@ProjectID
DELETE FROM tblworkorders WHERE tblWorkOrders.ProjectID=@ProjectID
DELETE FROM tblprojects WHERE tblProjects.ID=@ProjectID
--Project Comments cascade delete....
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
set @errorFlag=1
END CATCH
您可以考虑使用表值参数…尽管在SQL Server中可以使用表值参数,但据我所知,从Access中填充这些参数并不容易 解决方案可以是在存储过程中使用动态SQL,然后在Access应用程序中创建的varcharmax中使用项目ID,例如:
@projectIdList = '200,300,400'
然后在动态SQL中,您只需将其作为
'WHERE tblProjects.ID IN (' + @projectIdList + ')'
这显然容易受到SQL注入攻击,但根据Access应用程序的使用方式,这可能是可以接受的
另一个更安全的解决方案是,在调用存储过程之前,允许Access将projectId作为行写入一个小表中,然后在存储过程中执行如下删除操作:
DELETE FROM tblprojects
WHERE tblProjects.ID IN (SELECT ProjectId FROM ProjectIdsToBeDeleted)
这是一种更安全、更干净的方法,因为您避免了动态SQL。但是,您需要某种方法来处理并发性—可能是在填充ProjectdTobeDeleted表时生成一个唯一标识符,然后在执行存储过程时对该标识符进行筛选。查看本文中选择的答案:
用户所做的是创建一个存储过程,该过程将分割逗号分隔的字符串,然后返回一个表。一旦有了ID表,就可以将其插入到查询中。可能需要稍作修改才能使其正常工作,因为您的查询更多,但原理仍然相同。如果无法使用表参数,请创建一个分隔字符串参数来保存多个Id值,并将该分隔字符串转换为进程内的表变量。在线上有许多T-SQL UDF可以实现这一点。一篇好文章是 那么您的In子句将如下所示:
Where [Somecolumn] In (Select funcColName From dbo.ConvertFunction(@stringParameter))
我能够将多个值传递给存储过程的唯一方法是将它们连接到一个字符串中,并将该字符串传递给SP,然后在SP的开头解析该字符串,类似于这样的东西,项目id被删除
CREATE PROCEDURE [dbo].[cpas_DeleteProject]
@ProjectID varchar(3000)
@errorFlag int OUTPUT
AS
--Parse function
DECLARE @tblstring Table(ProjectID int) --table variable to store all parsed ProjectID's
DECLARE @project varchar(10)
DECLARE @StartPos int,
@Length int,--streng lengd
@Delimeter varchar(1)=','--delimeter
WHILE LEN(@ProjectID) > 0
BEGIN
SET @StartPos = CHARINDEX(@Delimeter, @ProjectID)
IF @StartPos < 0 SET @StartPos = 0
SET @Length = LEN(@ProjectID) - @StartPos - 1
IF @Length < 0 SET @Length = 0
IF @StartPos > 0
BEGIN
SET @Project = SUBSTRING(@ProjectID, 1, @StartPos - 1)
SET @ProjectID = SUBSTRING(@ProjectID, @StartPos + 1, LEN(@ProjectID) - @StartPos)
END
ELSE
BEGIN
SET @Project = @ProjectID
SET @ProjectID = ''
END
INSERT @tblstring (ProjectID) VALUES(@Project)
END
set @errorFlag=0
BEGIN TRY
BEGIN TRANSACTION
DELETE FROM tblWOTasks WHERE tblWOTasks.WorkOrderID IN (SELECT ID FROM tblWorkOrders WHERE ProjectID in (SELECT ProjectID from @tblstring))
DELETE FROM tblELaborSpread WHERE tblELaborSpread.WorkOrderID IN (SELECT ID FROM tblWorkOrders WHERE ProjectID in (SELECT ProjectID from @tblstring))
DELETE FROM tblWorkOrders WHERE tblWorkOrders.ProjectID IN (SELECT ID FROM tblWorkOrders WHERE ProjectID in (SELECT ProjectID from @tblstring))
DELETE FROM tblCPTransactiON WHERE tblCPTransactiON.CPProjectID in (SELECT ProjectID from @tblstring)
DELETE FROM tblCPJE WHERE tblcpje.jeid IN
(SELECT tblcpje.JEID FROM tblCPJE left joIN tblCPTransactiON as CR ON CR.CPTransID = tblCPJE.JECreditID
left joIN tblCPTransactiON as DR ON DR.CPTransID = tblCPJE.JEDebitID
WHERE DR.CPTransID is null AND cr.CPTransID is null)
DELETE FROM tblProjectTasks WHERE tblProjectTasks.ProjectID in (SELECT ProjectID from @tblstring)
DELETE FROM xrefProjectMICAP WHERE xrefProjectMICAP.ProjectID in (SELECT ProjectID from @tblstring)
DELETE FROM tblworkorders WHERE tblWorkOrders.ProjectID in (SELECT ProjectID from @tblstring)
DELETE FROM tblprojects WHERE tblProjects.ID in (SELECT ProjectID from @tblstring)
--Project Comments cascade delete....
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
set @errorFlag=1
END CATCH
我不认为你们可以将一个表值参数传递给SPI。我认为其他两个答案更优雅,Hedinn已经竭尽全力为我回答了这个问题。我非常感谢他的努力,以及其他受访者的努力。我现在明白该怎么办了。我可能会使用SP或UDF解析出一个列表。我的Access应用程序中已经有一个创建逗号分隔列表的实用工具子组件。再次感谢,伙计们。我从没想到会有这么多评论!