Hirdetés
- Redmi Pad 2 Pro / Poco Pad M1 - egy teszt, két lélek
- NVIDIA GeForce RTX 5070 / 5070 Ti (GB205 / 203)
- Épített vízhűtés (nem kompakt) topic
- Androidos tablet topic
- Kormányok / autós szimulátorok topikja
- Vezetékes FEJhallgatók
- Multimédiás / PC-s hangfalszettek (2.0, 2.1, 5.1)
- DUNE médialejátszók topicja
- AMD Ryzen 9 / 7 / 5 9***(X) "Zen 5" (AM5)
- NVIDIA GeForce RTX 5080 / 5090 (GB203 / 202)
Új hozzászólás Aktív témák
-
nyunyu
félisten
dupla
-
nyunyu
félisten
tripla

-
nyunyu
félisten
Egyáltalán a from után táblákat vesszővel felsorolós ősrégi szintaxist tanítják még valahol?
Mikor ~20 éve halogattam DB témájú tárgyakat a BMEn, akkor már csak a szabvány szintaxis Oracle és SQL Server implementációját mutogatták.
Legacy Teradata nyelvjárásba csak később futottam bele, amikor 10-15 éves ETL jobokat kellett visszafejtenem, és vizualizálnom.
-
nyunyu
félisten
Metszet nélküli az a left/right join is null-lal kombinálva.
select a.*
from tabla a
left join temp b
on b.id = a.id
where b.id is null;Ez szerintem ekvivalens ezzel:
select a.*
from temp b
right join tabla a
on a.id = b.id
where b.id is null;Ezeket a szörnyűségeket le se merem írni:
select a.*
from tabla a, temp b
where a.id = b.id (+)
and b.id is null;select a.*
from temp b, tabla a
where b.id (+) = a.id
and b.id is null;
-
nyunyu
félisten
Szerintem sok különbség nincs köztük, ha megfordítod a táblák sorrendjét, akkor right lesz a left-ből, és fordítva

Nekem olyan logikátlannak tűnik, hogy egy kicsi vagy lyukacsos táblához joinoljak egy nagyobbat / tömöret, így én sem szoktam right joint használni, helyette mindig nagy táblához left join.
-
nyunyu
félisten
Sosem szerettem az ősrégi szintaxist, mert nem bírtam megjegyezni, hogy az Oracle a feltétel melyik oldalán várja a (+)-t a left illetve right joinnál.
select t1.*, t2.*
from tabla1 t1, tabla2 t2
where t1.id = t2.id (+);Aha, amelyik oldal nem kötelező / lehet null, oda kell tenni a (+)-t.
Vagyis a fenti példa egy left join.Arra meg egyáltalán nem emlékszem, hogy Teradatában volt-e ilyen left/right szintaxis.
Csak annyi rémlik, hogy update közben is tudott implicit joinolni, amit rajta kívül egyik DB motor sem ismert:update tabla1
set valami = tabla2.valami
where id = tabla2.idSzabvány SQL mindenesetre jóval olvashatóbb, mint ezek az elfajzott példák.

-
nyunyu
félisten
Mondjuk join feltételnek megadod mindkét mezőt AND-dal?
SQL-92 szintaxis:
select t1.*
from tabla1 t1
join temp t2
on t2.valami = t1.valami
and t2.masikmezo = t1.masikmezo;Szabvány előtti ősrégi szintaxis:
select t1.*
from tabla1 t1, temp t2
where t2.valami = t1.valami
and t2.masikmezo = t1.masikmezo;Utóbbit csak a nagyon régi DB gyártók (Oracle, Teradata), illetve az újabbak közül csak páran (MS SQL 2008-tól, MySQL?) ismerik csak.
Nagyon nagy (100k+ rekord) tábla esetén sokat lehet gyorsítani rajta, ha legalább az egyik joinolt oszlopon van index.
(Esetleg partícionálod a táblát az egyik kulcs mentén, de az már nagyon advanced megoldás, és nem minden ócó/ingyenes DB motor tudja) -
nyunyu
félisten
Kezdésnek jó.
Ennek az értékét szorozd százzal, aztán oszd el a select count(*) from hitel where hitel.altipus='LAK' értékével.
select p.db*100/o.db pesti_szazalek
from
(select count(*) db
from hitel h
join ugyfel u
on u.ugyfel.kod = h.ugyfel.kod
where h.altipus = 'LAK'
and u.ugyfel.lakhely = 'Budapest') p
join
(select count(*) db
from hitel h
where h.altipus = 'LAK') o
on 1=1;Vagy akár egy menetben is lehet, ha egy alselectben strigulázod a hiteleket, és abból a pestieket, aztán a külsőben summázod őket, és számolod a százalékot:
select sum(pesti)*100/sum(db)
from (select 1 as db,
case when u.ugyfel_lakhely = 'Budapest'
then 1
else 0
end pesti
from hitel h
join ugyfel u
on u.ugyfel.kod = h.ugyfel.kod
where h.altipus = 'LAK'); -
nyunyu
félisten
válasz
martonx
#5335
üzenetére
2) pontban egyáltalán nem vagyok biztos.
Mostani banki GDPR projektemen kb. harmadannyian vagyunk, mint kéne, Üzlet meg csodálkozik, hogy miért tart annyi ideig a projekt, miért nem lesz idén se kész.
Csak hát a többi projektről elszállingózó emberek pótlása nagyobb prioritású.
Plusz közben szórakoztatják a fejlesztőcsapatot olyan derült égből vis majorokkal is, mint pl. moratórium, ami tavaly+idén totálisan megborította a futó IT projektek ütemezését, határidejeit, mert plusz ember az nincs a kormány ad hoc ötleteléseinek záros határidőre lefejlesztésére.
Előzőleg meg telconak dolgoztam, az se volt sokkal különb.

-
nyunyu
félisten
válasz
martonx
#5329
üzenetére
csomó lehetőséged van tehermentesítened az adatbázist, anélkül, hogy belegörcsölnél az SQL minden mélységébe. Pl. cachelés
Hibernate cachelésétől ments meg Uram minket.
Olyan szinten telibeszarja a DBk többfelhasználós jellegét, hogy öröm nézni.
Addig konzisztens csak önmagával, amíg rajta kívül nincs senki más, aki módosíthatja ugyanazt az adatbázist!Ha a háttérben megupdatelsz egy rekordot, azt a Hibernate nem szokta észrevenni, és a felette lévő alkalmazásban módosul a becachelt verzió, akkor szemrebbenés nélkül hülyeséggel írja felül a már megváltozott rekordot.
Nesze neked tranzakciók függetlensége.
-
nyunyu
félisten
Nem tudom ki volt, de szerintem arra gondolhatott, hogy az update, delete az egész táblát szokta lockolni, amíg le nem fut, ha a where feltételeihez nem talál használható indexet.
Ilyenkor az összes többi select, insert addig vár, amíg a tábla fel nem szabadul.Ha van olyan index, ami alapján meg tudja határozni, hogy melyik sorok érintettek az update vagy deleteben, akkor csak azokat a sorokat lockolja a DB, tábla többi része használható marad.
De ez erősen DB motor függő, nem mindegyik kezeli ugyanúgy a tábla meg sor lockokat.
-
nyunyu
félisten
Eddig az hittem, hogy van több kategória táblád, amikben nem biztos, hogy ugyanolyan id tartozik ugyanahhoz a kategórianévhez, ezért verziózod őket.
.
Ekkor logikusan vagy a cikkek-ben kellene tárolnod a kategoria_verzio-t, ha egy cikkhez egyszerre csak az egyik halmazból/táblából tartozhatnak kategóriák.Ha előfordulhat az, hogy adott cikkhez az egyik kategória az egyik halmazból, másik meg a másik halmazból származik, akkor meg a cikk_kategoria-ban van a helye.
Utóbbi esetben ez NEM lenne redundáns!Ezért írtam azt, hogy a mi a francért nem vonod össze a kategória tábláidat, hogy csak egyféle id tartozzon ugyanahhoz a kategória névhez.
De most kiderült, hogy ezekről szó sincs, hanem a kategoria_verzio az ellenőrző szkriptednek egy flag, hogy az adott cikket már ne kelljen vizsgálnia?
Mivel itt 1:1 kapcsolat van a cikkekkel, így szerintem felesleges kitenni új táblába, jó helyen van az a mező ott.Ekkor viszont túlbonyolítottam az előzőekben írt queryket, felesleges volt a sok case when, meg kategoria_v1/v2/v3 join.
Túlzottan beszédes volt a kategoria_verzio név, csak nekem teljesen mást mondott, mint amire a költő eredetileg gondolt.
Igazából neked csak arra van szükséged, hogy néha szemmelverd a cikk-kategória összerendeléseket, aztán ha egy cikkhez rossz kategória van rendelve, akkor vagy törlöd a cikk_kategoria rekordot, vagy megupdateled benne a kategoria_id-t a megfelelő kategóriáéra, ahogy a #5318-ban írtam.
-
nyunyu
félisten
Ja, hogy egységesíteni akarod a cikk_kategoria összerendeléseket?
Akkor
1) öntsd bele egy közös táblába az összes eddigi kategórianevedet (legyen kategoria_uj a példa kedvéért)2) csinálj egy cikk_kategoria_uj táblát, amiben már nincs kategoria_verzio oszlop, többi ugyanaz, mint az eddigi cikk_kategoria-nal.
3) töltsd fel tömegesen a cikk_kategoria_uj táblát:
merge into cikk_kategoria_uj i
using (
select a.cikk_id,
a.cim,
a.kategoria_nev
a.kategoria_verzio,
a.kategoria_id kategoria_id_regi
k.kategoria_id kategoria_id_uj
from (
select c.id cikk_id,
c.cim,
ck.kategoria_id,
ck.kategoria_verzio,
case
when ck.kategoria_verzio = 1 then k1.nev
when ck.kategoria_verzio = 2 then k2.nev
when ck.kategoria_verzio = 3 then k3.nev
end kategoria_nev
from cikkek c
join cikk_kategoria ck
on ck.cikk_id = c.id
left join kategoria_v1 k1
on k1.id = ck.kategoria_id
left join kategoria_v2 k2
on k2.id = ck.kategoria_id
left join kategoria_v3 k3
on k3.id = ck.kategoria_id) a
join kategoria_uj k
on k.kategoria_nev = a.kategoria_nev) x
on (i.cikk_id = x.cikk_id and i.kategoria_id = x.kategoria_id_uj)
when not matched
then insert (cikk_id, kategoria_id)
values (x.cikk_id, x.kategoria_id_uj);4) ELLENŐRIZD az új táblákat:
select c.id,
c.cim,
ck.kategoria_id,
case
when ck.kategoria_verzio = 1 then k1.nev
when ck.kategoria_verzio = 2 then k2.nev
when ck.kategoria_verzio = 3 then k3.nev
end kategoria_nev
from cikkek c
join cikk_kategoria ck
on ck.cikk_id = c.id
left join kategoria_v1 k1
on k1.id = ck.kategoria_id
left join kategoria_v2 k2
on k2.id = ck.kategoria_id
left join kategoria_v3 k3
on k3.id = ck.kategoria_id;
vsselect c.cid,
c.cim,
ck.kategoria_id,
k.nev kategoria_nev
from cikkek c
join cikk_kategoria_uj ck
on ck.cikk_id = c.id
join kategoria_uj k
on k.id = ck.kategoria_id;5) ha egyeznek, akkor átnevezed a régi táblákat valami másra.
ha nem, akkor átgondolod, mit szúrtál el/mi maradt ki.6) új táblákat átrakod a régiek helyére:
rename cikk_kategoria_uj to cikk_kategoria;
rename kategoria_uj to kategoria;7) ha már mindent 3x ellenőriztél, akkor eldobhatod az 5)-nél átnevezett táblákat.
8) itt jön az előző hozzászólásom.
NAGYON bátrak már az 5) pontnál tolhatják drop table-t.
Aztán utólag ne panaszkodjanak, hogy DDLre nincs undo. -
nyunyu
félisten
Nem teljesen értem, mit akarsz feleslegesen verziózni rajta.
Vedd a legfrissebb kategória táblázatodat, aztán annak az ID-it használd minden cikkhez.
Aztán ha jön egy új kategória, akkor csak egy helyre kell beszúrni egy új rekordot, és annak az IDját használod az új cikkhez.Ha meg egy cikk rossz kategóriába került, és utólag kézzel kell javítani?
Akkor átütöd a rossz cikk_kategoria rekordot.De az erősen kézi hajtány:
merge into cikk_kategoria u
using (
select c.id cikk_id,
c.cim cim
k1.id rossz_kategoria_id,
k2.id jo_kategoria_id,
from cikkek c
join kategoria k1
on k1.nev = 'rossz kategória'
join kategoria k2
on k2.nev = 'jó kategória') x
on (u.cikk_id = x.cikk_id and u.kategoria_id = x.rossz_kategoria_id)
when matched
then update
set u.kategoria_id = x.jo_kategoria_id;(nem mertem sima update szintaxissal írni, mert tuti belegabalyodnék és/vagy egy sor helyett a fél táblát updateelné az Oracle
) -
nyunyu
félisten
Oracle alatt lehet még használni egy rakat aggregáló függvényeknél az over (partition by valami) záradékot, akkor dinamikusan csoportosítja a rekordokat, és nem kell a lekérdezés végére a kemény group by:
create view cikkek_vw as
select c.id cikk_id,
c.cim cim,
c.create_date datum,
c.creator cikk_iro,
listagg(ck.kategoria_id, ', ') within group (order by ck.kategoria_id) over (partition by c.id) kategoria_id,
listagg(k.nev, ', ') within group (order by ck.kategoria_id) over (partition by c.id) kategoria_nev
from cikkek c
join cikk_kategoria ck
on c.id = ck.cikk_id
join kategoriak k
on ck.kategoria_id = k.id;De pl. az előbb linkelt MS SQL doksiban explicite leírják, hogy náluk kötelező a group by a string ragasztó függvényhez.
-
nyunyu
félisten
Valahogy meg lehet csinálni, hogy 1 cikk csak egyszer szerepeljen (ezt a distinct vagy a group by megoldja), és hogy a különböző kategóriák vesszővel elválasztva egy új mezőben legyenek az adott egy darab cikk rekordjában?
Persze, ha a nézetben aggregálod a rekordokat valamilyen függvénnyel:
Oracle alatt valahogy így nézne ki:
create view cikkek_vw as
select c.id cikk_id,
c.cim cim,
c.create_date datum,
c.creator cikk_iro,
listagg(ck.kategoria_id, ', ') within group (order by ck.kategoria_id) kategoria_id,
listagg(k.nev, ', ') within group (order by ck.kategoria_id) kategoria_nev
from cikkek c
join cikk_kategoria ck
on c.id = ck.cikk_id
join kategoriak k
on ck.kategoria_id = k.id
group by c.id, c.cim, c.create_date, c.creator;listagg() függvény nem része az SQL szabványnak, nem tudom, a Te DB motorod alatt van-e hasonló aggregálási lehetőség, illetve milyen szintaxissal.
(MySQL alatt GROUP_CONCAT, MS SQL alatt STRING_AGG)Ilyenkor a végére KELL a group by, mert az fogja megmondani, hogy milyen mezők alapján csoportosítsa/vonja össze a sok találatot egy-egy rekordba.
within group (order by valami) meg azt mondja meg, hogy a vesszővel felsorolt elemek mi szerint legyenek sorbarakva.
(gondolom IDnál és a névnél is ugyanazt a rendezést akarod használni
) -
nyunyu
félisten
create view cikkek_vw as
select c.id cikk_id,
c.cim cim,
c.create_date datum,
c.creator cikk_iro,
k.id kategoria_id,
k.nev kategoria
from cikkek c
join kategoria k
on k.id = c.kategoria_id;Aztán ezt már úgy kérdezed le utólag, ahogy akarod:
select *
from cikkek_vw
where kategoria = 'receptek'
order by cim;Aztán libasorban felsorolja neked a krumplileves, mákos guba, pejsli, töltött paprika receptes cikkek fő adatait.
Az már egyéni ízlés vagy munkahelyi megszokás kérdése, hogy a nézetek elnevezésénél V_ előtagot, vagy _VW utótagot használsz.
-
nyunyu
félisten
Egyelőre szerintem indulj el, aztán ha már úgy látszik, hogy a táblaméretek növekedésével egyre lassabb, akkor ráérsz optimalizálni.
Akkor már úgyis lesz elég adatod a felhasználói szokásokról, és egyértelműbben kirajzolódik, hol van a szűk keresztmetszet.1% sebességnövelésre nem érdemes napokat elszúrni.
Nekem is volt olyan projektem, ahol engem cseszegettek állandóan, hogy túl sokáig fut nagy ügyfelek esetén az adatmigráció teljességét vizsgáló querym, végül már a DBA guruink optimalizálták, de úgy sem lett sokkal jobb a helyzet, talán 10%-ot tudtak nyerni az indexeléssel és egyéb mágiával.
Legnagyobb telefonelőfizető vállalatot 12 óra alatt tudtuk végigkergetni, ebből 2-3 óra volt az adatkonverzió, és 9-10 az adathelyesség+teljesség ellenőrzés.Aztán projekt végén távoztak a főokosok, akik az adatellenőrző motort fejlesztették, és én örököltem meg a kódjukat a következő projekthez, mondván van már elég gyakorlatom a ellenőrző funkciók írásában.
Sikerült beüzemelni, főnököm elment demózni, hogyan lehet egy mozdulattal megszüntetni 120 ezer előfizetést, aztán 20 perc múlva idegesen telefonál, hogy még mindig nem jött be a következő képernyő.
Végül valami 2 óra volt, mire egy táblában szereplő 120 ezer rekordot sikerült kikeresni pár másik táblából, és a demó alkalmazás továbblépett a következő képernyőre.Kézzel megfuttattam ugyanazt az ellenőrző queryt, 3 perc alatt lefutott.

