Трудно удалить. Как мне?

80
11

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


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


UPDATE
sql server 2k5
значения первого столбца - есть уникальный, но не ID-s (это не ++: 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

спросил(а) 2010-11-16T19:42:00+03:00 10 лет, 11 месяцев назад
1
Решение
79

Если я правильно понял, вы хотите сохранить все записи с 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)
)

Edit:
t4.col1 < t3.col1 должно быть t4.col1 > t3.col1

Я создал тестовую таблицу с col1 и col2, оба int, col1 - PK, но не autonumber


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

ответил(а) 2010-11-16T19:56:00+03:00 10 лет, 11 месяцев назад
80

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


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

ответил(а) 2010-11-16T19:48:00+03:00 10 лет, 11 месяцев назад
46

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


для этого я создал таблицу ниже:
create table t1 (val int, val2 int)
GO


- ниже точная stmt:


С CTE as (выберите val, val2, row_number() over (order by val ASC) как rnum
из t1)
DELETE t1
Из t1 внутреннего соединения cte a
ON t1.val = a.val INNER JOIN (SELECT * fROM cte, где val2 = -1) в виде b
на a.rnum = b.rnum
или a.rnum = b.rnum - 1
или a.rnum = b.rnum + 1


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

ответил(а) 2010-11-17T15:05:00+03:00 10 лет, 11 месяцев назад
46

Решение состоит в том, чтобы сначала записать записи, идентифицировать те, которые смежны с правилами -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
)

ответил(а) 2010-11-17T13:53:00+03:00 10 лет, 11 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема