Ismétlődő sorok megkeresése az SQL használatával

Ez a cikk bemutatja, hogyan lehet megkeresni a duplikált sorokat az adatbázis-táblában. Ez egy nagyon gyakori kezdő kérdés. Az alapvető technika egyszerű. Bemutatok néhány variációt is, például a “duplikátumok két oszlopban” megkeresését (nemrégiben feltett kérdés a #mysql IRC csatornán).

Hogyan lehet megkeresni az ismétlődő sorokat

Az első lépés annak meghatározása, hogy pontosan mi teszi a sort egy másik sor duplikátumává. Legtöbbször ez egyszerű: ugyanazon értékkel rendelkeznek egyes oszlopokban. Ezt a cikk működő definíciójának tekintem, de lehet, hogy módosítania kell az alábbi lekérdezéseket, ha a “duplikátum” fogalma bonyolultabb.

Ebben a cikkben a következő mintaadatokat fogom használni:

Az első két sor megegyezik érték a day oszlopban, tehát ha ezeket duplikátumoknak tekintem, itt talál egy lekérdezést. A lekérdezés egy GROUP BY záradékot használ arra, hogy az összes sor azonos day értékkel egy “csoportba” kerüljön, majd megszámolja a csoport:

A duplikált sorok száma nagyobb, mint egy. Ha csak duplikált sorokat szeretne látni, akkor használnia kell egy HAVING záradék (nem egy WHERE záradék), így:

Ez az alapvető technika: csoportosítson a duplikátumokat tartalmazó oszlop szerint, és csak azokat a csoportokat jelenítse meg, amelyeknek egynél több sora van.

Miért nem használhatja a WHERE záradékot?

A A WHERE záradék kiszűri a sorokat, mielőtt csoportosulna. A HAVING záradék csoportosítás után szűri őket. Ezért nem használhat WHERE záradék a fenti lekérdezésben.

Ismétlődő sorok törlése

Kapcsolódó kérdés, hogy miként lehet törölni a ‘duplikált’ sorokat megtalálja őket.Egy közös t Ha a hibás adatok megtisztításakor megkérdezzük, az összes másolat kivételével töröljük az összes másolatot, így megfelelő indexeket és elsődleges kulcsokat tehetünk az asztalra, és megakadályozzuk, hogy az ismétlődések ismét bekerüljenek a táblába.

Ismét az első meg kell győződnie arról, hogy a definíciója világos. Pontosan melyik sort szeretné megtartani? Az első? Valamelyik oszlop legnagyobb értéke? Ennél a cikknél feltételezem, hogy meg akarja tartani az „első” sort – azt, amelyik a id oszlop legkisebb értékével rendelkezik. Ez azt jelenti, hogy minden más sort törölni szeretne.

Valószínűleg a legegyszerűbb módja ennek egy ideiglenes tábla. Különösen a MySQL-ben vannak bizonyos korlátozások a táblából történő kiválasztáshoz és annak frissítéséhez ugyanabban a lekérdezésben. Megkerülheti ezeket, amint azt elmagyarázom a Hogyan válasszon egy frissítési célból a MySQL-ben című cikkemben, de csak elkerülöm ezeket a bonyodalmakat, és ideiglenes táblázatot használok.

A feladat pontos meghatározása: minden olyan sor törlése, amely rendelkezik duplikátummal, kivéve azt a sort, amelynek minimális értéke id az adott csoporthoz. Tehát nemcsak azokat a sorokat kell megtalálnia, ahol egynél több van a csoportban, hanem meg kell találnia azt a sort is, amelyet meg akar tartani. Ezt a MIN() függvénnyel teheti meg. Íme néhány lekérdezés az ideiglenes tábla létrehozásához és a DELETE elvégzéséhez szükséges adatok megkereséséhez:

Most, hogy rendelkezik ezekkel az adatokkal, folytathatja a törlést a „rossz” sorok. Ennek sokféle módja van, és némelyik jobb, mint a többi (lásd cikkemet az SQL sok minden problémájáról), de ismét elkerülöm a finomabb pontokat, és csak megmutatok egy szabványos szintaxist, amelyben működnie kell bármely RDBMS, amely támogatja az alkérdezéseket:

Ha az RDBMS nem támogatja az alkérdezéseket, vagy ha ez hatékonyabb, akkor érdemes több táblázatot törölni. Ennek szintaxisa rendszerenként változó, ezért meg kell vizsgálnia a rendszer dokumentációját. Lehetséges, hogy mindezt egy tranzakció során is meg kell tennie, hogy elkerülje a többi felhasználó adatainak megváltoztatását munka közben, ha ez aggodalomra ad okot.

Hogyan találhatunk meg duplikátumokat több oszlopban

Valaki nemrég tett egy ehhez hasonló kérdést a #mysql IRC csatornán:

Van egy táblázatom oszlopokkal b és c, amelyek összekapcsolnak két másik táblázatot b és c, és szeretném az összes olyan sor megkeresése, amelynek duplikációja van a b vagy a c.

Nehéz volt megérteni, hogy ez pontosan mit jelent, de némi beszélgetés után megértettem: az illető egyedi indexeket akart felvenni a b és a c külön.

Nagyon egyszerű az egyik vagy a másik oszlopban duplikált értékeket tartalmazó sorokat találni, amint azt fentebb bemutattam: csak csoportosítson az adott oszlop alapján mn és számolja meg a csoport méretét. És könnyű megtalálni a teljes sorokat, amelyek pontosan másolatai a többi sornak: csak annyi oszlop szerint csoportosítson, amennyire szüksége van.De nehezebb azonosítani azokat a sorokat, amelyek vagy duplikált b vagy duplikált c értékkel rendelkeznek. Vegyük a következő mintatáblát, amelyet nagyjából az adott személy írt le:

Most már könnyen láthatja, hogy ebben a táblázatban vannak „duplikált” sorok, de valójában nincs két sor ugyanaz a duplával {b, c}. Ezért ezt egy kicsit nehezebb megoldani.

Nem működő lekérdezések

Ha két oszlop szerint csoportosít, akkor a csoportosítás módjától függően különféle eredményeket kap. és számolj. Itt tapadt az IRC felhasználó. Néha a lekérdezések másolatokat találtak, de másokat nem. Íme néhány dolog, amit ez a személy kipróbált:

Ez a lekérdezés a táblázat minden sorát visszaadja COUNT(*) of 1, ami téves viselkedésnek tűnik, de valójában nem az. Miért? Mivel a > 1 benne van a COUNT(). Elég könnyű kihagyni, de ez a lekérdezés valójában megegyezik a

Miért? Mivel az (b > 1) logikai kifejezés. Egyáltalán nem ezt akarja. Szeretne

Ez természetesen nulla sort ad vissza, mert nincsenek ismétlődő {b, c} sorok. A személy kipróbálta a HAVING záradékok, valamint az OR és AND sok más kombinációját, az egyik oszlop szerint csoportosítva, a másikat megszámolva stb.:

Semmi sem találta meg az összes másolatot. Szerintem az okozta a legnagyobb frusztráltságot, hogy részben működött, és arra késztette az embert, hogy majdnem megfelelő lekérdezés legyen … talán csak egy másik változat érné el …

Valójában lehetetlen megtenni az ilyen típusú lekérdezéseket egyszerű GROUP BY lekérdezés. Miért ez? Ez azért van, mert amikor egy oszlop szerint csoportosít, akkor a másik oszlop értékeit több csoportra osztja szét. Ezt vizuálisan láthatja az oszlopok szerinti sorrendben, ezt teszi a csoportosítás. Először a b oszlop szerint rendezze, és nézze meg, hogyan vannak csoportosítva:

a b c
7 1 1
8 1 2
9 1 3
10 2 1
11 2 2
12 2 3
13 3 1
14 3 2
15 3 3

Amikor b oszlop szerint rendel (csoportosít), az c különböző csoportokba vannak osztva, ezért nem számolhatja őket COUNT(DISTINCT c) vel, ahogy az illető megpróbálta. Az olyan összesített függvények, mint a COUNT(), csak egy csoporton belül működnek, és nem férnek hozzá más csoportokba sorolt sorokhoz. Hasonlóképpen, amikor c alapján rendel, az b oszlopban található duplikált értékek különböző csoportokba kerülnek. Ezt a lekérdezést nem lehet a kívánt módon megtenni.

Néhány helyes megoldás

Valószínűleg a legegyszerűbb megoldás az, ha az oszlopok duplikátjait külön és UNION őket együtt, így:

A kimenet what_col oszlopa jelzi, hogy a duplikált érték melyik oszlopban található. Egy másik megközelítés a alkérdezések:

Ez valószínűleg sokkal kevésbé hatékony, mint a UNION megközelítés, és minden duplikált sort megjelenít, nem csak a duplikált értékeket. Egy másik megközelítés az, hogy öncsatlakozásokat kell végrehajtani a csoportosított lekérdezésekkel szemben a FROM záradékban. Ennek bonyolultabb a helyes írása, de szükség lehet néhány összetett adat vagy hatékonyság érdekében:

A lekérdezések bármelyike megfelel, és biztos vagyok benne, hogy vannak más módszerek is. Ha használhatja a UNION alkalmazást, akkor valószínűleg ez a legegyszerűbb.

Write a Comment

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük