Új hozzászólás Aktív témák
-
nyunyu
félisten
válasz
#29736192
#4834
üzenetére
Unió az VAGYlagos kapcsolatot jelent, ÉS meg metszetet.
Neked az kell, hogy egyik regexpnek sem felel meg, azaz -regexp1 ÉS - regexp2 ÉS -regexp3... (komplementerek/negáltak metszete!)
Ezt ha levezeted, akkor azzal egyenlő, hogy -(regexp1 VAGY regexp2 VAGY regexp3...) (unió komplementere/negáltja!)Mivel a táblák sorai között mindig VAGYlagos kapcsolat van (tábla a sorainak uniója!), így ez utóbbi azt jelenti, hogy az érték nincs a regexp tábládban.
A táblából meg úgy kapjuk meg a B-ben nem szereplő értékeket, hogy LEFT JOIN ... IS NULL. -
nyunyu
félisten
válasz
bambano
#4835
üzenetére
Ezzel viszont vissza is kanyarodtunk a kurzoron végigiterálós megoldáshoz, amit macerásabb megírni, mint az előbbi jólfésült selectet

nagy vonalakban valami ilyesmi:
declare
cursor c is
select regexp
from regexptabla
order by gyakorisag desc;
r varchar2(100);
begin
truncate temptabla;
open c
loop
fetch c into r;
exit when c%NOTFOUND;
insert into temptabla (voltmar)
select e.ertek
from eredetitabla e
left join temptabla t
on e.ertek = t.voltmar
where t.voltmar is null
and e.ertek ~ r;
end loop;
close c;
select e.ertek
from eredetitabla e
left join temptabla t
on e.ertek = t.voltmar
where t.voltmar is null;
end;(Nem vágom a postgre szintaxisát.)
-
nyunyu
félisten
válasz
#29736192
#4832
üzenetére
Jó lesz az, csak halmazokban kéne gondolkozni.
Neked a regexp kifejezések uniójának negáltja kell, nem a negált regexpek uniója!Vagyis left join on keresendo ~ regexp... where regexp is null.
bambano megoldását szabvány join szintaxisra átírva:
select keresendo
from keresendotabla
left join regexptabla
on keresendo ~ regexposzlop
where regexposzlop is null; -
nyunyu
félisten
válasz
#29736192
#4827
üzenetére
Dokumentációja szerint a Postgre SIMILAR TO/NOT SIMILAR TO/~/~* operátoroknak egy patternt lehet megadni.
Úgyhogy nem úszod meg tárolt eljárás nélkül:
Kurzorba teszed a pattern lista tartalmát.
Végigiterálsz a kurzoron, minden egyes lépésnél egy ideiglenes táblába leválogatod az eredeti táblából az aktuális patternre illeszkedő értékeket.
Végén meg egy jól irányzott left joinnal kiválogatod az eredeti táblából azokat az értékeket, amik a másodikban NEM szerepelnek. -
nyunyu
félisten
válasz
Micsurin
#4818
üzenetére
GRANTolni csak az tud, akié a tábla, vagy kapott rá GRANTolási jogot, vagy DBA júzer.
Akinek csak olvasási/írási joga van, az nem tudja azokat továbbadni!Ha hr séma/júzer alatt hoztad létre a táblákat, akkor hr júzerrel kell kiadni a GRANTokat.
Utána a többi júzer select * from hr.táblanév;-vel fogja elérni őket.
Egyébként a táblák listája nyilvános, bárki lekérheti a select * from dba_tables;-t.
Ha a select * from all_tables;-t kérdezed, ott csak azokat mutatja az Oracle, amikhez az aktuális júzernek joga is van. -
nyunyu
félisten
-
nyunyu
félisten
válasz
Micsurin
#4804
üzenetére
Egy tranzakcióban futó adatmanipulációs (DML) utasítások (insert, update, merge, delete...) hatását csak az őket futtató DB session látja, amíg a tranzakció nincs commitálva.
Mittudomén, van egy táblád, amiben van 10 rekord.
Nyitsz egy adatbáziskezelő ablakot, amiben kiadsz 5 insertet, meg 3 updateet, majd kiadsz egy select count(*) from tabla;-t, akkor az ott 15-öt fog mutatni.
Közben nyitsz egy másik ablakot, egy ott kiadott select * from tabla; az eredeti állapotot, 10 rekordot fog mutatni, a még nyitva lévő tranzakcióban hozzáadott ötöt, meg az updateek hatását nem!
Ha az első ablakban kiadsz egy commit;-ot (amivel véglegesíted az addig nyitott tranzakcióban futtatott DML utasítások hatását és lezárod a tranzakciót), akkor a második ablakbeli select *-ot újrafuttatva már 15, módosult rekord fog megjelenni.
Ha az első ablakban commit; helyett rollback;-et nyomsz, akkor teljesen eldobódik a nyitott tranzakcióban futtatott DMLek hatása, és visszaáll az eredeti állapotra.
Tehát ha utána kiadnál egy select *-ot, akkor ugyanazt a 10 eredeti rekordot látnád az első ablakban is, mint korábban a kettes ablakban.Adatdefiníciós (DDL) utasítások (pl. tábla létrehozás, eldobás, oszlop hozzáadás, index létrehozás...) mindig önálló tranzakcióban futnak és azonnal commitálódnak, így azok nem vonhatóak vissza kiadás után.
Meg ha jól rémlik, akkor az adott DB sessionben még függőben lévő tranzakciót is commitálják!Savepointokat még nem használtam, de ahogy olvasom arra jó, hogy rollbacknél meg lehessen mondani, hogy ne az egész addigi tranzakciót dobja el, hanem csak a savepoint után futtatott utasításokat.
Lehet, hogy valakik szerint ez jó ötlet, de alapvetően sérti a tranzakciók atomiságát, és jóval nehezebb egy félig lefutott tranzakció által elcseszett adatokat javítani, mint ha eldobnád az egészet a francba, és javítás után elölről újrafuttatnád az egészet.
-
nyunyu
félisten
válasz
Micsurin
#4789
üzenetére
Alapvetően jó a próbálkozásod, de az első JOIN feltétel után már ne használd a vesszőt a következő JOINolandó táblához/queryhez, hanem ott is írd ki megfelelő JOIN formulát.
(ne keverjük a régi és a szabványos JOIN szintaxist!!!)Picit olvashatóbbra rendezve:
SELECT er.last_name, er.salary, d.department_name, át.átg
FROM employees er
INNER JOIN departments d
ON er.department_id = d.department_id
INNER JOIN (SELECT department_id, ROUND(AVG(salary),2) AS átg
FROM employees
GROUP BY department_id) át
ON er.department_id = át.department_id
WHERE er.salary > át.átg;Példa megoldás gyakorlatilag ugyanez, csak nem használ benne aliasokat (amik a kód átláthatóságát, követhetőségét, érthetőségét növelik)
Ja, meg natural joint használ, csak azért hogy ne kelljen kiírnia az azonos oszlopok menti join feltételeket.
-
nyunyu
félisten
válasz
Micsurin
#4777
üzenetére
Első példádban:
SELECT e.department_id, last_name, legkisebb
FROM employees e,
(SELECT department_id, MIN(salary) legkisebb
FROM employees
GROUP BY department_id) min
WHERE e.salary=min.legkisebb AND e.department_id=min.department_id;"e" néven hivatkozik az employees táblára, míg az alquery eredményhalmaza a "min" aliast kapta.
WHERE után láthatod, hogy táblanév.oszlop vagy alias.oszlop formátummal lehet hivatkozni az egyes táblák vagy alqueryk elemeire.
Vagy a SELECT mezőlistájánál is azért van kitéve az e. az első mező elé, mert mind a táblában, mind az alqueryben van department_id, és az Oracle megköveteli, hogy egyértelműen megmondd, hogy melyik oszlopra hivatkozol.
(Másik két oszlopa önmagában is egyértelmű, mivel a "last_name" csak a táblában, "legkisebb" meg csak az alqueryben van meg.) -
nyunyu
félisten
válasz
Micsurin
#4783
üzenetére
Alquerykről annyit érdemes tudni, hogy az SQL nyelv szintaxisa úgy van felépítve. hogy minden helyre, ahol táblanevet vár, oda lehet zárójelek közé írni egy alqueryt, és akkor annak a querynek az eredményhalmazát fogja a táblaként használni a másik művelethez.
Így tudod pl. tovább szűrni az eredményeket, vagy pl. azzal joinolni.Az mondjuk DB implementáció függő, hogy az alqueryt bezáró zárójel mögé kell-e aliast írni, vagy sem (Oraclenél kötelező, MSnél nem)
Azzal az aliasszal tudsz majd a fő queryben az alquery mezőire/oszlopaira hivatkozni, mintha egy tábla oszlopaira hivatkoznál.Tranzakciók: azt meg kell érteni, mivel egy sokfelhasználós konkurens rendszerben nem lehet élni nélküle.
Adatoknak akkor is konzisztensnek kell maradniuk, ha sokan piszkálják őket egyszerre, vagy bármi hiba beüt.
Olyan nem lehet pl. egy félbeszakadt átutalásnál, hogy a pénzt levonták a számládról, de a fogadó oldalon meg nem jelenik meg, olyankor a bank nem tárhatja szét a karját, hogy bocs rendszerhiba volt, így jártál...Terminálos dolog?
SQLPlus? Tudom, hogy a nagyvállalati rendszeradminok kedvenc perverziója, hogy SQLPlusszal futtatható releaset kérnek, majd hozzádvágják a hibalogot, hogy fejtsd meg miért nem futott le (mit írtál el benne, vagy melyik 2 query közé nem tettél /-t, vagy milyen alternatív nyelv volt beállítva a termináljának...)
de fejlesztőként minimum egy (ingyenes) Oracle SQL Developer IDEt azért elvárhatna az ember a fejlesztéshez, ugyan nem a legjobb, de mégsem az SQLPlusszal kell szerencsétlenkedni.
-
nyunyu
félisten
Meg az exists egy olyan okossag, ami egesz jo hatekonysagot mutat, annak a probalgatasat is ajanlom.
Nem volt mindig így.
Tizenéve még kifejezetten kerülendő antipatternként tanították az EXISTS/NOT EXISTS párost, mivel régi DBken nagyon rosszul futottak.
Modern DBk optimalizálói viszont végrehajtás előtt át szokták alakítani LEFT JOINra, és úgy futtatják.
Szóval a
select *
from tabla1
where not exists (select id from tabla2);helyett már
select tabla1.*
from tabla1
left join tabla2
on tabla1.id = tabla2.id
where tabla2.id is null;végrehajtási tervét fogod látni, és futtatási sebességben sem lesz köztük különbség.
Régebbi/kevésbé fejlett optimalizálóval rendelkező DB motorokon viszont a második kód sokkal gyorsabban fut, mint az első.
-
nyunyu
félisten
válasz
Micsurin
#4777
üzenetére
Mi a rák az a natural join?
Utána kellett néznem, mert ilyet még nem láttam.
Azt írják, hogy az SQL:2011 óta opcionális nyelvi elem, nem kötelező implementálni. (Akkor azért nem láttam eddig.
)Mindenesetre arra jó, hogy a lustáknak ne kelljen kiírni a JOIN feltételeket, hanem a DB motorra bízzák az azonos nevű oszlopok összehasonlítását.
(magyarul az ON tábla1.id=tábla2.id elhagyható, vagy ha az oldschool from tábla1, tábla2 szintaxist használod, akkor WHERE mögül a tábla1.id=tábla2.id)Egyáltalán miért nem szabvány SQLt tanítanak?
Mikor BMEn különböző DB jellegű tárgyakat hallgattam, ott nagyrészt szabvány SQL volt, de megmutatták azon felül a legelterjettebb DBk szintaktikai különbségeit. (T-SQL (MS) vs PL-SQL (Oracle))Másik kérdésre meg az a válasz, hogy nincs különbség a 2 query között.
Első az oldschool formátumban van írva, amikor még nem volt szabványosítva a JOIN szintaxis, hanem minden DB kezelő a saját feje szerint toldozta-foltozta az akkor érvényes szabványt, így alakult ki a FROM után vesszővel felsoroljuk a táblákat, majd WHERE mögé kerülnek a JOIN feltételek szintaxis, amit elég sokan implementáltak anno ahhoz, hogy még ma is elterjedt legyen, emiatt az újabb DB kezelőkbe is bele szokták tenni. (Pl. SQL Server 2008-ba betették, mivel MS lőni akart a Teradata júzereire is)
Második meg az SQL92-ben definiált szabványos írásmód, amit minden DB kezelőnek ismernie kell.
Működésben nincs különbség a kettő között, mivel a DB SQL optimalizálója átrendezi a futtatandó kódot, ide-oda pakolászva a feltételeket, végül mindkettő szintaxisnak ugyanaz lesz a végrehajtási terve.
-
nyunyu
félisten
-
nyunyu
félisten
válasz
Micsurin
#4766
üzenetére
Most mit szeretnél?
Átlagár legyen 5 misi alatt?
Ehhez kell az oszlopfüggvények kiértékelése utáni eredményhalmazt szűrő HAVING, de ahhoz pontosan ugyanazt a képletet kell írni, mint ami a mezőlistánál van:SELECT allapot AS "Állapot", ROUND(AVG(ar),2) AS "Átlag ár"
FROM motorok
GROUP BY allapot
HAVING ROUND(AVG(ar),2) < 5000000;5 misi alattiakat átlagolni?
-> először 5M-re kéne szűrni WHERErel, és azt átlagolni:SELECT allapot AS "Állapot", ROUND(AVG(ar),2) AS "Átlag ár"
FROM motorok
WHERE ar < 5000000
GROUP BY allapot;WHERE mindig a rekordokat szűri, és a szűrt rekordokon futnak le a csoportosítások/számítások.
HAVING a már kész, kikalkulált eredményhalmazt szűri. -
nyunyu
félisten
Ha nagyon elegánsak akarnánk lenni, akkor:
select t.a, t.b
from tabla t
where t.a in (select t1.a
from tabla t1
join tabla t2
on t2.a = t1.a
and t2.b <> t1.b); -
nyunyu
félisten
Talán még ez a legegyszerűbb, de előző főnököm hivatalból rühellte a distinctet, úgyhogy olyat nagyon ritkán használunk.
Szerinte az adathibát javítani kell, nem eltakarni!
(Mostani melóhelyem viszont DWHt örökölt, úgyhogy javíthatatlan adathiba adathiba hátán a default felállás.)
-
nyunyu
félisten
válasz
olywer.smith
#4746
üzenetére
with max_rogzites as (
select id, max(rogzites_ideje) utolso_rogzites
from tabla
group by id)
select t.*
from tabla t
join max_rogzites m
on m.id = t.id
and m.utolso_rogzites = t.rogzites_ideje;Persze amilyen hülye vagyok, lehet, hogy írnék előtte egy create index tabla_ix1 on tabla (id, rogzites_ideje);-t is, hogy a BI se dögöljön bele, ha egy 100 millió soros táblából kell riportálnia az utolsó rögzített értékeket...
-
nyunyu
félisten
válasz
bambano
#4737
üzenetére
Van amikor a számítási/lekérdezési sebesség fontosabb, mint a redundancia.
Ha csinálsz egy aktuális raktár nézetet, amiben összejoinolod az eredeti raktár táblát a mozgatások szummájával, és ebből dolgozik a következő lépést meghatározó lépés, akkor minden egyes lépés kiértékelésénél a DBnek egyesével újra kell számolnia az eddigi lépések eredményét, ahelyett, hogy a letárolt köztes értéket használná.
Ez ugyan elegáns, de nem hatékony.(Épp most kínlódunk azzal, hogy mindenféle BI riportokat kell készíteni, de többszázezer soros táblákat kell joinolni, szummázni, és az eredmény kb. 40k sor/nap.
BI meg állandóan beledöglik, amikor így-úgy szűrve belekérdez a DBben tárolt nézetbe.
Úgyhogy írhatok egy jobot, ami naponta lefuttatja a kb. egy percig futó queryt, és insert into-zza egy táblába, aztán onnan fog select *-ozni a BI, nem az eddigi nézetből.) -
nyunyu
félisten
válasz
martonx
#4736
üzenetére
Bármely programnyelvbe beletartoznak a deklaratív nyelvek is, ahova az SQL is tartozik.
Deklaratív programozási paradigmánál az elemi adatokat/tényeket és a köztük lévő kapcsolatokat definiálod, majd ezek elemeire kérdezel rá ("szűrsz"), gép meg majd valahogyan megoldja.
Programozási nyelvek másik, nagyobb csoportja az imperatív nyelvek csoportja, ahol az egymás után következő elemi utasításokat/lépéseket rágod a gép szájába.Programozó részéről ezek két különböző megközelítést, gondolkozásmódot igényelnek.
(Ezért nem értem, mi a francnak erőltetik pl. a lambda-függvényeket a modern imperatív programnyelvekben. Hacsak nem az a cél, hogy elméleti matematikusok svájci bicskaként tudják használni a Java 8-at?) -
nyunyu
félisten
válasz
mr.nagy
#4732
üzenetére
Meg lehet csinálni SQLben is, csak kell hozzá egy tárolt eljárás, amiben :
- csinálsz egy kurzort a negatív raktárkészletekből csökkenő sorrendben (hova = id, mennyi = -val)
- CTASsal lemásolod az eredeti raktár táblát egy újba (hogy ne az eredetit updatelgesd)
- végigiterálsz a kurzoron
-- kiveszed az aktuális maximum értéket, és az id-ját a raktár_másolatból, és ha az nagyobb, mint a az aktuálisan kezelendő hiány, akkor
--- update raktár_másolat set val=val-mennyi where id=honnan;
--- update raktár_másolat set val=val+mennyi where id=hova;
--- insert into mozgások values (honnan, hova, mennyi);Végén megvan a raktár_másolatban a művelet utáni új raktárkészlet, mozgásokban meg a teendők listája.
Ettől még fenntartom azt, hogy Javaban egyszerűbb lenne lekódolni+gyorsabban is futna.
De pár bolt esetén nem biztos, hogy olyan nagy lenne SQLben sem a futási idő. -
nyunyu
félisten
válasz
mr.nagy
#4729
üzenetére
Ez tipikusan egy olyan probléma, amit nem biztos, hogy SQLben érdemes leprogramozni.
Gond az, hogy ha kiegyenlíted az első hiányt, akkor aktualizálnod kell a raktárkészletet, és csak utána tudod kezelni a második hiányt.
Ha a közbenső adatfrissítést kihagyod, akkor lehet, hogy a második hiányt is ugyanonnan vonnád le, ahonnan az elsőt, de arra viszont nem elég az eredeti készlet.Ennek inkább valami magasszintű nyelven állnék neki, mert (rekurzív) tákolt eljárással nem annyira triviális.
Mittudomén, Javaban FOR ciklussal végigmész a tömb elemein, ahol negatív értéket látsz, ott indul egy belső ciklus a tömb elemeire, és ahol a hiánynál nagyobb értéket lát, ott felveszi egy listába a [honnan, hova, mennyi] tripletet, valamint tömb[honnan]=tömb[honnan]-mennyi, tömb[hova]=tömb[hova]+mennyi.
Aztán ha végigért a külső ciklus, akkor a tömbben a raktárak közötti mozgatás utáni raktárkészlet lesz, meg a listában a szükséges mozgatások listája.Persze ezt meg lehet írni SQL eljárásban is, csak nem olyan elegáns.
Vagy a példádnál maradva lehet, hogy egyszerűbb lenne megkérni a boltokat, hogy a felesleges árucikkek felét küldjék vissza a következő áruszállításkor a központi raktárba, aztán onnan küldik tovább a begyűjtött holmit a hiánnyal küzdő boltokba.
-
nyunyu
félisten
válasz
DeFranco
#4723
üzenetére
"Sima" joint szokták inner joinnak is hívni, csak az inner és outer kulcsszavakat nem kötelező kiírni.
Az csak akkor ad adatot, ha a join feltétel mentén mindkét táblában van találat.Régi Oracle jelöléssel asszem az az oldal lehet null, ahova a (+)-t teszed.
tehát a from t1, t2 where t1.id=t2.id (+) az egy left (outer) join, t1-hez joinolja opcionálisan a t2-t.
from t1, t2 where (+) t1.id = t2.id meg right (outer) join akar lenni.
Ha sehova sem teszel (+)-t, akkor (inner) join. -
nyunyu
félisten
Egyébként ettől a where-es egyenlő dologtól kiráz a hideg, pedig még az iskolában is így tanították a táblák join-ját.
Na igen, mert némelyik DBben régen úgy kellett joinolni a táblákat, hogy FROM után felsoroltad őket, majd WHERE után a feltételek.
Aztán jött a szabványos JOIN írásmód, ami ezzel ekvivalens, de sokkal olvashatóbb.Én meg a WHERE t2.id=t1.id (+) feltételtől kaptam hülyét, hogy akkor ez most left vagy right join, melyik táblát joinoljuk melyikhez?
Nem szeretem ezt a régi Oracle szintaxist, inkább szabványosat írok.
-
nyunyu
félisten
Az a baj, hogy a nagyon korai, huszonévvel ezelőtti Teradata szintaxis ilyen galádságokat is megengedett:
update t1
set column=t2.column
where t2.id=t1.id;Vakarhattam egy darabig a fejemet, amikor SQL parsert kellett a naponta futó DWH kódok felméréséhez írnom, hogy ez vajon mi a francot jelent.