Na, akkor jobban nekiálltam átnézni az ellenőrzéseket futtató motort, és észrevettem, hogy a kolléga minden rekordra, minden egyes query futtatására kurzort használt, így a tömeges adatellenőrzésre szolgáló query annyi példányban futott libasorban, ahány sor volt a táblában

Plusz megfejelve a dinamikusan összerakott SQL futattatásának a hívásonkénti overheadjével (120e rekordnál az bő egy óra!)Utána egy hétig faragtam az örökölt kódot, mire kiírtottam belőle az összes létező kurzort, hogy az összes query az egész adathalmazra egyben fusson, és egyszer legyen csak dinamikus SQL hívva.
Eredmény? 2 óra helyett 3 perc.Ha visszaportoltam volna az újraírt motort a migrációs projektbe, akkor "kedvenc" nagyvállalatunkat 12 helyett 3 óra alatt le tudtuk volna futtatni, ugyanazokkal az ellenőrző querykkel...
Szóval az optimalizálnivaló nem mindig ott van, mint amire először gondolnál!
-
nyunyu
félisten
Indexet csak a leggyakrabban keresett/joinolt oszlopokra érdemes tenni.
Ha a hébe-hóba kérdezett feltételeket is indexeled, azzal többet ártasz, mint használsz, mert az új rekordok beszúrása, illetve régiek törlése is lassul minden egyes plusz indexszel.Törlés+index létrehozás, újraépítés max akkor segít, ha nagyon sok rekordot töröltél a táblából, és emiatt lyukas lesz az index, és nem működik optimálisan.
De ez megint a többmillió soros táblák problémája, alatta jellemzően nem nyersz sokat azzal, hogy újraépíted.Szélsőséges példa: van egy millió soros táblád, ennek az indexe is millió rekordot tartalmaz.
Kitörölsz a táblából 900k rekordot, ekkor az index mérete nem változik, továbbra is 1m helyet foglal, lesz benne 900k lyuk.
Újraépítés után az index mérete lecsökken a maradék 100k-ra, így 10x gyorsabban lehet majd végigmenni rajta, mint újraépítés nélkül.
(B-fáknál log2(10) a gyorsulás?) -
nyunyu
félisten
válasz
martonx
#5241
üzenetére
ElasticSearchtől azóta kapok sikítófrászt, mióta kedvenc adóhatóságunk olyat szeretett volna az adószámla egyenlegek tárolására + napi újraszámolására, mert az menő, passzol a mikroszerviz architektúrába, és jól skálázható. (meg ingyenes(?) a licensze, tehát többet lehetett volna a projektből khm. megtartani)
Szerencsére főnökömnek sikerült megértetnie velük, hogy nagy mennyiségű, jól struktúrált adat kezelésére rendes RDBMS való, meg arra találnak hozzáértő szakembereket is, sok tapasztalattal.
Aztán a projekt végén, amikor csak a mi modulunk készült el határidőre (emiatt nem kellett meneszteni a projektért felelős álomtitkárt, meg az illetékes vezérőrnagyokat a sóhivatalból), akkor jól le lettünk szúrva, hogy de hát az architektúra szerint semmi SQL nem lehet a kódban, hol van az ElasticSearch, így nem veszik át.
Közben a projektmenedzseri divatlapokban olvasott menő három-négybetűs buzzwordökből összeollózott szent architektúrát szolgaian követő többi fejlesztőcsapat 2 év alatt 2 év késést hozott össze

-
nyunyu
félisten
Azt neked kell végiggondolni, hogy a táblád legszélesebb oszlopát indexelni akarod-e.
Ha igen, az (közel) megduplázza a tábla helyigényét, de legalább minden beszúrás, törlés művelet sokkal lassabb lesz, hiszen az indexet is karban kell tartania.Kérdés, hogy ez megéri-e azt, hogy néha-néha like '%%'-kal akarj benne keresni.
De mivel egy sokszázezer soros táblára tett többezer karakter széles index sem fog beleférni a memóriába, így szerintem tökmindegy, hogy az eredeti táblán megy a full table scan, vagy a nem sokkal kisebb indexet kell végigolvasnia először, és csak utána éri el a táblát.
Gyors az nem lesz... -
nyunyu
félisten
válasz
Apollo17hu
#5237
üzenetére
Rekurzió az matematikalag elegáns, gyakorlatban meg nagyon nem praktikus, akármelyik programnyelvet nézem.
-
nyunyu
félisten
válasz
Apollo17hu
#5224
üzenetére
Hmm, jobban megnéztem ezt a részt:
with cte(id,ertek,runningsum,seqnum) as
(select 0.szint
union
select n+1. szint)
select ... from cte;Ez pont ugyanúgy néz ki, mint amit a Teradata 13 tutorialokban láttam anno.
Ezek szerint az már szabványosított rekurziós szintaxist használhatott?Mondjuk a Teradata mindig hamarabb implementálta az új SQL szabványokat, mint az Oracle

-
nyunyu
félisten
válasz
Apollo17hu
#5224
üzenetére
Tényleg, a CTE szabványosításának az is volt a célja, hogy az addigi, DB függő szintaxis helyett könnyebben lehessen rekurzív queryket írni.
De sosem szerettem rekurzív kódot írni, mert nagyon könnyen beláthatatlan tud lenni.
-
nyunyu
félisten
Ha nagyon gonosz akarnék lenni, akkor:
UPDATE new_table
SET Parameter1=old_table.Parameter1
WHERE old_table.AzonosParameter = new_table.AzonosParameter;(30+ évvel ezelőtti Teradata szintaxis, még a FROM clause bevezetése előttről.
Kellett nekem ilyenekre SQL parsert írnom adattárház gyakornok koromban.
)Ha meg nem akarnék az lenni, akkor:
MERGE new_table u
USING old_table o
ON (u.AzonosParameter = o.AzonosParameter)
WHEN MATCHED THEN UPDATE
SET Parameter1=o.Parameter1; -
nyunyu
félisten
válasz
Apollo17hu
#5214
üzenetére
Az a baj, hogy az előző lépésben számolt értékre van szükséged a következő kiszámolásához, és nem szimplán szummázod a korábbi értékeket.
Így vagy rekurzívan számolod ki, vagy ciklust írsz rá.
Ezekre nem nagyon van szabvány szintaxis, kb. minden DBnek más megoldása van rá.
Oracle alatt valahogy így nézne ki a ciklusos megoldás:
DECLARE
v_id varchar2(10);
v_ertek number;
v_korr_ertek number := 0;
CURSOR c is
SELECT id, ertek
FROM proba
ORDER BY id;
BEGIN
OPEN c;
LOOP
FETCH c INTO v_id, v_ertek;
EXIT WHEN c%notfound;
v_korr_ertek := CASE WHEN v_korr_ertek + v_ertek > 0
THEN 0
ELSE v_korr_ertek + v_ertek
END;
dbms_output.put_line(v_id || ',' || v_ertek || ',' || v_korr_ertek);
/*
UPDATE proba
SET korr_ertek = v_korr_ertek
WHERE id = v_id;
*/
END LOOP;
CLOSE c;
END;Deklarálsz egy kurzort, amiben azonosító szerint növekvő sorrendben jönnek a rekordok, aztán azon egyesével végig mész, kiszámolva az aktuális korrigált értéket.
-
nyunyu
félisten
Tudom, Teradata huszonévvel ezelőtti szintaxisát emelték be az SQL Server 2008-ba, ami sosem volt szabványos.
Mondjuk a Teradatának volt egy olyan hasznos fícsöre, hogy csak a sikeresen illesztett sorokon updatelte a cél táblát, míg ha Oraclenek valami ilyesmit írtál:
UPDATE tábla1 u
SET u.valami = (select valami from másiktábla a where a.id=u.id);Akkor a nem illeszkedő sorokat is felülvágta NULL-lal

