Как удалить все строки между двумя числовыми значениями в столбце

У меня есть таблица с двумя столбцами, id и typ:

DECLARE @tb1 AS TABLE (id INT, typ INT)
INSERT INTO @tb1
(
    id,
    typ
)
VALUES
(1,1),(2,3),(3,2),(4,3),(5,1),(6,2),(7,3),(8,3),(9,1)
,(10,3),(11,3),(12,3),(13,2),(14,3),(15,1)

При просмотре строк, упорядоченных по id, я хочу удалить все строки, находящиеся между строкой с typ = 1 и следующей строкой с typ = 2.

Я хочу этот результат:

id          typ
----------- -----------
1           1
3           2
4           3
5           1
6           2
7           3
8           3
9           1
13          2
14          3
15          1

person mhsankar    schedule 31.05.2018    source источник


Ответы (4)


Это классический вопрос типа проблемы пробелов и островов. Я рекомендую вам прочитать этот превосходный статья о пробелах и островах.

Вы можете использовать запрос, как показано ниже

;
with BoundarySuspects as 
(
    select 
        a.*, 
        seqNumber=row_number() over( order by id asc)
    from @tb1 a
    where a.typ=1 or a.typ=2 
 ),
 GapMap as
 (
     select 
        GapFrom= a.id,
        GapTill= b.id
    from BoundarySuspects a
         join
         BoundarySuspects b
        on a.typ=1 and b.typ=2 and b.seqNumber=a.seqNumber+1 
 )
    select 
        t.* 
     from @tb1 t 
         left join 
     GapMap g
         on t.id >GapFrom and t.id <GapTill
     where GapFrom is NULL
person DhruvJoshi    schedule 31.05.2018
comment
@mhsankar Рад быть полезным! Надеюсь, вы отблагодарите сообщество SO, добавив более ценные вопросы и ответы и оставаясь активными здесь. - person DhruvJoshi; 31.05.2018

Попробуйте это

DECLARE @idtype1 int, @idtype2 int

DECLARE type_cursor CURSOR FOR   
SELECT a.ID as ID_TYPE_1, b.ID as ID_TYPE_2  
FROM (SELECT ID, ROW_NUMBER() OVER(ORDER BY_ID) AS RN
    FROM TABLE WHERE TYPE = 1) a
INNER JOIN (SELECT ID, ROW_NUMBER() OVER(ORDER BY_ID) AS RN
        FROM TABLE WHERE TYPE = 2) b
    ON a.RN = b.RN

OPEN type_cursor  

FETCH NEXT FROM type_cursor   
INTO @idtype1, @idtype2  

WHILE @@FETCH_STATUS = 0  
BEGIN  
    DELETE FROM TABLE WHERE ID BETWEEN @idtype1 AND @idtype2

END
person Alfin E. R.    schedule 31.05.2018
comment
@Alfin-e-r с cursor занимает очень много времени. я хочу более быстрое решение, пожалуйста - person mhsankar; 31.05.2018
comment
До сих пор я мог только думать, что курсор - лучший способ сделать это, потому что его выполнение основано на строке, которая требует выборки строк, чтобы получить параметр между каким идентификатором и каким идентификатором, который затем должен быть применен к условию удаления - person Alfin E. R.; 31.05.2018
comment
@АльфинЭ.Р. В сообществе SQL часто используется термин RBAR[red-gate.com/simple-talk/sql/t-sql-programming/. Основная идея операций SQL должна заключаться в том, чтобы избегать циклов и выполнять работу, используя подход, основанный на наборах. - person DhruvJoshi; 31.05.2018

Сначала вам нужно определить границы того, что вы хотите удалить:

SELECT
    T1.id as StartId,
    (SELECT MIN(T2.id) from @tb1 T2 WHERE T1.id < T2.id and T2.typ = 2) as EndId
from @tb1 T1
WHERE T1.typ = 1

Результат:

StartId  EndId
1        3
5        6
9        13
15       NULL

Затем вы можете использовать этот запрос в CTE (Common Table Expression) для фактического удаления:

DECLARE @tb1 AS TABLE (id INT, typ int)
INSERT INTO @tb1 (id, typ)
       VALUES (1,1),(2,3),(3,2),(4,3),(5,1),(6,2),(7,3),(8,3),(9,1),(10,3),(11,3),(12,3),(13,2),(14,3),(15,1)

;WITH ranges AS (
    SELECT
        T1.id as StartId,
        (SELECT MIN(T2.id) from @tb1 T2 WHERE T1.id < T2.id and T2.typ = 2) as EndId
    FROM @tb1 T1
    WHERE T1.typ = 1
)
DELETE T3
FROM @tb1 T3
INNER JOIN ranges ON T3.id > ranges.StartId and T3.id < ranges.EndId

SELECT * FROM @tb1
person Peter B    schedule 31.05.2018

этот запрос должен работать

delete from @tb1 where id < 13 and id > 9

удалить, где тип находится между 10 и 12 [включая границы]

person DDS    schedule 31.05.2018
comment
у меня есть тип 1, 2 и 3 - как установить где с типом 13 и 10? - person mhsankar; 31.05.2018
comment
поэтому, пожалуйста, улучшите свой вопрос, из вашего вывода я могу понять, что вы удалили идентификатор между 9 и 13 - person DDS; 31.05.2018
comment
Я хочу удалить все строки между типами 1 и 2. ты понял мой вопрос? - person mhsankar; 31.05.2018
comment
«между» не существует в строках SQL, каждая строка может находиться в «случайной» позиции из-за плана выполнения запроса. вам нужно найти условие по значениям - person DDS; 31.05.2018
comment
строки между типами 1,2 — например, удалить строки с идентификатором 2 — потому что строки до этого имеют тип 1, а после — тип 2. - person mhsankar; 31.05.2018