2012-07-20 37 views
2

說一個表,我有這樣的(SQL Server 2008中)的表:了陷入選擇性DELETE語句在T-SQL

CREATE TABLE tbl (ID INT, dtIn DATETIME2, dtOut DATETIME2, Type INT) 

INSERT tbl VALUES 
(1, '05:00', '6:00', 1), -- will be removed 
(2, '05:00', '7:00', 1), -- will be removed 
(3, '05:01', '8:00', 1), 
(4, '05:00', '8:00', 1), 
(5, '05:00', '6:00', 2), -- will be removed 
(6, '05:00', '7:00', 2), 
(7, '05:00', '7:00', 3), 
(8, '04:00', '7:00', 3) 

我需要刪除相同的「類型的所有記錄'(如果找到2個或更多),''類型'具有相同的'dtIn',但具有最大'dtOut'的除外。換句話說,上面的表格應該導致這樣的:

(3, '05:01', '8:00', 1), -- no matching 'dtIn' for 'type' = 1 
(4, '05:00', '8:00', 1), -- largest 'dtOut' for 'type' = 1 
(6, '05:00', '7:00', 2), -- largest 'dtOut' for 'type' = 2 
(7, '05:00', '7:00', 3), -- no matching 'dtIn' for 'type' = 3 
(8, '04:00', '7:00', 3) -- no matching 'dtIn' for 'type' = 4 

你怎麼連選擇具有相同類型從同一個表中的多個行。你不能這樣做SELECT * FROM TBL其中type =類型....無論如何,我會很感激一些幫助,這...

回答

7

這裏選擇要刪除的行的一種方法:

SELECT * 
FROM tbl T1 
WHERE EXISTS 
(
    SELECT * 
    FROM tbl T2 
    WHERE T1.Type = T2.Type 
    AND T1.dtIn = T2.dtIn 
    AND (
      T1.dtOut < T2.dtOut 
      OR (T1.dtOut = T2.dtOut AND T1.id < T2.id) 
     ) 
) 

此查詢也可以很容易地更改爲實際刪除行。只需將SELECT *更改爲DELETE T1即可。但是請確實在運行刪除語句之前測試它是否做了你想要的。

看到它的在線工作:一個使用ROW_NUMBER的方法sqlfiddle


更新

這裏:

;WITH T1 AS (
    SELECT id, ROW_NUMBER() OVER (PARTITION BY Type, dtIn 
            ORDER BY dtOut DESC, ID DESC) AS rn 
    FROM tbl 
) 
SELECT * FROM tbl 
WHERE id IN 
(
    SELECT id 
    FROM T1 
    WHERE rn > 1 
) 

看到它聯機工作:sqlfiddle

+0

聽着,它怎麼連力所能及的爲你做字面上10秒我的東西內張貼,當我已經整個上午工作在這??? – ahmd0 2012-07-20 22:09:52

+3

@ ahmd0:很多練習!第一次我不得不做這樣的事情,這也花了我一段時間。 :-) – 2012-07-20 22:12:32

+0

不,認真的,馬克,你如何學習所有這些東西?有沒有特別的書教你這個...因爲它不僅僅是一種簡單的編程技巧。 – ahmd0 2012-07-20 22:13:59

0

中號INE是從@馬克的有點不同,但我相信它應該讓你相同的結果(只是因爲我認爲id是唯一的):

DELETE a 
FROM dbo.tbl a 
WHERE id <> (
    SELECT MAX(id) 
    from dbo.tbl b 
    WHERE a.type = b.type 
     AND a.dtIn = b.dtIn 
) 
+0

對不起,sqlfiddle.com似乎沒有返回正確的結果與您的查詢。這是超出我的知識,以糾正它,雖然... – ahmd0 2012-07-20 22:18:50

+2

嗯,似乎爲我工作... http://sqlfiddle.com/#!3/1ff87/2 – 2012-07-20 22:21:10

+0

嗯。奇怪,現在它確實如此。對不起,我不知道爲什麼它給了我不同的結果...也許是因爲我太累了。感謝您的意見! – ahmd0 2012-07-20 22:30:03

1

不是很優雅(+的條件是相同的馬克的答案),但它是一種選擇。

Fiddle is here

;with my_cte(ID) 
as 
(
    SELECT T1.ID 
    FROM 
     tbl T1 
     JOIN tbl T2 on 
     T1.Type = T2.Type 
     AND T1.dtIn = T2.dtIn 
     AND T1.dtOut < T2.dtOut 
) 
select * 
from tbl t 
where not exists 
       (
       select 1 
       from my_cte c 
       where t.ID = c.ID 
      ) 
1

查詢爲重複的行

我剛纔看到你可以有重複的行。所以:

DELETE X 
FROM 
    (SELECT Row_Number() OVER (PARTITION BY Type, dtIn ORDER BY dtOut DESC) Item, * 
    FROM #tbl) X 
WHERE Item > 1 

請注意,此版本不需要連接,所以應該比頁面上的所有其他查詢執行得更好。

DELETE T 
FROM #tbl T 
    CROSS APPLY (
     SELECT TOP 1 * 
     FROM #tbl T2 
     WHERE 
     T.dtIn = T2.dtIn 
     AND T.Type = T2.Type 
     ORDER BY T2.dtOut DESC, T2.ID DESC 
    ) X 
WHERE T.ID < X.ID 

DELETE T 
FROM #tbl T 
    INNER JOIN #tbl T2 
     ON T.dtIn = T2.dtIn 
     AND T.Type = T2.Type 
     AND (
     T.dtOut < T2.dtOut 
     OR (T.tdOut = T2.dtOut AND T.ID > T2.ID) 
    ) 

查詢爲沒有重複的行

如果你不能有重複的行(除ID),那麼這將是簡單的:

DELETE T 
FROM #tbl T 
WHERE EXISTS (
    SELECT * FROM #tbl T2 
    WHERE 
     T.dtIn = T2.dtIn 
     AND T.Type = T2.Type 
     AND T.dtOut < T2.dtOut 
) 

甚至

DELETE T 
FROM #tbl T 
    INNER JOIN #tbl T2 
     ON T.dtIn = T2.dtIn 
     AND T.Type = T2.Type 
     AND T.dtOut < T2.dtOut 
+0

謝謝。是的,重複記錄是可能的,所以你簡短的版本將無法正常工作。 – ahmd0 2012-07-20 23:54:09

+1

@ ahmd0增加了兩個版本 – ErikE 2012-07-21 00:15:56

+0

謝謝。給我一些時間來研究它。到目前爲止,這是我的聯盟的方式... – ahmd0 2012-07-21 16:52:15

0
DECLARE @Table TABLE  
( 
ID INT, 
newno int 
) 

insert @table 
SELECT T1.ID, 
ROW_NUMBER() OVER (PARTITION BY Type, dtIn 
           ORDER BY dtOut DESC, ID DESC) AS newno 
FROM tbl T1  

select * 
from tbl t 
where t.ID IN 
      (
       select ID from @Table where newno > 1 
      )