(Nem emlékszem pontosan az elszabott Oracle szintaxisra, helyette mindig MERGEet írtam.) -
nyunyu
félisten
válasz
Apollo17hu
#5214
üzenetére
Mint az egyszeri matekpélda, ahol az első megállóban felszáll 2 ember a buszra, másodiknál leszáll 5, akkor hány embernek kell felszállnia a harmadiknál, hogy senki ne legyen a buszon?
-
nyunyu
félisten
Nem teljesen értem, mire való a második táblád.
Ha ebben csak a lehetséges táborozási opciók vannak felsorolva, és a harmadik táblába viszed fel a beérkezéskor, hogy melyik gyerek melyik opciókat kéri, akkor a harmadik táblába csak a gyerek nevét (vagy elsődleges azonosítóját/kulcsát), és az opció azonosítóját kell letárolnod.
Ha a második táblában előre le vannak tárolva, hogy melyik gyerek mit kért (gyerekneve/azonosítója, opció párosként), akkor a harmadik tábla helyett kellene egy lekérdezés vagy nézet, ami ebből egy mátrixot rajzol.
valahogy így:
select nev, vega, reggeli, ebed, vacsora, szamtech, lovas, uszas
from (
select x.nev,
max(x.vega) vega,
max(x.reggeli) reggeli,
max(x.ebed) ebed,
max(x.vacsora) vacsora,
max(x.szamtech) szamtech,
max(x.lovas) lovas,
max(x.uszas) uszas,
from (
select gy.nev,
case when o.opcio = 'Vega' then 'I' else '' end vega,
case when o.opcio = 'Reggeli' then 'I' else '' end reggeli,
case when o.opcio = 'Ebéd' then 'I' else '' end ebed,
case when o.opcio = 'Vacsora' then 'I' else '' end vacsora,
case when o.opcio = 'Számítástechnika' then 'I' else '' end szamtech,
case when o.opcio = 'Lovas' then 'I' else '' end lovas,
case when o.opcio = 'Úszás' then 'I' else '' end uszas,
from gyerekek gy
join opciok o
on o.gyerek_id = gy.id) x --vagy o.nev = gy.nev, ha nevet tárolsz
group by x.nev);Ennek az eredménye egy ilyen táblázat lesz:
NEV VEGA REGGELI EBED VACSORA SZAMTECH LOVAS USZAS
Kiss Péter I I I I
Nagy Anett I
Török Flóra I I I(Bocs, nem nagyon vágom az Accesst, de elvileg szabvány SQL-ben is meg lehet feléje fogalmazni a kéréseket.)
-
nyunyu
félisten
Ugyanúgy, where alá megy a szűrő alquery:
SELECT f.item_id, f.item_date
FROM
(SELECT item_id, item_date
FROM items
ORDER BY item_date ASC LIMIT 1000) AS f
INNER JOIN items_categories AS fic
ON f.item_id=fic.item_id
WHERE f.item_id not in (select t.item_id
from items_categories t
where t.category_id IN (27))
GROUP BY f.item_id, f.item_date
ORDER BY f.item_date ASC LIMIT 4Tehát a termék-kategória párosokból leválogatod azokat a termékeket, akik a nemszeretem kategóriában vannak, és ezzel szűröd az eredeti terméklistát.
-
nyunyu
félisten
Ugyanezt benéztem nemrég melóban.
Még szerencse, hogy a tesztelők is átnézték a GDPR törlendő szerződések listáját, és kiszúrták, hogy a left join tiltolista + where tiltolista.id is not null átengedte azokat a szerződéseket, ahol csak az egyik ügyfél volt tilitólistás, másik nem.
Írhattam át a queryt where ügyfél not in (select id from tiltolista)-ra. -
nyunyu
félisten
Fordítva gondolkozol.
Nem azokat kell megmutatni, amik nem 27-es kategóriájúak, mert akkor a többszörös kategóriából csak azt az egy példányt zárod ki, nem az összeset.
Helyette azokat a termékeket nem szabad megmutatni, amik 27-esek.
Úgy biztosan kizárja a terméket, akárhány kategóriába tartozik is a 27-esen kívül.SELECT item_id, item_date
FROM items
WHERE
item_id NOT IN (select item_id from items_categories where
category_id in (27))
ORDER BY item_date ASC LIMIT 4 -
nyunyu
félisten
Jééé, Oracle 19c alatt már működik az oszlop aliasra order by, és nem kell kiírni az egész képletet?

11 csak oszlopszámra, vagy komplett képletre engedett order by-olni.
-
nyunyu
félisten
Azt ne felejtsd ki a képletből, hogy a count() lekérdezésnek a végeredménye egy szám, míg a count() nélkülié egy adathalmaz, aminek a DB szerverről letöltése lényegesen tovább tart.
Tegnap kellett lementenem egy 850k soros táblához kapcsolódó adatokat CSVbe, eltartott vagy 20 percig, mire lejött a 160 mega adat a céges VPNről.
Ugyanez select count(*) from (eredeti query)-vel 5 másodpercig tart. -
nyunyu
félisten
Ha Azureban gondolkodsz, akkor érdemesebb lehet SQL Server (Express) irányban nézelődni először.
Ha bejön, akkor onnan már minimális kód módosítással igénybe tudod venni az SQL Server felhős változatát. -
nyunyu
félisten
válasz
martonx
#5131
üzenetére
Kérdés, hogy azokból a free megoldások (Oracle XE, SQL Server Express) mennyire használhatóak az ő céljaira, hiszen pár magra meg pár GB RAMra vannak korlátozva, és az adatbázis lehetséges mérete is korlátozott, ez többmillió soros táblákhoz kevés lehet.
Oracle XE:
- 2 szál
- 2GB RAM
- 12GB tárterület
- 3 DB (séma?)SQL Server Express:
- 4 mag
- 1GB RAM
- 1MB puffer
- 10GB tárterületMindenesetre egy próbát megérnek, hogy melyik hogyan hasít a gépeden.
Más kérdés, hogy a MariaDBs szintaxist, adattípusokat biztosan át kell majd írni PL/SQL-re vagy T-SQL-re.
Amennyire múltkor nézegettem a MariaDBt, szintaxisa inkább az Oracle szintaxisához áll közelebb.Nem tudom, hogy hoztad létre az ID mezőket a táblákban, ha autoincrementesek, akkor egyszerűbb lehet az SQL Server Expresst használni, mivel Oracle még mindig szekvenciákat használ, amit neked kell manuálisan
kezelni.PostgreSQL-t nem vágom.
-
nyunyu
félisten
válasz
sztanozs
#5116
üzenetére
Nincs rá garancia, az igaz.
Gyakorlatban meg pont emiatt szívtam a mostani GDPR projektemen.
3 insert szedte össze a daráló érett szerződéseket, első leválogatta az egyik típusú szerződéseket, második az első szerződésekhez kapcsolódó másik típusúakat, harmadik meg a második típusúakból az önállókat.Aztán amikor beröffentettük az állami hivatallal való szinkronizációt, az első 20000db-os adatcsomagba kb. 19000 olyan rekord került, aminek az IDja 20000 alatti volt.
Végül a második típusú szerződések szinkronizációjára már csak akkor került sor, amikor az első típusúak teljesen elfogytak a táblából.Ez azért volt kellemetlen, mert mint kiderült, a második típusú szerződések nagy része nem kellett, hogy meglegyen az állami nyilvántartásban, azok sokkal gyorsabban darálhatóak lennének.
Első típusúak darálása meg nem ment olyan gyorsan a túloldalon, mint vártuk. -
nyunyu
félisten
SQL99 óta azt javasolja a szabvány, hogy csoportosításnál, rendezéskor írd ki a teljes mezőt, függvényt, akármit.
Oszlopra sorszámmal hivatkozás az ennél régebbi szintaxis maradvány, már nem szabványos.Eddig csak Oracle kódokban láttam használatban, de ahogy nézem jó pár DB kezelő ismeri ezt a szintaxist.
-
nyunyu
félisten
GROUP BY az aggregáló függvényekhez (min, max, avg, sum...) kell, az mondja meg, hogyan csoportosítsa az adatokat aggregálás előtt.
Utána felsorolt oszlopokból képez egyedi halmazokat, és az aggregátor függvény oszlopában annak a halmazra lefuttatott függvényértéket fogod visszakapni.
-
nyunyu
félisten
válasz
martonx
#5083
üzenetére
Korábban írta, hogy MariaDBt használ, azt meg nem támogatja az SQLFiddle.
Múltkor próbáltam felrakni a gépemre a MariaDBt, de már az is gondot okozott, hogy találjak Win7 x64-en elinduló verziót, asszem a 10.3.30-ig kellett visszamennem.
Utána meg szívtam a mellécsomagolt HeidiSQL IDEvel *, aminek a működése eléggé az agyamra ment, meg az Oracle hibaüzeneteinél is semmitmondóbb hibaüzenetektől ** is a falra másztam, amikor valami szintaktikai hiba volt, vagy éppen Oracle kompatibilis módban lévő MariaDBnek nem tetszett a kód.
Kb. fél nap google után inkább feladtam, hogy az Oracle alatt hibátlanul működő példámat átírjam MariaDBre.
*: Rég dolgoztam ennyire használhatatlan IDEvel, szerintem még az SQL Server 2000-ét is alulmúlja. (2005-től jött helyette a Visual Studio stílusú SQL Server Management Studio)
**: pl. a lemaradt egy vessző hibaüzenet végére odamásol sortörések nélkül 5 sor kódot, amiből minden látszik, kivéve az, hogy melyik sor végéről maradt le.