Ehhez képest a későbbi, FROMmal turbózott szintaxisuk kifejezetten olvasható.
Tudom, Oracle sem szabványos, de a szabvány SQL dialektikát azért nagyjából érti.
-
nyunyu
félisten
válasz
DeFranco
#4711
üzenetére
Összeadni-kivonni a különböző alqueryk eredményeit csak annak a query mezőlistájában tudod, amelyik queryben definiáltad az aliasokat:
SELECT
K.[munkavállaló] "MUNK"
KHD.[érték]/AHD.[érték] AS "KPERA"
KH.[hónapazonosító] AS "HO"
FROM (select munkavallalo, ...
from ...
where ...) K
JOIN (select munkavallalo, ertek ...
from ...
where ...) KHD
ON KHD.munkavallalo = K.munkavallalo
JOIN (select munkavallalo, ertek ...
from ...
where ...) AHD
ON AHD.munkavallalo = K.munkavallalo
JOIN (select munkavallalo, ho ...
from ...
where ...) KH
ON KH.munkavallalo = K.munkavallaloN+1-edik joinolt alselect nem hivatkozhat az előző alselectek mezőire, mert Oracle alatt nem látják egymás változóit a különböző aliasolt nézetek.
(Kivéve CTE kifejezést írva, ott használhatod joinra a korábban definiált másik alselectek aliasait.)(Előbb emlegetett Teradata DWH queryjeiben az aliasok globálisan láthatóak az egész queryben, nem csak az őket hivatkozó szinten.
Ja, plusz ott mező alias is hivatkozható, pl. select 1+1 as a, a+1 as b; simán visszaad A=2, B=3-at, Oracle meg szintaktikai hibát dob
) -
nyunyu
félisten
Ja igen, MS az SQL Server 2008 környékén nekiállt implementálni a Teradata szintaxist *, hátha át tud csábítani pár DWH júzert a méregdrága Teradatától.
De attól ez még nem szabványos, Oracle alatt biztosan NEM megy.
*: szabványos UPDATEben NINCS FROM, nem lehet táblákat felsorolni/joinolni.
-
nyunyu
félisten
válasz
RedHarlow
#4712
üzenetére
Ezt a Teradata féle joinnal bővített UPDATE szintaxist semelyik másik DB kezelő nem ismeri, nem tudsz így másik tábla alapján updatelni.
Oracle elég körülményesen tud hasonlót, SET+WHERE mögé írt alselecttel, de annak a pontos szintaxisára nem emlékszem, de arra igen, hogy amihez nem talál értéket, ott szimplán NULLlal felülírja a többi sort.

