2

たとえば、次のようなテーブルがあります(SQL Server 2008):

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)

最大の「dtOut」を持つものを除いて、「type」に同じ「dtIn」を持つ同じ「type」(2つ以上が見つかった場合)のすべてのレコードを削除する必要があります。つまり、上記の表は次のようになります。

(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 where type = type ....とにかく、これについて助けていただければ幸いです...

4

5 に答える 5

7

削除する行を選択する1つの方法は次のとおりです。

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です。ただし、実際にdeleteステートメントを実行する前に、必要な処理が実行されることをテストしてください。

オンラインで動作することを確認してください:sqlfiddle


アップデート

ROW_NUMBERを使用したアプローチは次のとおりです。

;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

于 2012-07-20T22:06:18.690 に答える
1

あまりエレガントではありませんが(+条件はマークの答えと同じです)、それは代替手段です。

フィドルはここにあります

;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
              ) 
于 2012-07-20T22:41:22.807 に答える
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
于 2012-07-20T23:37:19.120 に答える
0

私の物は@Markのものとは少し異なりますが、同じ結果が得られるはずだと思います(それ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
)
于 2012-07-20T22:14:47.263 に答える
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
              )    
于 2012-07-21T00:00:17.463 に答える