Ennyire hülye még az Oracle SQL Developer se szokott lenni, pedig az sem a szívem csücske. -
nyunyu
félisten
nekem az kellene, hogy a feed_id-kra legyen vonatkoztatva, tehát a képernyőfotós példában a 100111 csak egyszer szerepeljen.
Ha kiveszed a lekérdezésből a category_id-t, akkor minden feed_id csak egyszer fog szerepelni.
DISTINCT mindig a lekérdezésben szereplő összes oszlopra nézi az egyediséget!
-
nyunyu
félisten
Sokszorozás:
- Végigmész egy kurzorral a termék táblán, megjegyzed az eredeti adatait.
- kiosztasz neki egy új azonosítót
- beszúrsz egy új termék rekordot az eredeti adataival, csak id helyére az újat írod
- leválogatod a termék_kategoria táblából az eredeti terméked kategória értékeit
- beszúrod a termék_kategóriába az új termék_id, régi_kategória_id párosokat
- tetszés szerint ismétled-- sokszorozás
declare
regi_id number;
regi_name varchar2(100);
uj_id number;
i number;
cursor cur is
select p.id,
p.name
from product p
where instr(p.name,'_') = 0;
begin
open cur;
loop
fetch cur into regi_id, regi_name;
exit when cur%NOTFOUND;
for i in 1..1000
loop
uj_id := product_seq.nextval;
insert into product (id, name)
values (uj_id, regi_name || '_' || to_char(i));
insert into product_category (id, product_id, category_id)
select product_category_seq.nextval,
uj_id,
pc.category_id
from product_category pc
where pc.product_id = regi_id;
end loop;
end loop;
close cur;
end;Próbáltam SQLFiddlében összerakni a múltkori gyümölcsös példámat, de valamiért nem tetszik neki a szintaxis.
Hús-vér Oracle alatt persze simán legenerál 1000 új példányt minden termékből.
Ha a DB kezelőd automatikusan inkrementálja az id mezőt (kb. mindenki, kivéve Oracle
), akkor a for ciklus belsejében először beszúrod az új termék példányt, aztán leselectálod az id-jét az uj_id változóba, és úgy használod a termék_kategória beszúrásnál.Pl. SQL Serveren valahogy így
...
while @i <= 1000
begin
insert into product (name)
values (regi_name || '_' || convert(varchar(10),i));
select p.id
into @uj_id
from product p
where p.name = regi_name || '_' || convert(varchar(10),i));
insert into product_category (product_id, category_id)
select
@uj_id,
pc.category_id
from product_category pc
where pc.product_id = regi_id;
set @i = @i +1;
end;
..(Még jó, hogy mindenki másképp írja a szabvány SQLen felüli részt.)
-
nyunyu
félisten
Nem karbantartható.
Ahányszor jönne egy új kategória, annyiszor felvennél kézzel egy új oszlopot a táblába, és megupdatelnéd az összes rekordot 0 értékkel?
Plusz az összes lekérdezést átírnád, hogy az új oszlopot is figyelje?Külön kategória táblában akárhány kategória elfér, csak egy új rekordot kell beszúrni, aztán annak az ID-ját hozzárendelni a termékhez.
Nem jár adatszerkezet és kód módosítással! -
nyunyu
félisten
És ha jól értem, ugye azt írod, hogy csináljak egy product_category táblát, amibe úgy kerülnének bele a rekordok, hogy ha a fő táblámban (product) mondjuk van 2 millió rekord, és mindegyikhez tartozik 2-4 (átlagban 3) kategória (category). Akkor e szerint a product_category táblában jelen állás szerint 6 millió rekord lenne.
Nem ez a lényeg, hanem az, hogy a kategória táblád párszáz, ezer rekordos lesz csak.
Ezen a string műveletek időigénye még nem tragikus, gyorsan le tudja kérdezni kategórianevekhez tartozó ID-t.
Aztán abból már könnyen joinolja a többmilliós product_category táblát (ha tettél indexet a category_id-re), így hamar megvan a product_id, ami meg szintén külső kulcs, a product tábla elsődleges kulcsára mutat, ami megint csak indexelt, aztán máris megvannak a megfelelő termék rekordjaid.Feltételezem, hogy valami webshop motort hegesztesz, ahol a vevő a termék kategóriára is tudna szabadszövegesen keresni, ezért kell a kategória névre string illesztés.
-
nyunyu
félisten
N:M kapcsolatnak pont az a lényege, hogy külön-külön lekérdezhető mindegyik variációja.
Teszemazt van egy product táblád:
id name
1 alma
2 körte
3 banán
4 szilva
5 narancsvan egy categoryd:
id name
1 piros
2 sárga
3 zöld
4 kék
5 narancssárgaEzeket összerendelő product_category táblád:
product_id category_id
1 1
1 2
1 3
2 2
3 2
4 4
5 1
5 5Ha erre ráuszítod az előző querymet c.name like '%sár%'-ral, akkor ki fogja neked listázni az almát, körtét, banánt, narancsot, mert azok SÁRga vagy narancsSÁRga kategóriásak.
Ha azt akarod kérdezni, hogy melyik az a termék, amiből van sárga és piros is, akkor kétszer kell a product_category-t és a categoryt joinolni, és azokat ANDdal kérdezni:
select p.*
from product p
join product_category pc1
on pc1.product_id = p.id
join category c1
on c1.id = pc1.category_id
join product_category pc2
on pc2.product_id = p.id
join category c2
on c2.id = pc2.category_id
where c1.name = 'sárga' and c2.name = 'piros'
order by p.date desc;Ez már csak az almát találná meg.
Ha ezt írnád:
where c.name = 'sárga'
or c.name = 'piros'
or c.name = 'kék'
vagy az ezzel ekvivalenswhere c.name in ('sárga','piros','kék')
feltételt, akkor az összes sárga vagy piros vagy kék gyümölcs lejönne (alma, körte, banán, szilva)
Narancs nem, mert itt kategórianévre teljes egyezés a feltétel! -
nyunyu
félisten
DB teljesítményhez két dolog szükséges: sok RAM, meg sok, gyors diszk.
Több procimagot is meghálálja, de arra nem annyira érzékeny, mint a kevés memóriára.Tényleg, nem valami ingyenes DB licenszet használsz, ami 1 magra és 1GB RAMra van korlátozva?
(Pl. Oracle XE, SQL Server Express) -
nyunyu
félisten
Jaj, itt már a relációs adatmodell alapjai is hiányoznak.
Ahogy tm5 írja, ki kéne tenni a kategóriákat egy külön táblába, amiben van egy category_id, és egy name mező.
Mivel ez pártíz-száz különböző értéket fog tartalmazni, ezen akár még a lájk is működhetne gyorsan, nem fájna annyira, mint egy nagyonnagy táblán.Mivel egy termékhez több kategóriát is szeretnél tárolni, illetve egy kategóriába több termék is eshet, így N:M reláció lesz a termék és a kategória között.
Ennek leképezése úgy történik, hogy csinálsz egy termék_kategória táblát, amibe beleteszed a termék azonosítóját, és a kategória azonosítóját.
Ahány kategóriába tartozik, annyiszor veszed fel ide a terméket, mindig a következő kategória azonosítójával.Lekérdezéskor meg joinolod az id-k mentén a három táblát, valahogy így:
select p.*
from product p
join product_category pc
on pc.product_id = p.id
join category c
on c.id = pc.category_id
where c.name like '%akármi%'
order by p.date desc; -
nyunyu
félisten
A probléma leginkább azzal van, hogy szótöredékre próbálsz keresni
like '%valami%', emiatt nem nagyon tudja hatékonyan használni a category_id-re tett indexet.Azért egy próbát megérhet egy (channel_id, category_id) összetett index, hátha segít valamit.
Ha szó elejére keresnél
like 'valami%', akkor könnyen meg tudná mondani az indexből, hogy melyik rekordok kellhetnek. -
nyunyu
félisten
Indexet elég egyszer építeni, utána automatikusan karbantartja a DB, amíg el nem dobod a táblát.
Index karbantartás miatti insert, update időtöbblet sokkal kisebb, mint amit a selecteknél nyersz.
Sőt, sokmillió rekordos DBből törléskor baromi lassú tud lenni, ha a wherenél megadott feltételeket nem tudja legalább részlegesen kiértékelni valamelyik index használatával.
Olyankor gyorsabb, ha létrehozol egy indexet (pár perc alatt megvan!), majd a nagy mennyiségű adat törlése után eldobod az indexet.
-
nyunyu
félisten
Categoryt hiába indexálod, fészbúk operátor miatt mindig full table search lesz az eredmény...
Ha nem muszáj, ne nyomd a lájkot.
Nem tudom, melyik a gyakrabb a táblából olvasásnál, channel_id-re szűrés vagy a dátum szerinti rendezés, attól függően lehetne összetett indexet is használni, pl.:
CREATE INDEX table_ix1 ON table(channel_id, date);
Gyakrabban használt oszlopot tedd előre az indexben.Egy táblából olvasáshoz egyszerre csak egy indexet szoktak használni a DB kezelők, így hiába tennél minden oszlopra külön-külön, jobban jársz pár jól megválasztott összetett indexszel.
-
nyunyu
félisten
Próbálj meg indexet tenni a date mezőre.
CREATE INDEX table_date_ix ON table(date);Akkor nem próbálja meg felolvasni az egész táblát a memóriába 4 rekord kedvéért, hanem csak az indexet tölti be, és az alapján választja ki a következő négyet.
Sokmillió rekordos táblákat nem móka index nélkül használni...
-
nyunyu
félisten
Egyébként meg lehet, hogy a tákolt eljárás ezredmásodpercekre kireszelése helyett inkább a folyamatot kéne átnyálazni, hogy az mennyire optimális, azzal valószínűleg SOKKAL többet nyernél.