Valami ilyesmi lehetett:
UPDATE t1
SET t1.column=(SELECT column FROM t2 WHERE t2.id=t1.id)
WHERE t1.id IN (SELECT id FROM t2);(Teradata csak a joinnal megtalált sorokat updateli, többit békén hagyja!)
Legtisztább megoldás erre a szabványos MERGE utasítás:
MERGE t1
USING (SELECT id,
column
FROM t2) t2
ON (t2.id = t1.id)
WHEN MATCHED
THEN UPDATE SET t1.column = t2.column;Hmm, még alselect se kell az USING mögé, direktben is mehet a t2, ha a joinon kívül nem kell semmi bonyolultat csinálni vele:
MERGE t1
USING t2
ON (t2.id = t1.id)
WHEN MATCHED
THEN UPDATE SET t1.column = t2.column; -
nyunyu
félisten
FROM (select munkavallalo, ...
from ...
where ...) K
JOIN (select munkavallalo, ...
from ...
where ...) KHD
ON KHD.munkavallalo = K.munkavallaloErre gondoltam múltkor, amikor azt írtam, hogy tetszőleges select köré lehet zárójelet tenni, és az alquery mögéírt aliasnevet táblaként használni, ahol az SQL szintaxisa táblanevet vár.
Csak a korábbi példánál még nem értettem, hogy mit akarsz joinolni hova.
-
nyunyu
félisten
válasz
DeFranco
#4708
üzenetére
Jó, de hogy csatolod az aliasolt alqueryket a fő queryhez?
CTE szintaxissal libasorban?
with k as
(select munkavallalo, ...
from ...
where ...),
khd as (
select munkavallalo, ...
from ...
where ...),
ahd as (
select munkavallalo, ...
from ...
where ...),
kh as (
select munkavallalo, ...
from ...
where ...)
-- innentol a "fo" query
SELECT
K.[munkavállaló] "MUNK"
KHD.[érték]/AHD.[érték] AS "KPERA"
KH.[hónapazonosító] AS "HO"
FROM K
JOIN KHD
ON KHD.munkavallalo = K.munkavallalo
JOIN AHD
ON AHD.munkavallalo = K.munkavallalo
JOIN KH
ON KH.munkavallalo = K.munkavallalo
)
PIVOT
(
SUM(KPERA)
FOR HO IN (...)
)Vagy oldschool módon?
SELECT
K.[munkavállaló] "MUNK"
KHD.[érték]/AHD.[érték] AS "KPERA"
KH.[hónapazonosító] AS "HO"
FROM (select munkavallalo, ...
from ...
where ...) K
JOIN (select munkavallalo, ...
from ...
where ...) KHD
ON KHD.munkavallalo = K.munkavallalo
JOIN (select munkavallalo, ...
from ...
where ...) AHD
ON AHD.munkavallalo = K.munkavallalo
JOIN (select munkavallalo, ...
from ...
where ...) KH
ON KH.munkavallalo = K.munkavallalo
)
PIVOT
(
SUM(KPERA)
FOR HO IN (...)
)Elvileg mindkettő szabványos, menniük kellene.
(Még oldschoolabb, FROM után vesszővel felsorolt () K, () KH, () KHD, () AHD majd WHERE után a join feltételek szintaxis az nem szabványos, nem minden DB ismeri.
Az valami Teradata hagyaték lehet a JOIN szabványosítása előttről?) -
nyunyu
félisten
válasz
DeFranco
#4706
üzenetére
igen csak itt az általad leírt selectben már eleve aliasolt selectek a "táblaazonosítók" (K, KHD, KH, AHD)
Gondolom mindegyik alselectben be van rakva a munkavallalo azonosítója, ami mentén joinolhatóak a selectek által visszaadott virtuális táblák.
Szóval:
...
FROM K
JOIN KHD
ON KHD.munkavallalo = K.munkavallalo
JOIN KH
ON KH.munkavallalo = K.munkavallalo
JOIN AHD
ON AHD.munkavallalo = K.munkavallalo
...Ha nincs, akkor mindegyik alquerybe legyen beletéve!
-
nyunyu
félisten
válasz
DeFranco
#4704
üzenetére
Tetszőleges select köré lehet zárójelet tenni, majd eléírni egy másik selectet, aztán az egészet joinolni egy újabb táblával a belső selectből kijövő tetszőleges oszlopra:
SELECT *
FROM (
SELECT
K.[munkavállaló] "MUNK"
KHD.[érték]/AHD.[érték] AS "KPERA"
KH.[hónapazonosító] AS "HO"
FROM
???
) a
JOIN b
ON b.valami=a.kpera
PIVOT
(
SUM(KPERA)
FOR HO IN (...)
)Lényeg az, hogy a zárójel után adj az alquerynek egy aliast, azzal tudod a külső selectben hivatkozni a mezőit.
-
nyunyu
félisten
válasz
DeFranco
#4701
üzenetére
Ja, hogy az osszeget is aggregálni akarja az egyed_azonosito mentén?
Akkor használj valami oszlopfüggvényt az osszeg oszlopra, és akkor nem fog beszólni érte.Mondjuk: sum(ertek)/min(osszeg)
(Mivel ugyanahhoz az egyed_azonosito osszes sorához ugyanaz az osszeg joinolódik, mindegy, hogy min() vagy max()-ot használsz aggregálásra)
Ez azért van, mert a pivotnál mindent sorfejlécnek értelmezünk ami nincs benne a sum és a for mezőkben és az a lekérdezés sorrendje szerinti hierarchiában alábontást jelent?
PIVOT az gyakorlatilag group by-ol az oszlopfüggvényekben és a FORnál sem hivatkozott oszlopokra, azokból fog állni a fejléc, majd a FOR után felsorolt értékekből.
Ezek alá teszi be a "group by" értékeit változatlanul, melléjük az oszlopfüggvényekkel számolt aggregált értéket a FORban felsorolt oszlopok szerint szétválogatva.Esetedben az egyes oszlopok tartalma ez lesz:
- egyed_azonosito
- (select sum(ertek)/min(osszeg) where csoport_kepzo='A' group by egyed_azonosito) as 'A'
- (select sum(ertek)/min(osszeg) where csoport_kepzo='B' group by egyed_azonosito) as 'B'
- (select sum(ertek)/min(osszeg) where csoport_kepzo='C' group by egyed_azonosito) as 'C'
- ...
Mintha egy rakat group_by lenne egymás mellett, különböző where feltétellel. -
nyunyu
félisten
válasz
DeFranco
#4699
üzenetére
Csak tipp: felső selecthez hozzájoinolod az egyedenkénti szummát egy új oszlopba, majd ezzel az értékkel osztod lent a sum(ertek)-et?
select * from (
with egyed_osszeg as
(select egyed_azonosito,
sum(ertek) osszeg
from tabla
group by egyed_azonosito)
select t.egyed_azonosito,
t.csoport_kepzo,
t.ertek,
o.osszeg
from tabla t
join egyed_osszeg o
on t.egyed_azonosito = o.egyed_azonosito
)
pivot
( sum(ertek)/osszeg
for csoport_kepzo in ('A','B'...)
) -
nyunyu
félisten
Probléma az, hogy a WHERE után írt feltétel az globális.
Ha oda azt írja, hogy t19.ertek>19, akkor minden olyan rekordot vissza fog adni, ahol ez teljesül.
NULL értékekre definíció szerint <,=,> hasonlítás sem teljesül, emiatt kiszűri azokat, ahol csak a T20 táblában lenne jó érték, de a T19-ben nincs.LEFT/RIGHT/FULL JOINkor emiatt fokozottan figyelni kell a NULLokra.
Tehát valami ilyesmit tud csinálni, hogy
where (t19.ertek is null OR t19.ertek>19)
and ... többi feltétel. -
nyunyu
félisten
Lehet, hogy az első logikája érthetőbb lenne CTE szintaxissal:
with utolso_tankolas as
(select rendszam,
max(datum) max_datum
from tankolas t
group by rendszam)
select
t.datum,
t.rendszam,
t.km
from tankolas t
join utolso_tankolas t2
on t.rendszam = t2.rendszam
and t.datum = t2.max_datum; -
nyunyu
félisten
válasz
Petya25
#4684
üzenetére
Először le kéne válogatni rendszámonként az utolsó dátumot, majd azokhoz a rendszám-dátum párosokhoz tartozó km értéket kikeresni a táblából.
Alselect helyett joinnal:
select
t.datum,
t.rendszam,
t.km
from tankolas t
join (select rendszam,
max(datum) max_datum
from tankolas t
group by rendszam) t2
on t.rendszam = t2.rendszam
and t.datum = t2.max_datum;Vagy rendszámonként besorszámozod dátum szerint csökkenőbe, és minden rendszámhoz az első rekordot veszed:
select datum,
rendszam,
km
from (select datum,
rendszam,
km,
row_number() over (partition by rendszam order by datum desc) rn
)
where rn=1;Egyébként ha meg feltételezzük, hogy a km állás monoton növekvő (magyarul nem szokták babrálni az órát), akkor egyszerűbben is lehet, hiszen a max(datum) és a max(km) érték ugyanazon a rekordon kéne hogy legyen:
select rendszam,
max(datum) datum,
max(km) km
group by rendszam;De ilyet ne feltételezzünk, mert a valóság az, hogy ahány adatrögzítő, annyiféleképpen sikerült bevinnie az adatot az évek során.
-
nyunyu
félisten
Egyáltalán kell egy plusz lekérdezés az Oracle specifikus from dual szintaxissal?
Nem lenne egyszerűbb egy
select nvl(count(*),0) from tablanev;[szerk:]Hmm,Oracle 11G2 amúgy is 0-t ad vissza count(*)-ra, ha nincs egy rekord se a táblában, nem NULL-t.
-
nyunyu
félisten
Akár alselectet is lehetett volna írni:
SELECT *
FROM items
WHERE type=477
AND status='OPEN'
AND id in (SELECT id
FROM items
GROUP BY id
HAVING COUNT(*) = 1)Elvileg ez ekvivalens az előző, joinolt megoldással.
#4660: Szerintem a kérdés direkt van ilyen egyszerűre fogalmazva, hogy meg lehessen oldani subquery meg analitikus függvény nélkül.
Szerintem meg észre kéne venni, hogy ez a feladat két lépésből áll, először leválogatni az egyelemű tételeket, majd azokon szűrni.
Ha egy selectben szűrsz és számolsz, akkor fals eredményt fogsz kapni, mivel a szűrt eredményhalmazt fogja megszámolni, nem a teljes táblát.
(Először a WHERE értékelődik ki, és csak utána a HAVING)-> vagy alselect vagy join kell.
-
nyunyu
félisten
válasz
Szancsó
#4646
üzenetére
Én kiemelném egy CTEbe az A, B összege oszlopokat, és kapna egy sorszámot összeg szerint csökkenő sorrendben, majd következő lépésben ebből válogatnám le a sorszám<=5-öt ("top 5"), és hozzáunióznám a szumma(B összeg)-et, ahol sorszám>5.
Így az eredeti táblát csak egyszer kell végigolvasni, második lépésben uniót képző 2 select már a memóriában lévő párszáz-ezer soros aggregátumból dolgozik, minimális többletköltséggel.
Valahogy így:
with summa as (
select a,
sum(b) sum_b,
row_number() over (partition by a order by sum(b) desc) rn
from tabla5
group by a),
top5_summa as (
select a,
sum_b,
rn
from summa
where rn<=5
union
select 'Többi' as a,
sum(sum_b) as sum_b,
6 as rn
from summa
where rn>5)
select a,
sum_b
from top5_summa
order by rn;Nem tudom, Firebird ismeri-e ezt a szintaxist, SQL Server kb. 2005 óta igen, meg az Oracle 11 alatt is működik.
-
nyunyu
félisten
tábla1.oszlop1 LIKE '%valami%' miatt mindig full table scan lesz, nem tud semmilyen indexet használni a joinhoz.
Míg ha tábla1.oszlop1 LIKE 'valami%' -t írnál (vagyis a string elején keresel, nem közben), akkor a tábla1.oszlop1-re tett index használható lenne, és nem kellene mindig végigolvasnia az egész táblát.
-
nyunyu
félisten
Állami hivatal, napjainkban futó pármilliárdos IT tender.
Valamelyik nagyokos kitalálta, hogy Enterprise Architectben jól lemodellezi az egész rendszert, és megrajzolt egy olyan infrastruktúrát és adatmodellt, aminek az egyik fele felesleges, másik fele meg használhatatlan.
Hivatal IT osztálya persze ellenkezett, hogy ez így megvalósíthatatlan, kivitelezhetetlen, de hát nem ők voltak a döntéshozói szerepkörben, így el lett fogadva.
Megvalósítani meg úgyis a beszállítóknak kell...A hivatalnak van saját sokoldalas fejlesztési standardja, ami előírja a beszédes nevek használatát, minden objektumnak kell legyen egy _id végű egyedi kulcsa, minden mezőnév a táblanévvel kezdődik, stb.
Ezektől eltérni nem lehet, mert deploy előtti ellenőrzésen fennakad a kód, nem telepítik, ha valamelyik követelménynek nem felel meg.Lényeg: EAban szereplő adatmodellből generálják az objektumokat létrehozó szkripteket.
Probléma azzal még nincs, hogy a beszedes_elso_tablanev_elso_mezoje túl hosszú lenne, hanem azzal, hogy a külső kulcsok neve táblanév1_táblanév2_id alakú, illetve az N:M relációk leírásához szükséges táblák neve is konkatenálódik: táblanév1_táblanév2.
Így a benne lévő táblanév1_mezőre visszamutató mező neve elso_tabla_neve_masodik_tabla_neve_elso_tabla_neve_mezo_neve lesz.Ennek persze az lett az eredménye, hogy az EAból generált szkripteket a meglevő Oracle 12.1 rendszerük nem bírta lefuttatni, mert nem fértek bele a 30 karakteres tábla és oszlopnév limitjébe.
Főnököm felvetette, hogy akkor leimplementáljuk mi az adatmodellt, értelmesen rövidített táblanevekkel.
Na azt nem lehet, mert akkor nem felelünk meg az EAban leírt terveknek.Jó, akkor módosítsátok az EAban lévő adatmodellt úgy, hogy a konkatenált nevek is beleférjenek a 30 karakterbe.
Nem lehet, túl sok munka, meg már a projekt többi részéhez is hozzá kéne nyúlni.Harmadik opció?
DB upgrade, de annak jelentős szoftverlicensz vonzata van.Azóta a projekt alatt Oracle 19 dübörög, mivel annak a költségét egyszerűbb volt átverekedni az ilyen-olyan bizottságon, mint a szent és sérthetetlen (hetente ötször változó) haditervet módosítsák, mert az utóbbi annak a beismerése lett volna, hogy a terv alapból szar.

