Zdarza się, że chcemy w tabeli usunąć duplikaty. Przemilczmy powód, dla którego nie powinny się one tam znaleźć. Natomiast innym powodem, o którym możemy mówić, może być sytuacja gdy po prostu z jakiegoś źródła dostajemy takie dane (przychodzą z urządzenia rejestrującego lub importujemy dane zewnętrzne).
Dajmy za przykład tabelę gdzie przechowujemy temperatury z danego dnia. Ale urządzenie odczytujące temperaturę i zapisujące do bazy danych robi to w ciągu doby kilkukrotnie.
id | dzien | temperatura |
---|---|---|
1 | 2017-10-15 | 10 |
2 | 2017-10-16 | 11 |
3 | 2017-10-16 | 12.5 |
4 | 2017-10-16 | 11.7 |
5 | 2017-10-17 | 13 |
6 | 2017-10-17 | 13.2 |
7 | 2017-10-17 | 12.8 |
Chcemy pozostawić tylko pierwszą zarejestrowaną temperaturę w danym dniu.
Jak wyprosić niechciane rekordy w tym przypadku?
Musimy znaleźć sposób, aby pozostawić rekordy o id: 1, 2, 5. Na nic tu się zda grupowanie i funkcja MIN. Z pomocą przyjdzie nam CROSS JOIN (iloczyn kartezjański). Czyli musimy każdy rekord tabeli połączyć z każdym, ale jakoś go (iloczyn) ograniczyć aby wybrać wspomniane rekordy. Jeśli czytałeś ten wpis, to może kojarzysz tą metodę, a jeśli nie, to zapytanie będzie wyglądać tak:
SELECT * FROM tabela AS t1, tabela AS t2
WHERE t1.id>t2.id AND t1.dzien=t2.dzien
Póki co jest to zapytanie wybierające, a nie usuwające, ale łatwiej będzie Ci w ten sposób zrozumieć zasadę działania docelowego zapytania. Sprzegając tabelę ze sobą poprzez id (właśnie! to pole musi istnieć i posiadać wzrastającą numerację) z warunkiem nierówności ostrej spowodujemy, że wybrana zostanie część rekordów (pamiętaj, że łączenie rekordów ograniczymy w ramach dnia - drugi warunek w klauzuli WHERE):
t1.id | t2.id | t1.id>t2.id |
---|---|---|
1 | 1 | 1>1=0 |
2 | 2 | 2>2=0 |
2 | 3 | 2>3=0 |
2 | 4 | 2>4=0 |
3 | 2 | 3>2=1 |
3 | 3 | 3>3=0 |
3 | 4 | 3>4=0 |
4 | 2 | 4>2=1 |
4 | 3 | 4>3=1 |
4 | 4 | 4>4=0 |
5 | 5 | 5>5=0 |
5 | 6 | 5>6=0 |
5 | 7 | 5>7=0 |
6 | 5 | 6>5=1 |
6 | 6 | 6>6=0 |
6 | 7 | 6>7=0 |
7 | 5 | 7>5=1 |
7 | 6 | 7>6=1 |
7 | 7 | 7>7=0 |
Choć jedno id dla którego spełniony jest warunek zostanie wybrane. A które nie zostaną? Oczywiście 1, 2 oraz 5!
Wystarczy teraz przekształcić nasz SELECT w DELETE i pozbędziemy się wszystkich rekordów w danym dniu oprócz najstarszego.
DELETE FROM tabela AS t1, tabela AS t2
WHERE t1.id>t2.id AND t1.dzien=t2.dzien
A jak pozostawić najnowszy rekord w danym dniu? Odwrócić warunek.
DELETE FROM tabela AS t1, tabela AS t2
WHERE t1.id<t2.id AND t1.dzien=t2.dzien
Pamiętaj aby zrobić backup danych przed usuwaniem złego bliźniaka, aby przez przypadek nie usunąć jego dobrych braci.
Przydatne linki:
Przydzielanie rekordów do przedziałów.