2014-03-31 61 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)