Akarom mondani a DB frissítés kisebb projekt kockázattal járt, mint a tervet módosítani.
-
nyunyu
félisten
Pár éve az egyik mobilszolgáltató adattárházának betöltő jobjait kellett géppel feldolgoznom, ott láttam mindenféle cifra tördelést, meg extrém szintaxist a huszonéve toldozott kódban.*
Mostani melóhelyen is látom a kollégák kódolási stílusa közti különbségeket:
- kulcsszavak kis vagy nagybetűvel (select vs SELECT)
- hány szóközt használ behúzásra 2? 3?
- egy oszlopba rendezi-e a mezőneveket, aliasokat, kommenteket, vagy ahogy esik, úgy puffan
- hova teszi a vesszőt felsorolásnál:
a,
b
vagy
a
, b
(utóbbit nem szeretem, mert ronda, de könnyebb --szal kikommentezni, ha nem kell a második sor!)
- használ-e vessző után szóközt
- használ-e az egyenlőségjel, kacsacsőr körül szóközt (a=b vs a = b)
- van aki minden WHERE alatti sorba 1=2 AND-ot ír (így nem tud véletlenül elindítva lefutni a kód), aztán ha véglegessé vált a query, csak akkor kommentezi vagy törli ki.Nekem mindegy, amíg legalább annyira tördelve van, hogy el lehessen olvasni.
*: UPDATE a SET mezo=b.mezo2 WHERE a.id=b.id; megfejtését kérném OLVASHATÓAN, SQL:2003 szintaxissal leírni a válaszokban.

