[英]How do I loop through a temp table in a stored procedure with no pk
Problem: 问题:
I need to loop through the records in one table, pulling the employee number and comparing this employee number against another table to see if they're still active employees. 我需要在一个表中循环记录,拉出员工编号并将该员工编号与另一个表进行比较,以查看他们是否仍然是活跃的员工。 If they are no longer active employees I need to pass the data from this row into another stored proc.
如果他们不再是活跃的员工,我需要将此行中的数据传递到另一个存储过程。
Research: 研究:
I've googled around quite a bit and realize that I shouldn't use cursors for this. 我已经google了很多,并意识到我不应该使用游标。 I did however, find the following examples:
但是,我找到了以下示例:
However, it seems like they use a pk to loop through the records. 但是,似乎他们使用pk来遍历记录。 Employee numbers can be the same for multiple recods in my scenario
在我的方案中,多个recods的员工编号可以相同
Questions: 问题:
Since you haven't given us a full description of your situation, we cannot give a complete answer, however, in general, it's Loops that you want to avoid in a set-based language like SQL and not Cursors per se (the problem with Cursosr is that they require the Loops). 既然你还没有完整地描述你的情况,我们就无法给出一个完整的答案,但是,一般来说,它是你想要在基于集合的语言中避免的循环 ,比如SQL而不是游标本身 (问题是Cursosr是他们需要循环)。
In your comments you provide a little bit more information in that you want to " loop through first table, compare to second table, and when the compare fails i delete records from first table. In essense I'm deleting recods from the first table of employees who are no longer with the company. " 在你的评论中,你提供了一些信息,你想要“ 循环第一个表,与第二个表比较,当比较失败时,我从第一个表中删除记录。在essense我正在从第一个表中删除recods不再与公司合作的员工。 “
Here is how you can do this in SQL: 以下是在SQL中如何执行此操作:
DELETE From FirstTable
WHERE FirstTable.EmployeeID NOT IN
(
SELECT SecondTable.EmployeeID
FROM SecondTable
WHERE SecondTable.Flag = 'Y'
)
No Loops are needed ... 不需要循环......
If the issue then is that you want to use a pre-existing Stored Procedure to do the deletion, then there are a several possibilities: 如果问题是您想要使用预先存在的存储过程进行删除,那么有几种可能性:
First, you can extract the contents of the Stored Procedure and re-write them for these preceding WHERE conditions. 首先,您可以提取存储过程的内容,并为这些先前的WHERE条件重新编写它们。 I understand that this is code duplication and that it violates some people's DRY instincts, however, understand that SQL is NOT an Object-Oriented development environment and that sometimes code duplication has to happen.
我知道这是代码重复,它违反了某些人的DRY本能,但是,要了解SQL 不是面向对象的开发环境,有时代码重复必须发生。
The second option would be to refactor the stored procedure so that it could accept a TableParameter for its EmployeeId's to Delete. 第二种选择是重构存储过程,以便它可以接受TableParameter以使其EmployeeId删除。 This is complicated though, and we would need to see that stored procedure to advise you on it.
虽然这很复杂,但我们需要查看存储过程以便为您提供建议。
The third option would be to use string aggregation to build dynamic SQL to call the stored procedure for each EmployeeID to be deleted like so: 第三种选择是使用字符串聚合来构建动态SQL,以便为每个EmployeeID调用存储过程,如下所示:
DECLARE @sql As NVarchar(MAX);
SET @sql = N'';
SELECT @sql = @sql + '
EXEC YourProc ''' + CAST(EmployeeID As NVARCHAR(MAX)) + '''; '
FROM FirstTable
WHERE FirstTable.EmployeeID IN
(
SELECT SecondTable.EmployeeID
FROM SecondTable
WHERE SecondTable.Flag = 'Y'
)
EXEC(@sql);
This avoids both the Looping and the Cusror problems, though many dislike it also. 这避免了循环和Cusror问题,尽管许多人也不喜欢它。 I prefer this solution myself, largely because of its generality.
我自己更喜欢这个解决方案,主要是因为它的普遍性。
This will delete all records from your employee data table if there are no matching rows in your current employees table. 如果当前employees表中没有匹配的行,这将删除员工数据表中的所有记录。
I'd sugest you replace the DELETE FROM
with SELECT * FROM
and then when you're happy to delete the results change it back to DELETE
我想你用
SELECT * FROM
替换DELETE FROM
然后当你乐意删除结果时将它改回DELETE
DELETE FROM
EmployeeDataTable
WHERE
NOT EXISTS
(SELECT
NULL
FROM
CurrentEmployees
WHERE
EmployeeDataTable.EmployeeID = CurrentEmployees.EmployeeID
)
EDIT: Just saw your comment about the Active flag, this means the query can be changed to 编辑:刚看到你对Active标志的评论,这意味着可以将查询更改为
DELETE FROM
EmployeeDataTable
WHERE
EXISTS
(SELECT
NULL
FROM
CurrentEmployees
WHERE
EmployeeDataTable.EmployeeID = CurrentEmployees.EmployeeID
CurrentEmployees.IsActive <> 'Y'
)
I would do this by looping through a cursor. 我会通过循环游标来做到这一点。 You can also add a unique ID to the cursor so you know which row you are currently on.
您还可以向光标添加唯一ID,以便知道当前所在的行。
DECLARE @id uniqueidentifier
DECLARE @empName VARCHAR(50)
SELECT newId() AS Id, *
INTO #mytemp
FROM MyEmployees
ORDER BY EmpName
while EXISTS(SELECT TOP 1 1 FROM #mytemp)
BEGIN
--Get row from cursor to process
SELECT TOP 1 @id = Id, @empName = EmpName FROM #mytemp
--Do you processing here. Call other stored proc.
--Remove processed row from cursor.
DELETE FROM #mytemp WHERE Id = @id
END
DROP TABLE #mytemp
Have you considered using the MERGE
statement : http://technet.microsoft.com/en-us/library/bb510625.aspx 您是否考虑过使用
MERGE
声明: http : //technet.microsoft.com/en-us/library/bb510625.aspx
You have clauses for : 你有以下条款:
You can then insert, update or delete records depending on the match type. 然后,您可以根据匹配类型插入,更新或删除记录。 You can also output the action from match to a temporary table for additional custom operations.
您还可以将匹配操作输出到临时表以进行其他自定义操作。
For instance, you can do : 例如,你可以这样做:
MERGE INTO Table1
USING Table2 ON Table1.EmployeeID = Table2.EmployeeID
WHEN MATCHED
THEN UPDATE SET Table1.SomeField = Table2.SomeOtherField
WHEN NOT MATCHED BY SOURCE
THEN DELETE
WHEN NOT MATCHED BY TARGET
THEN Insert (Name, Status) VALUES (EmployeeName, 'Active')
Sometimes, cursors are the right solution for a variety of reasons. 有时,游标是出于各种原因的正确解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.