Sziasztok!
Napi szinten használok SQL-t (esetemben MariaDB), de van egy query, ami feladta a leckét, lényegében elképzelésem sincs, hogy hogy nézne ez ki. Viszont számomra nagyon-nagyon hasznos lenne.
Van egy táblám amelyből jelen esetben 3 oszlop a lényeg: GROUP, PREFIX, VALUE.
Csoportonként (GROUP érték) szeretném törölni azokat a rekordokat, ahol a prefix hosszabb egy nála rövidebb de azonos értéűvel definiáltnál, viszont a VALUE értéke megegyezik.
Pl.:
group1 a123 1.2
group1 a1234 1.2 <-ez nem kell mert a rövidebben definiáltnál is ennyi a VALUE
group1 a1235 1.4
group2 a1234 1.6
group2 a12345 1.6 <-ez nem kell mert a rövidebben definiáltnál is ennyi a VALUE
És mindezt csoportonként.
Ez a DELETE query valahogy nem áll össze a fejemben.
Hogy kellene ennek nagyjából kinéznie?
A válaszaitokat előre is köszönöm!
- 581 megtekintés
Hozzászólások
Hát, szerintem erre találták ki a PL/SQL-t, vélhetően extra programozás nélkül ezt csak SQL-ből nem tudod megoldani...
Alapvetően group és value szerint kellene group-ot képezni és a prefix-et sorba rendezni hossz szerint, majd az elsőt leszámítva törölni. Nem tűnik olyan komplexnek PL/SQL tárolt eljárásként.
- A hozzászóláshoz be kell jelentkezni
Nekem már az is jó, ha GROUP értékenként futtatok egy query-t, tehát ahol a WHERE-ben benne van, hogy GROUP=xyz. Ha az úgy megoldható. PHP-val összeszedem másik táblából a group-okat és egyenként mindegyikre lefuttatom, míg a végére nem érek.
- A hozzászóláshoz be kell jelentkezni
PHP is jó, ha van. Ilyesmi elvileg:
select `group`,`value` from `valamitábla` group by `group`,`value`;
Erre fogsz kapni egy listát, hogy milyen group-value párok vannak, azokon végig tudsz iterálni:
select `prefix` from `valamitábla` where `group`= ... and `value` = ...;
Aztán ha itt több sort kapsz vissza, akkor a logikád alapján már tudod törölni a felesleget.
- A hozzászóláshoz be kell jelentkezni
Köszi, de ezzel annyi a bibi, hogy túl sok lehetséges értéke van a value-nak.
- A hozzászóláshoz be kell jelentkezni
Populáld össze PHP-ból a value értékét, és
SELECT .... FROM ... WHERE value IN(1,2,3,4,5,6);
- A hozzászóláshoz be kell jelentkezni
"ezt csak SQL-ből nem tudod megoldani"
```
DELETE FROM table t1
WHERE EXISTS (
SELECT 1 FROM table t2
WHERE t1.group = t2.group and t1.value = t2.value and LEFT(t1.prefix, LENGTH(t2.prefix)) = t2.prefix) and LENGTH(t2.prefix) < LENGTH(t1.prefix)
);
```
- A hozzászóláshoz be kell jelentkezni
Kérdés, hogy milyen a prefix szabályrendszere, a fenti példára jó a length, de ha "értelmezni" is kell, akkor instr()-es a móka.
Gyakorlatilag group+value alapján újra kell csoportosítani és kiválasztani a min_prefix értéket, utána meg mehet egy sima WHERE ahol a prefix <> min_prefix
"The only valid measurement of code quality: WTFs/min"
- A hozzászóláshoz be kell jelentkezni
Ha ertemlezni kell majd elmondja,
... ha valamit nem lehet megcsinalni SQL-ben, azt nem lehet megcsinalni gyanus :)
A masodik mondat meg meginkabb ertelmezhetetlen mert ki mondta, hogy csak 1 prefix letezhet?
- A hozzászóláshoz be kell jelentkezni
kb erre gondoltam: https://www.db-fiddle.com/f/exwyNdjGcWhU9KNy1LxyBU/0
SELECT
t2.*
FROM
(
SELECT
t1.*,
LENGTH(t1.prefix) pfx_length
FROM
t1
) t2,
(
SELECT
t1.grp,
t1.val,
MIN(LENGTH(t1.prefix)) min_pfx_length
FROM
t1
GROUP BY grp,val
) t3
WHERE
t2.grp = t3.grp
AND t2.val = t3.val
AND t2.pfx_length <> t3.min_pfx_length
;
Delete-re nem alakítottam át, meg lehet szépíteni ízlés szerint :)
"The only valid measurement of code quality: WTFs/min"
- A hozzászóláshoz be kell jelentkezni
Valamiért szintaktikai hibát mond rá. Azt észrevettem, hogy becsúszott egy véletlen zárójel az "= t2.prefix" után, amit ki is is szedtem, de mást én nem látok és nem eszi meg.
- A hozzászóláshoz be kell jelentkezni
mit ir? valoszinuleg csak a group oszlop nevet kell idezojelbe rakni.
a postgres-ben gond nelkul lefut:
```
CREATE TABLE hup AS
select "group", "prefix","value" from (values
('group1', 'a123', '1.2'), ('group1', 'a1234', '1.2'), ('group1', 'a1235', '1.4'),('group2', 'a1234', '1.6'),('group2', 'a12345', '1.6')) as mytable("group", "prefix","value" );
DELETE FROM hup t1
WHERE EXISTS (SELECT 1 FROM hup t2 WHERE t1."group" = t2."group" and t1.value = t2.value and LEFT(t1.prefix, LENGTH(t2.prefix)) = t2.prefix and LENGTH(t2.prefix) < LENGTH(t1.prefix));
```
- A hozzászóláshoz be kell jelentkezni
1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'as t1
WHERE
EXISTS (
SELECT
1
FROM
hup as t2
WHERE
...
- A hozzászóláshoz be kell jelentkezni
Lehet igy kell irni mariadb-ben:
DELETE t1 FROM hup t1
- A hozzászóláshoz be kell jelentkezni
Köszönöm, a syntax kérdést megoldotta, ellenben úgy néz ki, ez a megoldás a MariaDB-nek nem tetszik:
1093 - Table 't1' is specified twice, both as a target for 'DELETE' and as a separate source for data, Time: 0.062000s
Viszont egy duplikált táblával kipróbálom, mert már ez nagyon nagy könnyítés a táblán. MÉg fut a query, ez el fog tartani egy darabig.
UPDATE:
Közben rájöttem, hogy hülye vagyok, mert még egy alcsoport szerint is külön kell szednem őket, de szerencsére a fenti query struktúrája egy sima "and t1.sub_group=t2.sub_group"-pal ezt lehetővé teszi.
Köszönöm.
- A hozzászóláshoz be kell jelentkezni
Igy mar mukodik:
DELETE t1 FROM hup t1
INNER JOIN (SELECT * FROM hup) t2
ON t1.group = t2.group and t1.value = t2.value and LEFT(t1.prefix, LENGTH(t2.prefix)) = t2.prefix and LENGTH(t2.prefix) < LENGTH(t1.prefix);
- A hozzászóláshoz be kell jelentkezni
Joinold a táblát önmagához. Ha jól értem, value szerinti egyezést keresel, és minden sorhoz kapcsold hozzá a nála rövidebb prefixeit. Ezt lapátold be egy subquery-be és aszerint törölj.
- A hozzászóláshoz be kell jelentkezni
Remélem értem a feladatot. Nem teszteltem. fejből írom. nem biztos, hogy megy (sőt!) a logika remélem átmegy:
SELECT t1.GROUP, t1.PREFIX, t1.VALUE FROM táblád AS t1
WHERE (SELECT t2.PREFIX FROM táblád AS t2 WHERE t2.prefix = substring(t1.prefix,0, length((t1.prefix)-1) LIMIT 1)
- A hozzászóláshoz be kell jelentkezni
ezt jobb volna /* */ koze rakni
- A hozzászóláshoz be kell jelentkezni
delete from table
where exist (
select 1
from table t
join (select group, value, min(len(prefix)) lprfx
from table
group by group, value ) p
on t.group = p.group
and t.value = p.value
and len(t.prefix)> p. lprfx
)
ha tobb azonos min. hosszu prefix van meghagyja mindet. (nem tesztteltem, fejbol irtam)
- A hozzászóláshoz be kell jelentkezni
delete from table
where concat(group,prefix,value) not in
(select gpv
from ( select concat(group,prefix,value) gpv
, row_number() over (partition by group,value order by len(prefix )) rn
from table
) x
where rn = 1
)
Nullokkal vigyazni!
- A hozzászóláshoz be kell jelentkezni
Ezek az értékek soha nem nullok. Viszont ezt a query-t nem értem. Nem tudom mi lenne ott az a gpv, meg az rn. Illetve bocsánat, az leesett hogy az a 3 oszlop rövidítése, csak nem látom át, hogy mit keres ott, ahol ott van. A len() alapján ez nekem MSSQL-nek tűnik.
- A hozzászóláshoz be kell jelentkezni
fejbol irtam.
len -> length nyilvan :)
szerintem mukodnie kell MSSQLben is:
- nem sok RDBMS erti a:
(x,y,z) in (select a,b,c from table)
format.
ezert fuztem ossze az oszlopokat concat(group,prefix,value) sima left joinra is lehene cserelni...
he lefuttadod reszenkent:
- x: sorszamozza (rn) a sorokat prefix hossz szerint novekvobe a group ,value csoprtokra.
- where rn = 1 kiveszi az 1-es sorszamut, ha tobb van azonnos hosszal az egyiket! (ha mindet meg akarod hagyni :a row_numbert cserled RANK -ra)
- concat(group,prefix,value) not in : minden sort kivalszt torlesre ami nincs a gpv selectben.
Igy?
- A hozzászóláshoz be kell jelentkezni
Értem a koncepciót. MariaDB-re ezt még egy kicsit reszelgetnem kell.
Kipróbálom ezt is. Köszönöm.
- A hozzászóláshoz be kell jelentkezni
Nagyon köszönöm mindenkinek a hozzászólásokat. A tábla megtisztult! :)
- A hozzászóláshoz be kell jelentkezni