-
nyunyu
félisten
válasz
kw3v865
#4617
üzenetére
Ha az a cél, hogy egy külső alkalmazás paraméterezetten hívjon egy eljárást/függvényt, akkor nem tudod refcursorral visszaadni a szűrt halmazt?
Legalábbis mi Oracle 11g alapon így szoktuk visszaadni az adatokat:
procedure get_order_status(p_group_id number, p_posting_id number, p_id number, p_order_num varchar2, c out sys_refcursor) is
begin
open c for
select
i.group_id,
i.posting_id,
i.id,
i.order_num,
o.status as status,
to_char(o.status_dt,'yyyy-mm-dd hh24:mi:ss') as status_ts
from input i
left join s_order o
on o.order_num= i.order_num
where i.id = p_id
or i.group_id = p_group_id
or i.posting_id = p_posting_id
or i.order_num = p_order_num;
end;Aztán Javaban fetchelik a kurzort.
-
nyunyu
félisten
Közben találtam egy másik megoldást, ami nem a JOINnál szűr, hanem CASE WHEN-ekkel pakolja külön oszlopokba az egyes tételeket:
SELECT p.projectName 'Project Name',
SUM(CASE WHEN pc.costCategory='Cost category1' THEN pc.cost ELSE 0 END) 'Cost category1',
SUM(CASE WHEN pc.costCategory='Cost category2' THEN pc.cost ELSE 0 END) 'Cost category2',
SUM(CASE WHEN pc.costCategory='Cost category3' THEN pc.cost ELSE 0 END) 'Cost category3',
SUM(CASE WHEN pc.costCategory='Cost category4' THEN pc.cost ELSE 0 END) 'Cost category4'
FROM Project p
LEFT JOIN ProjectCost pc
ON pc.projectID=p.projectID
GROUP BY p.projectName
ORDER BY p.projectName;De ez sem sokkal olvashatóbb

Jut eszembe, hasonló példával szívatott a mostani főnököm 3 éve állásinterjún.
Aztán nemsokkal később belebotlottam kolléga kódjába, ami 10 attribútum nevét és értékét feszíti ki egy termék sorra ugyanígy
Azóta sem mertem átírni PIVOTra. -
nyunyu
félisten
Ez így nem jó, mivel ő az egyes costCategory alá tartozó tételek összegét külön-külön oszlopban szeretné látni.
Meg lehet csinálni PIVOT() nélkül is, oszloponként külön JOINnal:
SELECT p.projectName 'Project Name',
SUM(pc1.cost) 'Cost category1',
SUM(pc2.cost) 'Cost category2',
SUM(pc3.cost) 'Cost category3',
SUM(pc4.cost) 'Cost category4'
FROM Project p
LEFT JOIN ProjectCost pc1
ON pc1.projectID=p.projectID
AND pc1.costCategory='Cost category1'
LEFT JOIN ProjectCost pc2
ON pc2.projectID=p.projectID
AND pc2.costCategory='Cost category2'
LEFT JOIN ProjectCost pc3
ON pc3.projectID=p.projectID
AND pc3.costCategory='Cost category3'
LEFT JOIN ProjectCost pc4
ON pc4.projectID=p.projectID
AND pc4.costCategory='Cost category4'
GROUP BY p.projectName
ORDER BY p.projectName;Itt az egyes JOINoknál szűröm a costCategory értékét, hogy az adott oszlopban melyik értékhez tartozó tételek látszanak (amiket aztán szummázunk).
PIVOT()-tal rövidebben, tömörebben lehet ugyanezt megcsinálni, viszont a mit írjak a FOR és IN részekhez megértése elsőre nehéz lehet.
-
nyunyu
félisten
válasz
OldBoyDev
#4610
üzenetére
Sorok oszlopokká forgatásához a PIVOT függvény kell, de azt nem minden DB kezelő ismeri.
Szintaxisa valahogy így néz ki:
SELECT p.projectName, pc.costCategory, pc.cost
FROM Project p
LEFT JOIN ProjectCost pc
ON pc.projectID=p.projectID
PIVOT(
SUM(pc.cost) sum
FOR(pc.costCategory)
IN('Cost category1', 'Cost category2', 'Cost category3', 'Cost category4')
)
ORDER BY p.projectName;Gyakorlatilag a FOR-nál megadott costCategory mező értékkészletét válogatja szét, és csinál belőlük új oszlopokat az IN-nél megadott sorrendben, és ezekbe az oszlopokba teszi a FOR előtti oszlopfüggvény értékét.
PIVOT()-on belül sehol nem említett oszlopok (projectName) pedig maradnak úgy ahogy van.
-
nyunyu
félisten
Jut eszembe, MS platform téren meg a NetAcademiának voltak képzései.
Nem tudom az SQL Server 2017 Admin képzésük milyen lehet. -
nyunyu
félisten
Utóbbi pár évben járt nálunk pár webváltós arc, többek között Oracle fejlesztők és egy DBA is.
Fő profiljuk elvileg az oktatás, céges tanfolyamok szervezése, de szoktak cégekhez szakértőket és/vagy frissen képzetteket kölcsönözni is. (Kb. mint a csapból is csöpögő IT gyorstalpalók: GreenFox, Training360)
[szerk:]Hmm, fél misi náluk egy egyhetes (40 óra) Oracle DBA tanfolyam?
Kb. annyi, mint a feljebb linkelt Számalknál. -
nyunyu
félisten
Egyáltalán kellhet valamihez a right join?
Vagy csak én kezdem mindig a fix adattartalmú táblákkal a lekérdezést, és ahhoz left joinolom az opcionálisakat?
Legalábbis az én fejemben ez a kettő ekvivalens:
select a.*,b.*
from a
right join b
on b.id=a.id;
select a.*,b.*
from b
left join a
on a.id=b.id;(Sima select * esetén az adattartalom ugyanaz lenne, csak a táblák oszlopainak sorrendje változna.)
-
nyunyu
félisten
válasz
sztanozs
#4573
üzenetére
Group by után minden olyan mezőt fel kell sorolni, ami nem szerepel az oszlopfüggvények paraméterében.
Ha van egy fixen 'kiscica' oszlopod, akkor azt is.
Értelmes interpreterrel bíró DBken valahogy így nézne ki:
select "osszesen" ad, ID, null nev, sum(ertek) ertek1, null ertek2, null ertek3, null ertek4,
null ertek5
from tabla
group by id, ad, nev, ertek2, ertek3, ertek4, ertek5;Kevésbé értelmeseken valahogy így:
group by id, 1, 3, 5, 6, 7, 8;(Ha már a hülye Oracle nem tud alias alapján rendezni, csoportosítani, csak oszlopszámmal...)
-
nyunyu
félisten
Jut eszembe, ezt is lehetne egyszerűbben írni:
SELECT
y.nev,
MAX(ar) max_ar
FROM t_cikk x
INNER JOIN t_tarsasjatek y
ON x.tarsasjatek_id = y.id
GROUP BY y.nev
ORDER BY MAX(ar) DESC;De amennyire emlékszem Oracle nem nagyon szokta szeretni, ha számolt oszlopokra próbál rendezni az ember, sokszor kaptam hasonló próbálkozásokra szintaktikai hibát, emiatt írtam inkább köré egy másik selectet a rendezéssel.
Más adatbáziskezelők rugalmasabbak ebben.
-
nyunyu
félisten
Alapvetően jó az elképzelés, de ezt lehet egyszerűbben is írni, mivel joinolt táblákat is tudsz szummázni:
SELECT
vasarlo.id,
vasarlo.nev,
sum(vasarlas.darab*vasarlas.vetelar) koltes_osszesen
FROM t_vasarlo vasarlo
INNER JOIN t_vasarlas vasarlas
ON vasarlas.vasarlo_id = vasarlo.id
GROUP BY vasarlo.id, vasarlo.nev; -
nyunyu
félisten
válasz
Jim Tonic
#4548
üzenetére
Ja tényleg, ablakozó függvényekkel lehet, hogy egyszerűbb, mivel ott összetett rendezést is tudsz alkalmazni:
select
p.product,
p.price
from products p
join (select
p1.product,
nvl(p2.valid_from, to_date('0000-01-01')) valid_from,
nvl(p1.valid_to, to_date('9999-12-31')) valid_to,
row_number() over (partition by p1.product
order by nvl(p2.valid_from, to_date('0000-01-01')) desc,
nvl(p1.valid_to, to_date('9999-12-31')) asc) rn
from products p1) b
on b.product = p.product
and b.valid_from = nvl(p.valid_from, to_date('0000-01-01'))
and b.valid_to = nvl(p.valid_to, to_date('9999-12-31'))
and b.rn = 1;Ezzel sorszámozod az egy termék rekordjait kezdő dátum szerint csökkenő és azon belül érvényességi dátum szerint növekvő sorrendben, majd veszed a legelső rekordot minden termékhez.
-
nyunyu
félisten
válasz
Jim Tonic
#4545
üzenetére
Ezeket egy selectben nem tudod összeszedni, mivel az oszlopfüggvények egymástól függetlenül értékelődnek ki.
Tehát nem max(valid_from)-hoz tartozó min(valid_to) értéket kapod vissza, hanem a globálisat.Maximum azt tudod tenni, hogy egy belső selectben leválogatod a max(valid_from)-okat minden termékhez, majd az a köré írt másik selectben kiveszed a min(valid_to)-t.
Valahogy így:
select product,
price
from products p
join (select
p1.product,
a.max_valid_from,
min(nvl(p1.valid_to, to_date('9999-12-31'))) min_valid_to
from products p1
join (select p2.product,
max(nvl(p2.valid_from, to_date('0000-01-01'))) max_valid_to
from products p2
group by p2.product) a
on a.product = p1.product
and a.max_valid_from = p1.valid_from
group by p1.product, a.max_valid_from) b
on b.product = p.product
and b.max_valid_from = nvl(p.valid_from, to_date('0000-01-01'))
and b.min_valid_to = nvl(p.valid_to, to_date('9999-12-31'));Oszlopfüggvények alapból figyelmen kívül hagyják a nullokat!
-
nyunyu
félisten
válasz
martonx
#4538
üzenetére
Egyébként MySql-nek (meg amúgy bármelyik SQL-nek) tök jól lehet paraméterezni a memória foglalását.
A teljesítmény rovására.
Nézz meg egy ingyenes, egy procimag+1GB RAMra limitált MS SQL licenszet, meg a rendes verzióját.
DB tipikusan olyan alkalmazási terület, ahol a több RAM mindig jobb.
Persze ha van három táblád, 10-10 sorral, akkor az 1GB is elég lehet, de párezer soros táblák joinolgatásánál már észreveszed a különbséget.
-
nyunyu
félisten
Egy 2008->2012 frissítésért is kuncsorogni kellett

