2014-03-31 56 views
5

我正在尝试使用sql表来实现一个FIFO队列。从加入时删除CTE

我有以下的SQL(修改发布),加入和参数的使用对于这个过程的工作方式很重要。

With cte as (
    select top(1) q.* from queue q with (readpast) 
    inner join MyTable a on q.id = a.myTableID AND myTable.procID = @myParam 
    order by q.Data asc 
) 
delete from cte 
    output 
     deleted.ID, 
     deleted.col1 

运行此语句返回一个错误“视图或函数‘CTE’不可更新,因为修改会影响多个基表。”

我明白为什么会抛出错误,但我无法弄清楚是如何解决它的。任何意见将不胜感激!

回答

13

可以使用exists(),而不是内部的CTE加盟MyTable

with cte as 
(
    select top(1) q.id, 
       q.col1 
    from queue q with (readpast) 
    where exists(
       select * 
       from MyTable a 
       where q.id = a.myTableID AND 
        a.procID = @myParam 
      ) 
    order by q.Data asc 
) 
delete from cte 
output deleted.ID, deleted.col1; 
+0

这正是我正在寻找的,谢谢! – Jay

+0

对于Kieninger提供的示例,这种方法的好处在于,它提供了一种构建DELETE命令的一致方法,您可以在其中首先测试SELECT的结果以查看cte中的DELETE行将影响哪些行。 –

4

像这样的东西?

With cte as (
    select top(1) q.* from queue q with (readpast) 
    inner join MyTable a on q.id = a.myTableID AND myTable.procID = @myParam 
    order by q.Data asc 
) 
delete from queue 
Where ID in (Select Id from cte) 
+0

这是绝对有可能从CTE删除,SQL Server将推断底层来自select语句的表。我遇到的问题是我正在加入另一张桌子,所以要从中删除的表现在不明确。 我会围绕你的答案做一些测试,并发将在这里成为一个问题,所以我担心在IN语句中锁定。 – Jay

1

CTE的使用感觉被迫在这里。你可以简单:

DELETE FROM [queue] 
    WHERE id IN ( 
    SELECT TOP 1 
      q.id 
     FROM [queue] q WITH (READPAST) 
      INNER JOIN 
      MyTable a ON q.id = a.myTableID 
        AND myTable.procID = @myParam 
    ORDER BY q.Data ASC) 

如果你想使用CTE我喜欢@沙林的答案,但使用的活着而不是:

WITH cte AS (
    SELECT TOP 1 
     q.id 
    FROM [queue] q WITH (READPAST) 
     INNER JOIN 
     MyTable a ON q.id = a.myTableID 
        AND myTable.procID = @myParam 
    ORDER BY q.Data ASC 
) 
DELETE [queue] 
WHERE EXISTS(SELECT 1 FROM cte WHERE cte.id = [queue].id)