Egy korábbi combos adatmigrációs projekten anyáztak velem állandóan a nagy adatmennyiségen lefutó sok adatellenőrző szkript "lassúsága" miatt.
(Én reszelgettem a szkripteket azon a projekten)Aztán következő projekten újrahasznosítottuk az egész adatellenőrző keretrendszert, csak annak a gazdája már nem volt a csapatunk része, így elmélyedhettem a kolléga kódjában, és tele volt kurzorokkal, meg dinamikusan összerakott SQL hívásokkal

Egészben az volt a legszebb, hogy az összes rekordra egyesével hívta meg az ellenőrző szkripteket.Azt meg tudni kell, hogy Oracle alatt egy exec 'select 1 from dual;' akkor is másfél másodpercig tart, ha fejreállsz közben...
Végeredmény az lett, hogy az egyesével futtatott szkripteket összefűztem egy clobba, aztán az lett dinamikusan futtatva.
Plusz kivettem a kurzort az egész elől, mert az ellenőrző szkriptek eleve úgy voltak megírva, hogy egész táblára futottak, így egy százezres táblán elég volt őket egyszer meghívni, nem kellett rekordonként külön-külön...Eredmény? 20 perc helyett lefutott az egész 15 másodperc alatt.
Tanulság?
Ne engedj Java/C/C# programozót SQLt "kódolni", mert az teljesen más műfaj.
(Pláne, ha natív SQL helyett Hibernate-tel vagy LinQ-el súlyosbítja
)Kiváncsi lettem volna, hogy a keretrendszer 2.0-át visszaportolva a légycsapó projektbe, mennyi ideig tartott volna a 3 betűs nagybank összes telefonvonalának adathelyesség ellenőrzése az eredeti 12 óra helyett

-
nyunyu
félisten
válasz
kw3v865
#5018
üzenetére
Akkor nézd meg most, mit csinál a query plan, aztán tegyél indexet a táblákra a join feltételek mentén, aztán ismét nézd meg mit csinál a query plan