Mielőtt Móricka azt képzelné, hogy régi DBn backup, aztán új szerveren restore, és máris megy minden, mint a karikacsapás, ennél nagyobbat nem is tévedhetne.

Annó egyik ügyfelünk nagyon nyüstölt minket az SQL Server 2000 miatt, hogy 2011-ben nem kéne már használni, aztán új DB szerver telepítésekor upgradeltette a rendszerét 2008R2-re.
Akkor a DBAink vagy egy fél hónapot reszelhették a régi kódot, hogy normálisan működjön a hárommal újabb DB verzióval, mivel felülről kompatibilitás ide vagy oda, az új DB motor sokmindent másképp optimalizált/futtatott, mint a régi.
Úgyhogy lehetett végignyálazni az indexeket, hinteket, meg utánaolvasni a 2008R2 újításainak, mivel a DBAnk főleg 2000-hez értett, meg kisebb részben 2005-höz. -
nyunyu
félisten
Ha jól értem, itt kőkemény gazdaságossági kérdések is bejátszanak.
Nektek kell eldönteni, hogy mire akartok költeni:
- újabb, erősebb vas
- toldozzátok-foltozzátok a régi kódot, hátha jobban fut az elégtelen vasonÍrtad, hogy van DBAtok.
Nem az ő dolga lett volna eddig kielemezni a rendszer gyenge pontjait, és azon optimalizálni?
Akár úgy, hogy megnézi, mi fut túl lassan, és a végrehajtási terv alapján kitalálja, milyen indexszel vagy hintekkel lehetne jobban futtatni ugyanazt, vagy akár úgy, hogy nyakára lép a trehány fejlesztőknek, hogy gondolkozzanak, mielőtt telibejoinolnak két sokmilliós táblát.Vagy azon is el lehet gondolkozni, hogy valami mentén partícionáljátok a táblákat.
Mittudomén, van egy folyamatod, aminek van egy azonosítója, akkor célszerű lehet az összes a folyamatban használt táblát a folyamat azonosító mentén partícionálni, és az összes joinba betenni a partíciókulcsot, így mindig csak az aktuális partíció pártíz-ezer során dolgozik a DB, nem az egészre megy a full table scan...[szerk:]Ja, hogy dobozos? Akkor a beszállítót kell rugdosni, ha még garis a termék, de sejtésem szerint már fizetős a support

