Хитро удалить.Как я? - PullRequest
       15

Хитро удалить.Как я?

2 голосов
/ 16 ноября 2010

Я получил таблицу с 2 столбцами (оба INT), и там 400 000 записей (много).Первый столбец случайных чисел упорядочен ASC.Во втором столбце есть правило (которое сейчас не важно). В таблице есть 1000 записей, которые являются исключениями.Таким образом, вместо «правила» есть только «-1» -значные ячейки.

Как я могу удалить ~ 399 000 записей, поэтому я хочу, чтобы в моей таблице остались только те, у которых -1и их "соседи" (записи до и после записей с -1)

ОБНОВЛЕНИЕ sql server 2k5 значения первого столбца - да, уникальные, но не идентификаторы (это не ++: D)

пример:

до:

 20022518   13
 20022882   364
 20022885   -1
 20022887   5
 20022905   18
 20023200   295
 20023412   212
 20023696   284
 20024112   416
 20025015   903
 20025400   385
 20025401   -1
 20025683   283
 20025981   298
 20025989   8
 20026752   763
 20027779   1027
 20028344   565
 20028350   6
 20028896   546
 20028921   25
 20028924   -1
 20028998   77
 20029031   33
 20029051   20
 20029492   441
 20029530   38
 20029890   360

после:

 20022882   364
 20022885   -1
 20022887   5
 20025400   385
 20025401   -1
 20025683   283
 20028921   25
 20028924   -1
 20028998   77

Ответы [ 4 ]

2 голосов
/ 16 ноября 2010

Если я правильно понимаю, вы хотите сохранить все записи с col2 = -1 и записи с ближайшим col1 к записям с -1.Если предположить, что в столбце col1 нет дубликатов, я бы сделал что-то вроде этого

delete from table where not col1 in 
(
    (select col1 from table where col2 = -1)
union
    (select (select max(t2.col1) from table t2 where t2.col1 < t1.col1) from table t1 where t1.col2 = -1)
union
    (select (select min(t4.col1) from table t4 where t4.col1 > t3.col1) from table t3 where t3.col2 = -1)
)

Изменить:
t4.col1 < t3.col1 должно быть t4.col1 > t3.col1
Я создал тестовую таблицу с col1и col2, оба типа int, col1 - это PK, но не автонумера

SELECT * from adjacent

Дает

col1    col2
1   5
3   4
4   2
7   -1
11  8
12  2

С указанными выше подвыборками:

SELECT * from adjacent
where
col1 in 
(
    (select col1 from adjacent where col2 = -1)
union
    (select (select max(t2.col1) from adjacent t2 where t2.col1 < t1.col1) from adjacent t1 where t1.col2 = -1)
union
    (select (select min(t4.col1) from adjacent t4 where t4.col1 > t3.col1) from adjacent t3 where t3.col2 = -1)
)

дает

col1    col2
4   2
7   -1
11  8

С not также

SELECT * from adjacent
where
col1 not in 
(
    (select col1 from adjacent where col2 = -1)
union
    (select (select max(t2.col1) from adjacent t2 where t2.col1 < t1.col1) from adjacent t1 where t1.col2 = -1)
union
    (select (select min(t4.col1) from adjacent t4 where t4.col1 > t3.col1) from adjacent t3 where t3.col2 = -1)
)

дает

col1    col2
1   5
3   4
12  2

Наконец, удаление и выберите

delete from adjacent
where
col1 not in 
(
    (select col1 from adjacent where col2 = -1)
union
    (select (select max(t2.col1) from adjacent t2 where t2.col1 < t1.col1) from adjacent t1 where t1.col2 = -1)
union
    (select (select min(t4.col1) from adjacent t4 where t4.col1 > t3.col1) from adjacent t3 where t3.col2 = -1)
)

select * from adjacent

дает

col1    col2
4   2
7   -1
11  8
2 голосов
/ 16 ноября 2010

Предполагая, что SQL Server здесь. Лучше всего, если вы храните очень маленький набор данных, это вставить его в новую таблицу. I.E.:

SELECT *
INTO MyTable2
FROM MyTable
WHERE ColumnB = -1

DROP TABLE MyTable

exec sp_rename MyTable2 MyTable

Это будет минимально зарегистрированная операция, которая будет выполняться за долю времени DELETE.

Без другого ключа невозможно гарантировать, что вы получите «соседей», так как это не совсем верная концепция в реляционной БД. Если первый столбец является «случайным», вы не можете сказать, какие из них «до» и «после» строки со значением -1.

Если под "случайным" подразумевается столбец IDENTITY, который автоматически увеличивается, И У ВАС НЕТ пропущенных значений в ПОСЛЕДОВАТЕЛЬНОСТИ вы можете сделать что-то вроде:

SELECT *
INTO MyTable2
FROM MyTable mt
WHERE ColumnB = -1
OR WHERE EXISTS (
     SELECT * FROM MyTable mt2
     WHERE mt2.id = mt.id + 1
     OR mt2.id = mt.id -1)

DROP TABLE MyTable

exec sp_rename MyTable2 MyTable
0 голосов
/ 17 ноября 2010

Используйте этот хитрый запрос:

для этого я создал таблицу с помощью оператора ниже: создать таблицу t1 (val int, val2 int) GO

- ниже указано точное значение:

С CTE as (выбрать val, val2, row_number () over (упорядочить по val ASC) в качестве rnum из т1) УДАЛИТЬ t1 Из t1 внутреннего соединения cte a ON t1.val = a.val ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБЕРИТЕ * ОТ Cte, где val2 = -1) как b на a.rnum = b.rnum или a.rnum = b.rnum - 1 или a.rnum = b.rnum + 1

Для получения дополнительной информации о CTE, пожалуйста, смотрите этот пост: http://blog.sqlauthority.com/2009/08/08/sql-server-multiple-cte-in-one-select-statement-query/

0 голосов
/ 17 ноября 2010

Решение состоит в том, чтобы сначала нумеровать записи, идентифицировать те, которые примыкают к правилам -1, а затем использовать UNION для получения окончательного результата:

WITH Numbered(seq, id, ruleno) AS (
 SELECT
  ROW_NUMBER() OVER (ORDER BY id), id, ruleno
 FROM
  Tricky
),
Brothers(id, ruleno) AS (
 SELECT
  b.id, b.ruleno
 FROM
  Numbered a INNER JOIN Numbered b
  ON a.ruleno = -1 AND
  abs(a.seq - b.seq) = 1
),
Triplets(id, ruleno) AS (
 SELECT
  id, ruleno
 FROM
  Tricky
 WHERE
  ruleno = -1
 UNION ALL
 SELECT
  id, ruleno
 FROM
  Brothers
)
-- Display results
SELECT 
 id, ruleno
FROM
 Triplets
ORDER BY
 id

Результат:

id ruleno
20022882 364
20022885 -1
20022887 5
20025400 385
20025401 -1
20025683 283
20028921 25
20028924 -1
20028998 77

Наконец:

DELETE FROM
  Tricky
WHERE
  id NOT IN (
    SELECT 
      id
    FROM
      triplets
  )
...