Meg sokszor a statisztika gyűjtés is hasznos tud lenni nagyobb számítások előtt, hogy a DB optimalizálónak legalább valami halvány fogalma legyen arról, hogy melyik tábla mekkora, mert másképp célszerű csinálnia a joint kicsi tábláknál, mint nagyoknál.
-
nyunyu
félisten
válasz
kw3v865
#5016
üzenetére
Ja, hogy a sokmilliós táblán nincs index?
Úgy biztos lassú lesz.Ha meg dinamikus SQLt vagy egyéb hasonló külsőleg futtatandó varázslatokat hívsz, akkor meg pláne lemondhatsz az 1-2 másodperc alatti futásidőről.
Ha meg annyira időkritikus, akkor nincs mese, alá kell pakolni a vasat.
Esetleg elgondolkozni azon, hogy tetőfedéshez nem malteros kanalat kéne használni, mert azzal tényleg nem lehet haladni, akárhogy optimalizálod a processt. -
nyunyu
félisten
-
nyunyu
félisten
Esetleg összefűzni az egy percen belüli logbejegyzéseket?
SELECT x.min_date,
listagg(x.log, chr(10)||chr(13)) within group (order by x.rn) log_list
FROM (
SELECT a.date min_date,
row_number() over (group by a.date order by b.date) rn,
b.log
FROM table a
JOIN table b
ON b.date >= a.date
AND b.date <= a.date + interval '1' minute) x
GROUP BY x.min_date
ORDER BY x.min_date;(Nem tudom, hogy néz ki a listagg postgresql megfelelője.)
-
nyunyu
félisten
Esetleg összefűzni az egy percen belüli logbejegyzéseket?
SELECT min_date,
listagg(b.log, chr(10)||chr(13)) within group (order by rn) log_list
FROM (
SELECT a.date min_date,
row_number() over (group by a.date order by b.date) rn,
b.*
FROM table a
JOIN table b
ON b.date >= a.date
AND b.date <= a.date + interval '1' minute)
GROUP BY min_date
ORDER BY min_date;(Nem tudom, hogy néz ki a listagg postgresql megfelelője.)
-
nyunyu
félisten
válasz
kw3v865
#4997
üzenetére
Nem teljesen értem, hogy mit is szeretnél igazából.
Leválogatni a legsűrűbb időbélyeg környékeket?
Listázni az időbélyegeket, és a tőlük max 1 percre lévő logbejegyzéseket?Utóbbira valami ilyesmit tudnék elképzelni:
SELECT *
FROM (
SELECT a.date min_date,
row_number() over (group by a.date order by b.date) rn,
b.*
FROM table a
JOIN table b
ON b.date >= a.date
AND b.date <= a.date + interval '1' minute)
ORDER BY min_date, rn; -
nyunyu
félisten
válasz
kw3v865
#4995
üzenetére
Nem lenne egyszerűbb az időbélyegek különbsége alapján számolni?
SQL szabvány szerint mint a dátum, mind az időbélyeg típusok kivonhatóak egymásból és akkor kapsz egy időintervallumot.
Vagy dátum+időintervallum=dátum, időbélyeg+időintervallum=időbélyeg!Én legalábbis úgy nézném meg, hogy mi a legsűrűbben logolt környék, hogy önmagával összejoinolnám a táblát, hogy a második rekord időbélyege nagyobb legyen, mint az elsőé, és a különbségük egy percen belül legyen, aztán ezt a halmazt group by-olnám az első időbélyegre, és megszámolni, hány második tartozik hozzá.
valami ilyesmire gondoltam:
SELECT y.date, y.cnt
FROM (
SELECT x.date, count(x.date2) cnt
FROM (
SELECT a.date, b.date as date2
FROM table a
JOIN table b
ON b.date > a.date
AND b.date < a.date + interval '1' minute) x
GROUP BY x.date) y
ORDER BY y.cnt desc;Itt az erős join miatt csak azokat az dátumokat/időbélyegeket fogod visszakapni, ahol egy percen belül volt legalább egy másik bejegyzés.
Magányos, kósza bejegyzéseket nem! (mondjuk a b.date >= a.date feltétellel azokat is figyelembe lehetne venni.) -
nyunyu
félisten
Mai színes:
Oracle alól indítva
select *
from tabla@SQLSERVER
where id=1;Visszajön egy ilyen hibaüzenet:
[Microsoft SQL Server]Error converting data type varchar to numeric {HY000, NativeErr = 8114}where id='1';Dettó ugyanaz a hiba.
where to_number(id)=1;
Működik...where masikid=2;
Bezzeg ez is működik...
Megfejtés:
id numeric(10,0)-nak, masikid numeric(3,0)-nak van castolva a MSSQL oldali viewban.Fene se érti, miért hasal ez el a két DB közti adatkonverziós rétegen.
-
nyunyu
félisten
Nem ezt akarod inkább lekérdezni?
with t1t2 as
(select t1.ID, t1.Date1 as Date, t1.Attr1, null as Attr2, t1.valid_from, t1.valid_to
from t1
union
select t2.ID, t2.Date2 as Date, null as Attr1, t2.Attr2 as Attr2, t2.valid_from, t2.valid_to
from t2)
select distinct
akt.id,
akt.date valid_from,
lead(akt.date) over (order by akt.date) valid_to,
ut1.attr1,
ut2.attr2
from t1t2 akt
left join t1t2 ut1
on ut1.id=akt.id
and ut1.valid_from<=akt.date
and ut1.valid_to>akt.date
and ut1.attr2 is null
left join t1t2 ut2
on ut2.id=akt.id
and ut2.valid_from<=akt.date
and ut2.valid_to>akt.date
and ut2.attr1 is null
order by akt.id, akt.date;Összefűztem a két táblát, majd minden dátumhoz megkeresem az adott pillanatban érvényes Attr1 és Attr2 értékeket, meg a következő változás dátumát.
-
nyunyu
félisten
De ez egy realációs adatbázis, szóval lehet, hogy több táblából is kell törölni, lehet megfelelő sorrendben, mittudomén, innentől már egy db expert is megízzadna ezzel a feladattal.
Ne emlegesd, pont egy ilyen banki projekten dolgozom 1 hónapja...
Mindenféle custom Java alkalmazás alatti ~250 Oracle táblából kell kigyalulni a rég lejárt adatokat, de persze egyikhez sincs semmi doksi, fejlesztők már rég máshol dolgoznak, meg a táblák nagy részén nincsenek foreign keyek, nehogy véletlenül lássuk, melyik tábla melyikhez kapcsolódik adattartalomra.
ER diagram? Ha rajzolok, akkor talán lesz.Törlést végző cuccot elődeim szerencsére már megcsinálták, már csak az alkalmazások forráskódjából kell kihámoznunk, hogy mi hova joinolódik, hogy sorba rendezhessük a 250 táblát, hogy miből mit kell előbb törölni, és csak utána lehet a rájuk hivatkozó rekordokat.
-
nyunyu
félisten
Azt nem tudod belegyógyítani a közös táblát író insertbe, hogy HTML requestben megkapott domain függően töltse ki a forras mezőt?
Illetve a weblapnak választ adó selectekbe is?insert into ujtabla (forras, mezo1, mezo2...)
select
case when domain = 'elsoweblapom.hu' then 'forras1'
when domain = 'masodikweblapom.hu' then 'forras2'
end forras,
mezo1,
mezo2,
...De akkor már elegánsabb lenne felvenni egy szótár táblát, amiben megadod a domain - forrás összerendeléseket, és ez alapján joinolod a selecteket.
Így már nem kell majd hozzányúlni a kódhoz amikor új forrást veszel fel, hanem csak egy új sort kell felvenni a forrasok táblába, és működni fog az új weblap is.create table forrasok (
domain varchar(100),
forras varchar(10)
);
insert into forrasok (domain, forras)
values ('elsoweblapom.hu','forras1');
insert into forrasok (domain, forras)
values ('masodikweblapom.hu','forras2');
insert into ujtabla (forras, mezo1, mezo2)
select f.forras, v.mezo1, v.mezo2
from html_valasz v
join forrasok f
on f.domain=v.domain
...
select t.*
from ujtabla t
join forrasok f
on f.domain = html_domain
where t.forras = f.forras
and ...Remélem érthető a gondolatmenetem.
Egyébként meg az ilyen mellényúlásokból tanul a legtöbbet az ember.
-
nyunyu
félisten
válasz
bambano
#4956
üzenetére
mondjuk az is relatív, hogy kinek mi a nagy adatbázis. a postgesql párszázmillió rekorddal még szépen elgurul
8 éve próbálkoztam az egyik mobilszolgáltató adattárházán dolgozni, aztán a DB műveletek query planjét logoló táblából (~napi 10 millió rekord?) kellett volna adatokat kinyernem egy adatvizualizációs projekthez.
Próbaképpen lekértem negyedórányi adatot, erre 10 perccel később jött a teradata üzemeltető leordítani a hajamat, hogy ilyet ne merjek még egyszer lekérdezni, mert letérdelt tőle a 24 node-os DWH, alig bírták kilőni a querymet.

Pedig előtte direkt megnéztem, milyen indexek vannak a táblán, meg mekkora a várható eredményhalmaz mérete, nehogy egyszerre túl sokat akarjak lekérdezni...
-
nyunyu
félisten
válasz
xabolcs
#4952
üzenetére
Még mindig nem jöttem rá, mi a logikája a /-ek elhelyezésének a telepítő szkriptekbe, hogy sqlplus kompatibilis legyen, így inkább minden DDL-t záró ; utáni sorba kirakom.

(Azt meg végképp nem értem, miért nem tudnak az üzemeltetők értelmes DB buherátort használni élesítéskor.)
-
nyunyu
félisten
Gondolom utólag akarsz arra is szűrni, hogy honnan származik az adat.
Most ha quick&dirty megoldást akarsz a meglévő táblákban lévő rekordok egy helyre lapátolására, akkor:
create table ujtabla as
select 'forras1' as forras, t1.*
from tabla1 t1;
insert into ujtabla
select 'forras2' as forras, t2.*
from tabla2 t2;
...
insert into ujtabla
select 'forras5' as forras, t5.*
from tabla5 t5;+ az eddigi kódban minden insertbe beleteszed, hogy az új rekordoknál mivel töltse a forras mezőt.
+ az eddigi táblaneveket mindenhol lecseréled ujtabla-ra
+ létrehozod az eddigi táblákra vonatkozó indexeket ujtabla-ra.Ekkor ha mondjuk külön akarnál selectálni a kettes rendszerből, akkor ezután így fog kinézni:
select *
from ujtabla
where forras='forras2'
and ...
order by date desc;lletve PHP oldalról megnézni, hogy az új struktúrájú lekérdezésben hogyan tudnám hatékonyan használni a bind_param-ot. (Ha kell/lehet-e egyáltalán.)
Nem vágom a PHPt, de gondolom a mezők bindelésénél ki kell cserélni a táblanevet az újra, valamint az új forras mezőnek fixen megadni egy értéket. (Mittudomén kettes webshopnál azt, hogy 'forras2', vagy aminek elnevezted)
-
nyunyu
félisten
De amúgy tényleg érdekelne, hogy miben/mennyivel "rosszabb", ha több táblában vannak az adatok. Nyilván a sebesség az egyik válasz, ez biztos. De érdekelne, miben még.
Leginkább a kód karbantarthatóságról szól a felvetésünk. (meg olvasni, átlátni is könnyebb a rövidebb, egyszerűsített kódot)
Most ha bejön egy új alrendszer/forrás, akkor kézzel definiálsz neki egy új táblát, arra indexeket, meg a meglévő kódbázisban az összes union-os selectet ki kell bővíteni +1 ággal, hogy az új forrást is visszaadja.
Plusz szopni fogsz, ha bármelyik táblába fel kell venni egy plusz mezőt, mert akkor kézzel alter table az összesre, hogy az unionok továbbra is működhessenek...Míg egy táblánál csak az új forrás adatbetöltő rutinját kell megírnod, ami egy új azonosítóval szúrja be a meglévő táblába a rekordokat.
Plusz oszlop igény esetén meg elég egy táblát alterelni, nem fog elszállni a kód (ha ki van mindenhonnan irtva a select *
) -
nyunyu
félisten
Úgy szeretném megcsinálni, hogy utána szerkezeti változás miatt ne kelljen már "soha" belenyúlni, ezért veszem a fáradságot és időt és átírom, ezzel nincs baj. Csak érteni is szeretném a miértjét.
Ha most nem léped meg a refaktort, és később kiderül, hogy valamelyik táblába fel kell venned pár plusz oszlopot, akkor az összesbe veheted fel egyesével ugyanazokat, ugyanabban a sorrendben, különben hibával elszáll az összes union-os lekérdezésed!
Mondjuk ebből a szempontból a select *-os slendriánság sem egy életbiztosítás