Pénz meg szokás szerint nincs.Én sok kis lépéssel próbálok javítani. Igazából szorgalmiként, mert mellette ott vannak a feladataim is :/
Sajnos volt ilyen munkahelyem.
Amikor sikerült sok hónap munkával eloltanom egy évek óta lángoló tüzet, amit az egyik vezető fejlesztő nemtörődömsége okozott, akkor még vállveregetést sem kaptam érte, nem hogy fizuemelést.
Aztán még én voltam a szemét, amikor leléptem onnan... -
nyunyu
félisten
Replikáció erre való, hogy ha megváltozik egy adat, akkor a változás automatikusan át legyen víve a másolatra is.
Persze arra oda kell figyelni, hogy a táblák egyedi azonosítóit populáló szekvenciákat nem szokta szinkronizálni, így pl. ha kiesik az eredeti adatbázis, és ideiglenesen a replikát akarod használni helyette, akkor manuálisan léptetned kell a másolat DBben lévő szekvenciákat, hogy nagyobb értékről induljanak, mint a táblában lévő aktuális ID, különben egyedi kulcs sértést kapsz, amikor írni próbál a rendszer a replikába.
(aztán a kiesett eredeti DBre visszaálláskor is el lehet ezzel játszani.)Nyilván a replikációt elindítani sem munkaidőben kell, ha akkorák a tábláid, hiszen jó pár óráig eltarthat, mire nulláról felépíti a másolatot.
Kollégáimnak annó elég sok bajuk volt az SQL Server 2000 replikációjával, de a 2005, aztán a 2008 már jóval stabilabban működött.
-
nyunyu
félisten
A hasht tároló oszlopra rakj rá egy unique megszorítást, és akkor magától hibát dob, ha már bent lévő értéket próbálsz megadni:
CREATE TABLE "logs" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"level" INTEGER,
"tstamp" TEXT,
"message" TEXT,
"location" TEXT,
"userid" TEXT,
"hash" TEXT UNIQUE
);Nem vágom az SQLiteot, de az insert szintaxisát elnézve lehet benne olyan upsertet írni, hogy:
insert or ignore into tábla values (értékek) on conflict do nothing;Ekkor figyelmen kívül hagyja a hibára futó insertet, és nem hajtja végre.
-
nyunyu
félisten
válasz
bambano
#4472
üzenetére
Nem elég azt nézni, hogy benne van-e a dátum a calendarban, hanem azt is kéne nézni, hogy az extra nap milyen napnak számít, különben elveszted a soknapos ünnepek körül elcserélt szombati munkanapokat.
Ezért volt plusz egy oszlop az ügyfeleinknél használt naptár táblákban, ahova a munkanapcserés szombatokat is fel kellett vennem péntek értékkel, előtte pénteket meg csütörtökkel, amikor egy évre előre felvettem az ünnepnapokat.NOT IN vs LEFT JOIN?
Annak idején úgy tanultuk, hogy jobb az anti join teljesítménye, de nem tudom ez a mai DB kezelőknél mennyire áll még fenn.
Oracle optimalizálója alapból anti joinná alakítja a not in-t, hacsak nem tiltod meg neki, így ott már nincs különbség teljesítményben. -
nyunyu
félisten
válasz
bambano
#4461
üzenetére
Oracle:
with extra_nap as (
select '20200410' datum, '7' nap from dual
union
select '20200413' datum, '7' nap from dual
union
select '20200501' datum, '7' nap from dual),
szamok as (
select level l
from dual
connect by level <= 1000),
datumok as
(select to_char(sysdate+l,'yyyymmdd') datum,
case when nvl(e.nap, to_char(sysdate+l,'d')) in ('1','2','3','4','5') --hétfő..péntek
then 'Y'
else 'N'
end munkanap
from szamok l
left join extra_nap e
on e.datum=to_char(sysdate+l,'yyyymmdd'))
select datum, row_number() over (order by datum) rn
from datumok
where munkanap='Y';Extra_nap "táblába" felvettem a nagypénteket, húsvéthétfőt, május elsejét vasárnapi munkarenddel.
Aztán legenerálom a következő 1000 nap dátumát, és melléteszek egy munkanap flaget, ami az extra_napban beállítottból vagy a hanyadik nap a héten értéktől függ.
Végül leválogatom a munkanapokat és melléteszek egy sorszámot, hogy ő hanyadik. -
nyunyu
félisten
válasz
kw3v865
#4459
üzenetére
Mi volt a baj az eredeti elképzeléseddel?
FOR nem a mögé írt query által visszaadott sorrendben megy végig a sorokon, mint ahogyan a kurzorok tennék? De.
Indexelős ötleted nagyon elborult, egyrészt nehéz megvalósítani, pl. mi van akkor, ha jön egy új elem a táblába, akkor minden sort megupdatelsz az aktuális sorrend alapján?
Iszonyúan nagy overheadet produkálnának az ehhez szükséges triggerek.Ha csak annyi lenne a kérdés, hogyan tudod megmondani egy sorról, hogy ő valamilyen rendezés szerint hanyadik a táblában, akkor a row_number() over (order by x,y) függvényt tudod használni.
Egyébként meg a relációs adatbázisok mindig halmazokkal dolgoznak, nem egy-egy elemmel, így a más programnyelvek procedurális gondolkozásmódja (ciklusok, kurzorok...) SQLben sosem ad jó teljesítményt.
Próbálj inkább úgy gondolkozni, hogyan lehet egy queryvel az összes adatot egyszerre frissíteni/beszúrni.Előző projekten amúgy belefutottam hasonlóba, mint amit most szeretnél.
Örököltem egy kódot, ami egy táblából csinált egy rendezett kurzort, majd azon ment végig egyesével, és dinamikus SQLben kért új értéket egy szekvenciából, majd updatelte rá a tábla soraira, kvázi új indexet vezetett be.
Persze, hogy 15000 sor esetén húsz percig szöszmötölt rajta az Oracle.
Megoldás az lett, hogy egy segédtáblába leválogattam a fő tábla azonosítóit, meg a row_number() over (order by x,y) rn-t, aztán következett egy jól irányzott merge a fő táblára.
Egyből lefut 10 másodperc alatt... -
nyunyu
félisten
válasz
MrSealRD
#4451
üzenetére
Normalizálásnak megvan a maga helye és az ideje, de ez az eset nem tűnik annak.
Mostanában már nem annyira a tárhely (memória, vinyó, szalag...) a szűk kapacitás, mint tizenévekkel korábban, így már nem feltétlenül érdemes a normalizációval megspórolható helyre gyúrni.Adattárházaknál például bevett szokás a csillag séma, amikor egy nagyon széles, sokmillió soros ténytáblához joinolnak sok kicsi dimenziót, viszont a dimenziótáblák tartalmát nem nagyon szokták normalizálni, hogy minél kevesebb joinnal gyorsabban lekérdezhető legyen a nagy mennyiségű adat.
Vannak olyan mondások is, hogy a dimenziókat nem ártana normalizálni, azt hívják hópehely sémának, de az általában ront a lekérdezések, adattranszformációk sebességén.Előző projektünkből kiindulva az sem ideális, amikor tizen-huszon, alig pár rekordot tartalmazó paramétertáblát kell kerülgetned, hogy mi az amit a következő shipmentbe bele kell tenned, és mi az amit nem szabad.
Olyankor valami mindig kimarad, vagy éppen felülírod az éles beállításokat egy alsóbb környezetre érvényes teszt beállítással.
Ráadásul fél évvel később az üzemeltetési doksi írásakor már nem is emlékeztem arra, hogy kollégák melyiket mire használták, sokat úgy kellett kitúrni a kódból, amikor az üzemeltetők rákérdeztek valami egyedi beállítási lehetőségre.Azon a projekten a fontosabb paraméterek állítására például az Üzlet kért egy képernyőt, ahol Excelben letöltheti a fontosabb paramétertáblák tartalmát, majd szerkesztés után visszatölthesse.
Azokat a táblák tartalmát például tilos volt dumpként a shipmentbe adni, nehogy felülírjuk a felhasználók beállításait.
Ha új sorok kellettek, akkor azokat élesítéskor insertekkel kellett beszúrni. -
nyunyu
félisten
válasz
MrSealRD
#4445
üzenetére
Ha az a cél, hogy enumokat tárolj, akkor egy szótártábla elég, amiben van enum_neve, sorszám, érték.
(Aztán utána lehet hitvitákat folytatni, hogy nullától vagy egytől indexeljünk, lásd java vs sql)Ha viszont Hibernateet akarsz használni DB kezelésre, akkor jól gondold meg, hogy mire vállalkozol, mert az arra tökéletesen alkalmatlan.
Előző projekten alapvetően Oracle DBben fejlesztettünk egy üzleti alkalmazást, afölé lett Javaban írt frontend-backend téve, aztán az eredeti elképzelés az volt, hogy a Hibernate közvetíti az DBben lévő adatokat a Java GUI felé.
Aha, iszonyúan erőforráspazarló, nem gyors, de legalább az összes adatműveletnél lockolja az összes érintett táblát, tábla szinten.
Gyakorlatban totálisan alkalmatlannak bizonyult többfelhasználós célokra, mert folyamatosan homokórázott a rendszer a Hibernate hülyeségei miatt lockolt táblák miatt.
Végül az össze 3 táblából összejoinolok egy táblázatot kérdésre az lett a válasz, hogy a GUI meghív egy tárolt eljárást, ami elvégzi a joint, és az eredményt visszaadja egy kurzorban, aztán annak a tartalmát húzták be a kliens oldalon tovább szűrhető gridbe.
Vagy natív query.A másik nagy kedvencem a késleltetett írás témája.
Felhasználó képernyőn kitölt egy táblázatot, amit egy az egyben a Hibernate ment egy DB táblába.
Elmélet az, hogy a táblázat soráról elvéve a fókuszt azonnal menti a módosult sort a DBbe.
Gyakorlatban? Ha a felhasználó rábökött a Tovább gombra, ami meghívott valami tároltat, ami a frissen töltött táblát használta, akkor az esetek 20%-ában nem volt elmentve az utoljára szerkesztett sor, és a DBben implementált logika emiatt hülyeséget csinált.
Én meg nyomozhattam, hogy mi a francért van jó adat a forrástáblában, az adattranszformáció végén meg rossz. (Hibernate végül mégiscsak elmentette, miután a DB már felhasználta a rossz adatot...)
Végeredmény? Javas kollégákkal veszekedtem pár napot, hogy a DB tárolt hívása előtt MENTSÉK el a táblát.Ez vajon megoldotta a problémát?
A fenéket, méréseim szerint még mindig 3% adathibát okoz, hogy a SaveAndFlush() sem ment azonnal.
Utolsó ötletük a javas kollégáknak a probléma megoldására a Thread.Sleep(500) beiktatása volt a SlaveAndFlush() és a DB tárolt hívás közé...
Mivel az ilyen hókuszpókuszokban nem bízom, inkább beraktam egy összehasonlítást a transzformáció végére, hogy ha inkonzisztenciát lát, azonnal fusson újra az időközben mentett adatokra.Harmadik agybaj meg az volt, hogy a Hibernate konkrétan lebénul attól, ha olyan táblába kell sorokat beszúrnia, ahol a tábla egyedi kulcsát képező szekvencia egyesével lépked. (ami ugye a DB default beállítás...)
Javas kollégák magyaráztak valami marhaságot arról, hogy a Hibernate húszasával becacheli előre a leendő ID értékeket, így a szekvencia lépésközét ennél nagyobbra kell állítani, hogy ne akadjon össze a DBvel egy-egy insertkor.Szóval csak óvatosan a Hibernatetel, mert attól erősen csökken a savassága a DBnek.
-
nyunyu
félisten
válasz
BuktaSzaki
#4422
üzenetére
SELECT DISTINCT s.szerzodesID,
CASE
WHEN s1.tetel IS NOT NULL AND s2.tetel IS NOT NULL THEN 'Mindkettő megvan'
WHEN s1.tetel IS NOT NULL AND s2.tetel IS NULL THEN 'Csak az első'
WHEN s1.tetel IS NULL AND s2.tetel IS NOT NULL THEN 'Csak a második'
ELSE 'Egyik se'
END tetelek
FROM szerzodesek s
LEFT JOIN szerzodesek s1
ON s1.szerzodesID = s.szerzodesID
AND s1.tetel = 'Tetel1'
LEFT JOIN szerzodesek s2
ON s2.szerzodesID = s.szerzodesID
AND s2.tetel = 'Tetel2'
WHERE s.datum>SYSDATE-30
ORDER BY s.szerzodesID;Főnököm mondjuk megölne a distinct miatt, meg nem árt egy index a szerzodesID mezőre, ami mentén joinolod önmagával a táblát, különben elég elborult végrehajtási terve lenne.
-
nyunyu
félisten
válasz
GreenIT
#3879
üzenetére
Valamelyik régebbi, XPre még feltelepíthető SQL Server Express?
Ahogy nézem a 2008 R2 SP2 még felmenne, 2012 már nem.Azokban lévő SQL Server Management Studio GUIja nem sokban különbözött a Visual Studiotól.
-
nyunyu
félisten
Between azért is szívás lehet, mert ha varcharban tárolt értékeket próbálsz hasonlítani, akkor az implicit típuskonverzió számmá, aztán az csúnyán el tud szállni, ha benézel egy NULLt vagy egy nem jól/jókor szűrt táblát.
Pl. hiába teszel a between elé egy upper(x)=lower(x)-et plusz egy is not null-t, hogy a nem számokat kiszűrd, mert nem biztos, hogy mindig ugyanolyan sorrendben fog szűrni az adatbázis...
Oracle például szereti párhuzamosan kiértékelni a join feltételeket: mindegyik lefut minden sorra, aztán a részeredményekből legózza össze a join eredményét.(Telefonszámokat kellett sorfolytonos tartományokba rendeznem, ahol a telefonszám mezőben egyéb azonosítók is lehettek a nem telefon jellegű rekordokon...
Lexebb a '#47543' érték volt, ami a varchar(10)-ból kilógó hosszúságú telefonszámot tároló másik táblára mutató pointer akart lenni.
Ja, átment az upper(x)=lower(x) teszten.) -
nyunyu
félisten
válasz
galocza
#3727
üzenetére
Ez elég nehezen távgyógyítható témakör, és a sarki pistike nem biztos, hogy saját kútfőből meg tudja oldani okosba'
Ha meg a kasszarendszert hivatalosan supportáló brigád cserélte sok pénzért a komplett gépet ahelyett, hogy megvizsgálta volna, hogy
1) hálózati kapcsolat elég stabil-e kábelteszterrel, és ha szükséges, akkor kábel újrakrimpelés RÁ VALÓ dugóval */komplett kábel csere, ha a régi menthetetlen
2) gépen jól van-e beállítva a DB connection string (pl. servert keresi-e a helyben futó Firebird példány helyett)
Akkor toll a fülükbe.
*: Tömör fali kábel vs egyenes késes UTP csatiról tudnék órákat mesélni...
-
nyunyu
félisten
PHPből hívott tákolt eljárásnak átadod paraméterként a módosítandó értékeken kívül az elkövetőt is, aztán nem egy insert lesz benne, hanem egy másiodikkal a napló táblába szúrod az elkövetőt, tetthelyet, időbélyeget?
Trigger nagyon jó arra, hogy kikényszerítsd az adatbázis konzisztenciát, de annak jelentős teljesítményvesztés az ára.
-
nyunyu
félisten
válasz
Iginotus
#3658
üzenetére
valami ilyesmi:
declare i number;
begin
for i in 1 .. 9 loop
update ...
where row_id=i
end loop;
end;Kevésbé procedurálisan gondolkozva persze meg lehet írni egy updatetel is, mivel van sorfolytonos IDd a táblán, amihez lehet row_number()-rel joinolni:
update sds.forge upd
set code_neu=
(select a.orgeh_code from
(select oe.*, row_number() rn from sds.oe
order by dbms_random.value) a
where a.rn=upd.row_id); -
nyunyu
félisten
válasz
bambano
#3645
üzenetére
Ilyesmi feladatba már sikerült belefutnom melóhelyen.
Ottani kódom erősen leegyszerűsítve.DB adminjaink persze nem szoktak szeretni érte, amikor több millió soros táblákból kell kibogarásznom pár tízezer hasznos rekordot, majd azokat intervallumokba rendezni...
Query plant kielemezve mindenféle Cartesian join kerülendő szakszavakkal dobálózva próbálják levenni a rontást a DB performanciáról. -
nyunyu
félisten
-
nyunyu
félisten
válasz
bandi0000
#3614
üzenetére
Úgy több-több a kapcsolat, hogy egy vásárló több eladótól is vehet (az mindegy, hogy mikor), de egy eladó termékeit is több vevő veheti.
Labor házidra ugyanez igaz, egy ember több fodrászhoz is foglalhat időpontot, de egy fodrásznak is több vendége van egy nap, és ezek egymástól függetlenek.
Minden egyes tranzakció egy új rekord lesz a foglalásos táblában.
-
nyunyu
félisten
válasz
bandi0000
#3612
üzenetére
N:M reláció:

