SQL Удалить низкие показатели - PullRequest
2 голосов
/ 20 сентября 2009

У меня есть таблица с этими данными:

Id     Qty  
--     ---  
A       1  
A       2  
A       3  
B       112  
B       125  
B       109  

Но я должен иметь только максимальные значения для каждого идентификатора. Максимальное значение для A - 3, а для B - 125. Как выделить (и удалить) другие значения?

Финальный стол должен выглядеть так:

Id     Qty  
--     ---   
A       3  
B       125  

Запуск MySQL 4.1

Ответы [ 5 ]

2 голосов
/ 20 сентября 2009

Ой, подождите. Получил более простое решение: Я выберу все максимальные значения (сгруппированные по идентификатору), экспортирую данные, очисту таблицу, повторно импортирую только максимальные значения.

CREATE TABLE tabletemp LIKE table;  
INSERT INTO tabletemp SELECT id,MAX(qty) FROM table GROUP BY id;  
DROP TABLE table;
RENAME TABLE tabletemp TO table; 

Спасибо всем!

1 голос
/ 20 сентября 2009

Попробуйте это в SQL Server:

delete from tbl o
left outer join 
(Select max(qty) anz , id
from tbl i
group by i.id) k on o.id = k.id and k.anz = o.qty
where k.id is null

Редакция 2 для MySQL ... Кто-нибудь может проверить это?

delete from tbl o
where concat(id,qty) not in 
    (select concat(id,anz) from (Select max(qty) anz , id
    from tbl i
    group by i.id)) 

Пояснение:

Поскольку я должен был не использовать объединения (см. Комментарии о поддержке MySQL по соединениям и удалению / обновлению / вставке), я переместил подзапрос в предложение IN (a, b, c).

Внутри предложения In я могу использовать подзапрос, но этот запрос может возвращать только одно поле. Таким образом, чтобы отфильтровать все элементы, которые не являются максимальными, мне нужно объединить оба поля в одно, чтобы я мог вернуть его внутри предложения in. Так что в основном мой запрос внутри IN возвращает только самый большой ID + QTY. Чтобы сравнить его с основной таблицей, мне также нужно составить конкатец снаружи, чтобы данные для обоих полей совпадали.

В основном предложение In содержит: ( "A3", "B125")

Отказ от ответственности: приведенный выше запрос "зло!" так как он использует функцию (concat) для полей для сравнения. Это приведет к тому, что любой индекс в этих полях станет практически бесполезным. Никогда не следует формулировать запрос таким образом, чтобы он выполнялся регулярно. Я только хотел попытаться согнуть его, чтобы он работал на MySQL.

Пример этой "плохой конструкции": (Получить все o за последние 2 недели) выберите ... из заказов, где orderday + 14> now ()

Вы всегда должны делать: выберите ... из заказов, где orderday> now () - 14

Разница едва заметна: версия 2 должна выполнять математику только один раз и может использовать индекс, а версия 1 должна выполнять математику для каждой строки в таблице заказов. Вы можете забыть о использование индекса ...

0 голосов
/ 21 сентября 2009

Вам придется пройти через другую таблицу (среди прочего, что делает единственное утверждение удаления здесь совершенно невозможным в mysql, если вы не можете удалить из таблицы и использовать эту же таблицу в подзапросе).

BEGIN;
create temporary table tmp_del select id,max(qty) as qty from the_tbl;
delete the_tbl from the_tbl,tmp_del where 
  the_tbl.id=tmp_del.id and the_tbl.qty=tmp_del.qty;
drop table tmp_del;
END;
0 голосов
/ 20 сентября 2009

Я бы попробовал это:

delete from T
where exists (
  select * from T as T2
  where T2.Id = T.Id
  and T2.Qty > T.Qty
);

Для тех, у кого могут возникнуть подобные вопросы в будущем, это может быть когда-нибудь поддержано (теперь это в SQL Server 2005 и более поздних версиях)

Это не потребует объединения, и имеет преимущества перед использованием временной таблицы, если таблица имеет зависимости

with Tranked(Id,Qty,rk) as (
  select
    Id, Qty,
    rank() over (
      partition by Id
      order by Qty desc
    )
  from T
)
  delete from Tranked
  where rk > 1;
0 голосов
/ 20 сентября 2009

MySQL 4.0 и более поздних версий поддерживает простой синтаксис для нескольких таблиц для DELETE:

DELETE t1 FROM MyTable t1 JOIN MyTable t2 ON t1.id = t2.id AND t1.qty < t2.qty;

Создает объединение каждой строки с заданным идентификатором для всех других строк с таким же идентификатором и удаляет только строку с меньшим qty в каждой паре. После того, как все это сделано, строка с наибольшим значением qty для группы id остается не удаленной.

Если у вас есть только одна строка с данным идентификатором, она все равно работает, потому что, естественно, одна строка - это та, которая имеет наибольшее значение.


FWIW, я только что попробовал свое решение, используя MySQL 5.0.75 на Macbook Pro 2,40 ГГц. Я вставил 1 миллион строк синтетических данных с разным количеством строк на «группу»:

  • 2 строки за id завершается за 26,78 с.
  • 5 строк на id завершается за 43,18 с.
  • 10 строк на id завершается за 1 мин. 3,77 сек.
  • 100 строк на id завершается за 6 мин 46,60 сек.
  • 1000 строк на id не было завершено, пока я не завершил его.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...