Sokkal elegánsabb, és hibatűrőbb, ha egyesével felsorolod a lekérdezendő oszlopokat + insertnél a beszúrandó tábla oszlopait.magyarul mindenhol így nézzen ki a kód:
insert into tábla (oszlop1, oszlop2, oszlop3)
select oszlop1, oszlop2, oszlop3
from tábla2;Ez nem fog megborulni, ha bármelyik tábla szerkezete módosul.
-
nyunyu
félisten
Akkor meg pláne most kéne meglépni az egy táblára átállást, mert 20 táblánál már sokkal több időt fog igényelni a refaktorálás.

Amire kell csak figyelni: összes a táblába szúró insertnél legyen kitöltve a forrásrendszer azonosító.
Aztán ha alrendszerenként nagyon sok adat van, és az adatbázis licenszed is megengedi, akkor el lehet gondolkozni a forrásrendszer azonosító menti partícionáláson, amikor partíció kulcsonként külön táblateret használ, és mindegyiknek külön épít indexeket.
Ekkor konkrét azonosítóra szűrve ugyanúgy viselkedik a nagy tábla, mintha önálló táblája lenne az alrendszernek viszonylag kicsi adatmennyiséggel, ha meg nem szűrsz, akkor az alrendszerek tábláinak unióját látod. (ez utóbbi nem annyira hatékony, ha a partíciókulcs nincs a join/where feltételben!) -
nyunyu
félisten
válasz
sztanozs
#4932
üzenetére
'NOT IN' elég pazarló (legalább is az én ismereteim szerint), persze lehet, hogy a modern motorok már átalakítják kevésbé lassabbakra.
Tizenéve már azt tanították az egyetemen, hogy mindegy, úgyis átalakítja left joinra az optimalizáló.
Gyors futáshoz LEGYEN index a vizsgált mezőn.A LIKE-ok meg szerintem mindegy milyen scope-ban futnak.
Na, az az igazán pazarló, pláne, ha %-gal kezdődik a lájkolnivaló, mert akkor semmilyen indexet nem tud használni hozzá, hanem mindig full table scan lesz a vége.
Ha csak 'valami%'-ra alkalmazod a facebook filtert (vagyis ismert a string eleje), akkor legalább a keresendő oszlopra rakott indexből tud dolgozni. -
nyunyu
félisten
Az 5 táblában 5 különböző forrásból származó bejegyzések vannak, jellemzően több száz (idővel több ezer), ezért vannak már eleve külön táblákba mentve.
Erre felesleges 5 táblát fenntartani, elég lenne egy tábla is, amibe felveszel egy pár karakteres új oszlopot, amibe az forrás azonosítóját írod, aztán ha forrásra kell szűrni, akkor beírsz plusz egy where feltételt a lekérdezésbe.
Amúgy meg kimaradt a külső select:
SELECT *
FROM
(SELECT * FROM table1
UNION ALL
SELECT * FROM table2
UNION ALL
SELECT * FROM table3
UNION ALL
SELECT * FROM table4
UNION ALL
SELECT * FROM table5)
WHERE ID NOT IN (...)
ORDER BY date DESC
LIMIT 4; -
nyunyu
félisten
Mi a ráknak van öt, tökegyforma táblába szétszedve az adat?
Teljesen felesleges, hacsak nincs sokmillió rekord, és időnként másik táblába archiváltok.
Gyorsan hízó logokhoz szerintem felesleges az unionnal bohóckodni, egyszerre úgyis csak egy logban akarsz keresni, hiszen nagyjából be tudod lőni, milyen dátum intervallumot akarsz vizsgálni.Meg az order by-t sem értem, mert ebben a formában csak az ötödik táblát rendezi csökkenőbe.
Először kapod az első táblát rendezetlenül, aztán a másodikat, aztán a harmadikat... végül az ötödiket rendezve.
Ha fontos az időben csökkenő rendezés, akkor én tennék egy select * from ( ) order by date desc-et az unionok köré. -
nyunyu
félisten
válasz
sztanozs
#4919
üzenetére
Csak hogy az Oracle szintaxis is meglegyen:
select szttorzsszam, sztnev, listagg(klnevhu, ',') within group(order by klnevhu) from szemelytorzs
left join bfkepzettsegimatrix on szemelytorzs.szttorzsszam = bfkepzettsegimatrix.kmtorzsszam
left join kepzettseglista on bfkepzettsegimatrix.kmkepzettsegid = kepzettseglista.klid where szttorzsszam = '1234'
group by szttorzsszam, sztnev; -
nyunyu
félisten
válasz
RedHarlow
#4904
üzenetére
Fizikailag belefűzni a sorvége karakter(eke)t a stringbe?
desc=desc || chr(13) || chr(10) || 'Adat: 1200'
Feltéve, ha Windows stílusú stringekkel dolgozol, ami CR+LF (\r\n)-rel van terminálva.
Unix/linux vonalon elég lehet a chr(13) (CR, \r), mac esetén a chr(10) (LF, \n) is -
nyunyu
félisten
válasz
Apollo17hu
#4902
üzenetére
Ezt passzolom, nem látok bele ennyire az SQL optimalizálók lelkivilágába.
Érzésem szerint rá kéne jönnie, hogy ugyanazt akarod számoltatni az group by-nál is, így a korábban kapott eredményhalmazt használja, de meg kéne nézni egy konkrét végrehajtási tervet, hogy változik-e ha kiírod az order by-nál a case-whent, vagy ha oszlopsorszámmal hivatkozod.
-
nyunyu
félisten
Új hozzászólás Aktív témák
- Vivo X300 Pro – messzebbre lát, mint ameddig bírja
- Redmi Pad 2 Pro / Poco Pad M1 - egy teszt, két lélek
- Bittorrent topik
- NVIDIA GeForce RTX 5070 / 5070 Ti (GB205 / 203)
- Gyúrósok ide!
- Épített vízhűtés (nem kompakt) topic
- Építő/felújító topik
- Android alkalmazások - szoftver kibeszélő topik
- Androidos tablet topic
- Kodi és kiegészítői magyar nyelvű online tartalmakhoz (Linux, Windows)
- További aktív témák...
- Akciós! Lenovo ThinkPad P15 Gen 1 Intel i7-10875H 32GB 512GB Nvidia Quadro RTX 3000 1 év garancia
- GYÖNYÖRŰ iPhone 13 Mini 128GB Starlight-1 ÉV GARANCIA -Kártyafüggetlen, MS4183, 100% Akkumulátor
- LG 27GR95UM - 27" MiniLED - UHD 4K - 160Hz 1ms - NVIDIA G-Sync - FreeSync Premium PRO - HDR 1000
- ÁRGARANCIA!Épített KomPhone i5 14600KF 16/32/64GB RAM RTX 5070 12GB GAMER PC termékbeszámítással
- darkFlash CF8 Pro
Állásajánlatok
Cég: Laptopszaki Kft.
Város: Budapest
Cég: PCMENTOR SZERVIZ KFT.
Város: Budapest