Jól látod, foglalásnak külön tábla kell 4 oszloppal:
- foglalt termék idegen kulcsa
- foglaló vevő idegen kulcsa
- foglalás ideje
- foglalás áraMajd az itt tárolt külső kulcsokkal joinolod össze a foglalót a foglalt termékkel.
[szerk:]Céges feladat? Ez inkább egy állásinterjúhoz szakmai beugrónak tűnik, amit fél délután össze lehet rakni.
-
nyunyu
félisten
válasz
Fundiego
#3600
üzenetére
Ablakozó függvénnyel beszámozod a pilótánkénti helyezéseket, majd leválogatod, melyik lett az első, második, harmadik?
Oracle alatt valami ilyesmi lenne:
with eredmeny
as (select id,
ev,
vegeredmeny,
pilota,
pont,
row_number() over (partition by ev, pilota order by vegeredmeny, id) eredmeny
from futam)
SELECT e.pilota,
SUM( e.pont ),
e1.vegeredmeny er1,
e2.vegeredmeny er2,
e3.vegeredmeny er3,
e3.vegeredmeny er4
FROM eredmeny e
join eredmeny e1
on e1.ev=e.ev
and e1.pilota=e.pilota
and e1.eredmeny=1
join eredmeny e2
on e2.ev=e.ev
and e2.pilota=e.pilota
and e2.eredmeny=2
join eredmeny e3
on e3.ev=e.ev
and e3.pilota=e.pilota
and e3.eredmeny=3
join eredmeny e4
on e4.ev=e.ev
and e4.pilota=e.pilota
and e4.eredmeny=4
WHERE e.ev = 2017
GROUP BY e.pilota,
e1.vegeredmeny,
e2.vegeredmeny,
e3.vegeredmeny,
e4.vegeredmeny
ORDER BY SUM( e.pont ) DESC; -
nyunyu
félisten
válasz
velizare
#3596
üzenetére
Nincs erre valami parancs, amit minden lefuttatott script elejére be tudsz szúrni, hogy UTF8 kódolást használjon?
Mi Oracle DBAink is szoktak szívni azzal, hogy mentenek egy scriptet PL/SQL Developerből, aztán a prod környezet üzemeltetéséért felelős "kolléga" SQL Developerből futtatva mindig telibevágta vele az éles adatokat.
Azóta minden neki küldött script úgy kezdődik, hogy
ALTER SESSION SET NLS_LANGUAGE=...Aztán jönnek csak az ékezetes stringeket tartalmazó INSERTek.
-
nyunyu
félisten
-
nyunyu
félisten
válasz
orbanka
#1935
üzenetére
Gondolom kb. akkora lehet a kulonbseg az elso es a masodik verzio kotott, mint MS platformon a Linq es az SqlCommand osztaly hasznalata kozott.
Linq baromi kenyelmes, mert definialod az adatkotest, aztan a tablak frissiteset, betolteset, stb. a hatterben magatol intezi a .NET keretrendszer, nem neked kell megirni, hogy ha modositanak egy mezot a griden, akkor mit hova updateeljen.
Viszont ez durvan 200x lassabb kodot general, mint ha megirnad SQLben, es feladnad rendes querykent, ahol viszont nem biztos, hogy minden esetre gondoltal, es kimaradhat valami...
Új hozzászólás Aktív témák
- E-book olvasók
- Milyen routert?
- Synology NAS
- D1Rect: Nagy "hülyétkapokazapróktól" topik
- GoodSpeed: Daikin FTXF35E / RXF35F Sensira 3,3 kW Inverteres klíma - a Sztori
- Bittorrent topik
- Gumi és felni topik
- iPhone topik
- Mi az a monitor ott a gépedben? Csak a Phanteks vizesblokkom...
- Milyen billentyűzetet vegyek?
- További aktív témák...
- Fujitsu LIFEBOOK E449 i3-8130U 12GB 512GB 14" FHD 1 év garancia
- ÁRGARANCIA!Épített KomPhone i7 14700KF 32/64GB RAM RX 9070 16GB GAMER PC termékbeszámítással
- Borzasztóan cuki, elegáns, HALK fileszervernek bőven elég teljesítménnyel és elegáns megjelenéssel
- ÁRGARANCIA!Épített KomPhone i5 10400F 16/32/64GB RAM RTX 3060 12GB GAMER PC termékbeszámítással
- 2db Kolink kontinium 1200w platinum
Állásajánlatok
Cég: Laptopműhely Bt.
Város: Budapest



)


