Hirdetés

2024. május 3., péntek

Gyorskeresés

Útvonal

Fórumok  »  Szoftverfejlesztés  »  SQL kérdések (kiemelt téma)

Hozzászólások

(#4701) DeFranco válasza nyunyu (#4700) üzenetére


DeFranco
nagyúr

Köszönöm szépen, nagyjából működik de nem teljesen:

1: a sum(ertek)/osszegre ugrik az ellenőrzés, nem fut le, a hibaüzenet az alábbi:

ORA-56902: összesítő függvényt várható a forgatási műveletben
56902. 0000 - "expect aggregate function inside pivot operation"
*Cause: Attempted to use non-aggregate expression inside pivot operation.
*Action: Use aggregate function.

2: ez csak nekem kérdés mert még nem vagyok otthon pivotban: ha sum(ertek)-en hagyom tehát nem képzek indexet, akkor az eredménytábla úgy néz ki hogy ezeket az oszlopokat pakolja egymás mellé:

egyedi_azonosito II o.osszeg II A II B II C II stb.

tehát az [o.osszeg] oszlopot a pivotolt résztől függetlenül beteszi a "sorfej" és az "oszlopok" közé

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?

(#4702) nyunyu válasza DeFranco (#4701) üzenetére


nyunyu
félisten

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.

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4703) DeFranco válasza nyunyu (#4702) üzenetére


DeFranco
nagyúr

köszönöm szépen, így sem működött de megoldottam, egyszerűen kiszámoltattam vele még a selectben és azt pivotoltattam az abszolút érték helyett

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,
t.ertek/o.osszeg arany
from tabla t
join egyed_osszeg o
on t.egyed_azonosito = o.egyed_azonosito
)
pivot
( sum(arany)
for csoport_kepzo in ('A','B'...)
)

így már szépen működik, elé joinoltam az abszolút értékeket és teljes lett a tábla

köszönöm még egyszer a tippeket

[ Szerkesztve ]

(#4704) DeFranco


DeFranco
nagyúr

újabb problémába futottam bele, lehet egy kicsit vadulok már ezzel:

adott egy lekérdezés, ami elég hosszú, több subqueryből áll,

gyakorlatilag legyártok néhány kereszttáblát, majd ezeket joinolom egymás után, egyes kereszttáblákban nyers adatok vannak, más kereszttáblákban számított adatok.

pl.
1: munkavállalók havi keresete, havonkénti bontásban (KH)
2: munkavállalók keresete legyártott darabonként havonkénti bontásban (KHD)
3: munkavállalók éves keresete (K)
4: munkavállalók anyagfelhasználása havonkénti bontásban (AH)
5: munkavállalók anyagfelhasználása legyártott darabonként havonkénti bontásban (AHD)
6: munkavállalók éves anyagköltsége (A)

a joinok miatt minden ilyen szakasz el is van nevezve (Pl. KHD, AHD), ezek alapján tudom K.Y=KHD.B módon kapcsolni.

a lekérdezés végére szeretnék tenni még egy kereszttáblát de azt már lehetőleg úgy, hogy az néhány korábbi subquery eredményére hivatkozzon, pl.

SELECT
K.[munkavállaló] "MUNK"
KHD.[érték]/AHD.[érték] AS "KPERA"
KH.[hónapazonosító] AS "HO"
FROM
???
PIVOT
(
SUM(KPERA)
FOR HO IN (...)
)

Nem tudom hogy a felső subqueryket így meg tudom-e csapolni, jelenleg nem tudom megoldani, és ötletem sincs mit lehetne tenni a FROM mögé mert a subquery neveket nem akarja "fogyasztani"

egy nagy selecten belül kell mindent megoldanom, táblát gyártani nincs jogosultságom.

érzésem szerint amit egyszer valahol már legyártottam azt fel kellene tudnom használni úgy hogy nem ismétlem meg azt a kódrészt még egyszer de nem jövök rá hogy kellene ezt megtennem.

[ Szerkesztve ]

(#4705) nyunyu válasza DeFranco (#4704) üzenetére


nyunyu
félisten

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.

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4706) DeFranco válasza nyunyu (#4705) üzenetére


DeFranco
nagyúr

igen csak itt az általad leírt selectben már eleve aliasolt selectek a "táblaazonosítók" (K, KHD, KH, AHD)

és mivel a SELECT szintaktikája ha jól tudom megköveteli a FROM-ot, nem tudom mit írhatnék a ??? helyére, mert ha azt írom hogy

SELECT
K.[munkavállaló] "MUNK"
KHD.[érték]/AHD.[érték] AS "KPERA"
KH.[hónapazonosító] AS "HO"
FROM
K
JOIN KHD
ON
K.valami = KHD.valami
JOIN KH
ON
K.valami = KH.valami
JOIN AHD
ON
K.valami = AHD.valami

akkor az nem működik. azt nem tudom hogy elvileg kellene-e működnie, sajnos favágó módszerrel tanulom az sql-t

[ Szerkesztve ]

(#4707) nyunyu válasza DeFranco (#4706) üzenetére


nyunyu
félisten

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!

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4708) DeFranco válasza nyunyu (#4707) üzenetére


DeFranco
nagyúr

igen, így van, ahogy írod, ha jól értem az utolsó két kommentben tartalmilag ugyanazt a kódot írtuk mindketten, és ennek ellenére nem működik ha lefuttatom, már K-ra is non existent table-t ír (ha jól emlékszem)

(#4709) nyunyu válasza DeFranco (#4708) üzenetére


nyunyu
félisten

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?)

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4710) nyunyu válasza nyunyu (#4709) üzenetére


nyunyu
félisten

FROM (select munkavallalo, ...
from ...
where ...) K
JOIN (select munkavallalo, ...
from ...
where ...) KHD
ON KHD.munkavallalo = K.munkavallalo

Erre 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.

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4711) DeFranco válasza nyunyu (#4709) üzenetére


DeFranco
nagyúr

nos...

az oldschool módszert használom, ahogy írod és szépen megy is addig, ameddig leírtad.

ezek ugye önmagukban (a zárójelek között) önálló selectek, egymás változóit nem használják csak egymás mögé vannak láncolva.

(az hogy pivotolgatok is ezekben az önálló selectekben, az egy másik kérdés. szerintem redundáns és ki kellene szedni de még nem jöttem rá a mikéntjére, ha csak simán kiszedem akkor az egy-a-többhöz kapcsolatok miatt a 20k-s valós rekordszámból a várt 400k-s rekordszám helyett (x20 oszlop a pivotban) 380 millió rekord lesz, nyilván én vétek hibát valahol)

ez alá jönne az a rész (amit én írtam lentebb) amikor az önálló, tábla-szerű egységgé zárójelezett, aliasolt blokkokból ki szeretnék venni mutatókat, azokat pl. összeszorozni vagy kivonni, és ez már nem megy. mutatom példában:

SELECT * FROM
(
SELECT
AL1.munkavallalo...
FROM... AL1
) K
JOIN
(
SELECT
AL2.munkavallalo
AL2.mutatoX
FROM AL2
) KHD
ON K.munkavallalo = KH.munkavallalo
JOIN
(
SELECT
AL3.munkavallalo
AL3.mutatoY
FROM AL3
) AHD
-- eddig a te logikáddal megegyezik, annyiban tér el hogy select * from van a definiált értékek helyett, de ez indifferens azt hiszem
-- innen jönne az amit én szeretnék, de nem megy
JOIN
(
SELECT
K.munkavallalo
KHD.mutatoX-AHD.mutatY
FROM
???
) KAMEHAMEA

de azt hiszem az első opció szerint lenne elegáns megcsinálni, én is gondoltam már erre (mióta megtanultam Tőled a where-t :D ) valószínűleg az lenne a praktikus.

[ Szerkesztve ]

(#4712) RedHarlow


RedHarlow
aktív tag

Sziasztok, az alábbi feladat megoldására ezt a példát találtam stackowerflow-on azonban az SQL developer hibára fut vele. A feladat az lenne, ogy egy tábla oszlopát kitöltsem egy másik tábla adataival azonos ID-k alapján. Tudnátok segíteni benne, fehér öves vagyok SQL-ből, nekem ez tök érthetően okénak tűnt aztán mégsem jó. Előre is köszönöm a segítséget.

UPDATE t1
SET t1.colmun = t2.column
FROM Table1 t1, Table2 t2
WHERE t1.ID = t2.ID;

[ Szerkesztve ]

(#4713) nyunyu válasza RedHarlow (#4712) üzenetére


nyunyu
félisten

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. :W

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;

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4714) Ispy válasza RedHarlow (#4712) üzenetére


Ispy
veterán

MS SQL-ben így írnám:

Update t1 set column=t2.column
From t1 inner join t2 on t1.id=t2.id

A formázás ilyen fosch, mert mobilról vagyok...

"Debugging is like being the detective in a crime movie where you're also the murderer."

(#4715) nyunyu válasza Ispy (#4714) üzenetére


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.

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4716) bambano válasza RedHarlow (#4712) üzenetére


bambano
titán

ezt rendes adatbáziskezelők így írják: (példa postgresql-ből)

update table1 set oszlop=table2.oszlop from table2 where table1.id=table2.id;

annyi a különbség, hogy az updatelendő táblát nem a from-ba teszi, hanem az update után, és nem használ aliasokat.

Egy átlagos héten négy hétfő és egy péntek van (C) Diabolis

(#4717) nyunyu válasza DeFranco (#4711) üzenetére


nyunyu
félisten

Ö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.munkavallalo

N+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 :D)

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4718) Ispy válasza nyunyu (#4715) üzenetére


Ispy
veterán

Hát, akkor nekem kivételes helyzetem van. ;]

De valóban a merge is jó megoldás, igaz én már annyira megszoktam a joint, hogy a merge csak tábla függvényében használom, ahol az update-et nem lehet.

"Debugging is like being the detective in a crime movie where you're also the murderer."

(#4719) nyunyu válasza Ispy (#4718) üzenetére


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. :W

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.

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4720) Ispy válasza nyunyu (#4719) üzenetére


Ispy
veterán

Sőt olyat is szoktam, hogy a from-ba rakok aggregát subselectet és annak az értékét updatelem vissza.

Life is easy! :D

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.

[ Szerkesztve ]

"Debugging is like being the detective in a crime movie where you're also the murderer."

(#4721) nyunyu válasza Ispy (#4720) üzenetére


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.

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4722) DeFranco válasza nyunyu (#4717) üzenetére


DeFranco
nagyúr

köszönöm, akkor már az elv sem volt jó, akkor így már világos.

gondolom akkor ezt azzal tudom áthidalni hogy előre with-elek mindent amit egyébként subquerybe raknék, majd onnan szedem be a megfelelő mutatókat egy fő querybe.

amint lesz lehetőségem átrendezem így a lekérdezést.

(#4723) DeFranco válasza nyunyu (#4721) üzenetére


DeFranco
nagyúr

én eleve nem is használtam a sima join-t úgy "tanították" (gyorstalpaló volt cégnél, a többit magamtól kapartam össze) hogy egzakt módon mondjuk meg hogy left right inner outer milyen join.

(#4724) nyunyu válasza DeFranco (#4723) üzenetére


nyunyu
félisten

"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.

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4725) mr.nagy


mr.nagy
tag

Sziasztok!

MSSQL környezetben a következő problémára keresem a választ:

adott egy tábla ahol az id mellett van egy érték oszlop is. Az érték lehet pozitív és negatív szám is. Ahol az érték negatív oda kellene át tenni onnan ahol ez pozitív. Az eredménynek az kellene, hogy honnan hova tegyünk át és mennyit, hogy a negatív eltűnjön.

Megvalósítható ez és hogyan szerintetek?

HMNote10Pro

(#4726) martonx válasza mr.nagy (#4725) üzenetére


martonx
veterán

Konkrétabban nem lehetne? dbfiddle példa esetleg?

Én kérek elnézést!

(#4727) mr.nagy válasza martonx (#4726) üzenetére


mr.nagy
tag

Megcsináltam: [link]

[ Szerkesztve ]

HMNote10Pro

(#4728) tm5 válasza mr.nagy (#4727) üzenetére


tm5
tag

" Ahol az érték negatív oda kellene át tenni onnan ahol ez pozitív."
Ezt a mondatodat el tudnád magyarázni egy példával? Mert gondolom nem arra gondolsz, hogy ahol pl. az érték -8 az legyen 8.

(#4729) mr.nagy válasza tm5 (#4728) üzenetére


mr.nagy
tag

Az eredménynek az kellene, hogy honnan vegyek el 8-at a pozitív értékektől, úgy hogy ne csökkenjen 0 alá az érték az elvétel miatt. A fiddle példánál maradva az eredmény ami kellene:
honnan id: 1, hova id: 2, val 8
honnan id: 6, hova id: 4, val 12
honnan id: 8, hova id: 7, val 4
......

Egy kereskedelmi példa: van 20 üzletem, van ahol felesleges készlet van és van ahol hiány. Honnan hova vigyek és mennyit, hogy a hiány megszünjön, de maradjon ott is elég ahonnan elveszek.

[ Szerkesztve ]

HMNote10Pro

(#4730) nyunyu válasza mr.nagy (#4729) üzenetére


nyunyu
félisten

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.

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4731) tm5 válasza nyunyu (#4730) üzenetére


tm5
tag

Én is valami hasonlóra jutottam, mint nyunyu, hogy ehhez minimum egy tárolt eljárás szükséges, ezt 1 sql paranccsal nagyon nem lenne egyszerű megoldani.
Valami olyasmit csinálnék, hogy generálnék 2 listát (plusz(i): pozitívok csökkenő sorrendben, minusz(j): negatívok növekvő sorrendben) és mennék végig a minusz listán úgy, hogy a plusz-os lista aktuális elemével megpróbálnám kiegyenlíteni a negatív értéket. ha nem tudom, akkor nézem a következőt a minuszból. Addig megy a ciklus, amíg a végére nem érsz valamelyik listának. + eköré még kellene még egy loop ami az elején újraszámolja a plusz, minusz listákat és addig megy amíg vannak update-ek. Valami ilyesmi lenne...

(#4732) mr.nagy válasza nyunyu (#4730) üzenetére


mr.nagy
tag

Köszönöm a választ, de a példánál maradva nincs központi raktár és sajnos a kereskedők az üzletben olyanok amilyen. Nem lehet rájuk bízni ezt a kérdést.

Esetleg két ideiglenes tábla, az egyikbe írom a kiegyenlítést a másikba csökkentem ennyivel az értéket, majd a második alapján új ciklus. Ez a ciklus addig fut, míg van hova tenni?

HMNote10Pro

(#4733) martonx válasza tm5 (#4731) üzenetére


martonx
veterán

És szerintem ezzel el is értünk oda, amikor a feladatot már tipikusan nem SQL-ben kellene megoldani, és a végén egy manuális jóváhagyás sem ártana, azaz mindez csak javaslat lenne a humán kezelőnek.

Én kérek elnézést!

(#4734) nyunyu válasza mr.nagy (#4732) üzenetére


nyunyu
félisten

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ő.

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4735) mr.nagy válasza nyunyu (#4734) üzenetére


mr.nagy
tag

Köszönöm! Ezt megpróbálom!

HMNote10Pro

(#4736) martonx válasza nyunyu (#4734) üzenetére


martonx
veterán

"Ettől még fenntartom azt, hogy Javaban egyszerűbb lenne lekódolni+gyorsabban is futna."
Mármint bármilyen programnyelven (javascript, php, c#, python, java, stb...) és nem csak egyszerűbb lenne lekódolni, és nem csak gyorsabban is futna, de könnyedén debuggolható, logolható, verzió kezelhető is lenne.
Noha mindezt SQL-el is meg lehet oldani, de elképesztően nyögve nyelősen.

Én kérek elnézést!

(#4737) bambano válasza mr.nagy (#4729) üzenetére


bambano
titán

én ezt úgy csinálnám, (mssql-hez nem értek), hogy csinálnék egy eredménytáblát, amibe beleírom, hogy honnan hova, ahogy te is felírtad.
majd csinálnék egy nézettáblát, ahol összeadnám a nyitó készletet és a mozgásokat, és az lenne az eredmény.
az eredménytábla feltöltését pedig a nézettábla alapján csinálnám meg.
majd csinálnék egy ciklust, ahol kiválasztanék egy honnan meg egy hová üzletet (például az alapján, hogy mekkora a hiány vagy mennyire nagy a készlet) és az alapján pakolnék a mozgás táblába.

a javaslatom az, hogy minden olyan megoldástól visítva menekülj, ami redundanciát okoz.

Egy átlagos héten négy hétfő és egy péntek van (C) Diabolis

(#4738) nyunyu válasza martonx (#4736) üzenetére


nyunyu
félisten

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?)

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4739) nyunyu válasza bambano (#4737) üzenetére


nyunyu
félisten

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.)

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4740) martonx válasza nyunyu (#4738) üzenetére


martonx
veterán

Bocs, pontatlan voltam. Az SQL-t nem számítom a programnyelvek közé. De igazad van végülis ez is programnyelv, csak épp nem imperatív. Ugyanígy nem tekintem programnyelvnek a CSS-t sem :D Legalábbis a magam pongyola megfogalmazásában.

A Java lambdát ne keverd ide, az csak egy syntetic sugar, nem attól lesz deklaratív nyelv a Java. De kezdünk nagyon eltérni az eredeti problémától :D

Én kérek elnézést!

(#4741) nyunyu válasza martonx (#4740) üzenetére


nyunyu
félisten

Pedig benne van a nevében hogy Structured Query Language :DDD

Hello IT! Have you tried turning it off and on again?

(#4742) Ispy válasza martonx (#4736) üzenetére


Ispy
veterán

tárolt eljárásban kb. bármit meg lehet írni, ahol adatbázis adatokkal kell zsonglörködni, kell csinálni pár temp table-t, belerakod a cuccost, írsz pár ciklust, ha kell, pikk-pakk megvan az egész és szerver oldalon maradtál.

"Debugging is like being the detective in a crime movie where you're also the murderer."

(#4743) bambano válasza nyunyu (#4739) üzenetére


bambano
titán

úgy kezdted a megoldásodat, hogy csináljon másolatot a tábláról.
ez már önmagában zűrök okozására ad lehetőséget.
ha például jávába beolvasod az adatokat, feltéve, hogy beférnek, akkor is ott lesz a probléma, hogy a riport futtatása közben vásárolnak, és akkor szétszalad a valós raktárkészlet adata meg a temp tábla adata.

"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": ez tény, de feladattól, környezettől függ, hogy ez hátrány vagy előny.

nekem az a véleményem, hogy hagyni kell az adatbáziskezelőt dolgozni.
az, hogy a bi ócska, az másvalaki problémája :P vegyenek bele több ramot.

Egy átlagos héten négy hétfő és egy péntek van (C) Diabolis

(#4744) Szmeby válasza bambano (#4743) üzenetére


Szmeby
tag

Szerintem ez csak egy házifeladat.

Már eleve életszerűtlen, hogy egy rakás fontos dolgot nem vesz figyelembe. Illene ellenőrizni, hogy a teljes rendszer egyenlege egyáltalán pozitív-e. Ha nem, akkor el kell dönteni, hogy inkább a kis hiánnyal rendelkező üzletek készletét optimalizáljuk és hagyjuk a nagy hiánnyal küzdő üzletet megdögleni. Vagy a nagy hiányra összpontosítunk és a kis hiánnyal rendelkező üzletek majd megoldáják valahogy. Teljesen más megközelítést igényel a két üzleti igény.

Ha feltételezzük, hogy a teljes egyenleg pozitív, akkor is kell egy korlát, ami alatt egyszerűen nem éri meg megmozdulni. Továbbá sokkal jobb minden üzlet készletét egy átlagos érték felé közelíteni. Vagyis ne a 0 hiány, 0 többlet legyen a cél, hiszen, ahogy te is mondtad, a raktárkészlet állandóan forog: ha csak a nullát tűzzük ki célul, akkor az első vásárláskor újra negatívba fordul, ami optimalizálási igényt kényszerít ki... abszolúte nem hatékony.

De még az átlagos szint sem feltétlenül optimális, hiszen egyes üzletek forgalma historikusan nagyobb, másoké kisebb, így érdemes ez alapján egy átlagtól való korrekciót alkalmazni. Ami aztán további problémákat szül, mivel egy tűpontosságúra optimalizált rendszerben - amennyiben az ember elfelejt gondoskodni az utánpótlásról - nagyon könnyen a teljes rendszer szintjén fellépő hiány alakulhat ki nagyjából ugyanabban a pillanatban.

A feladat nem veszi figyelembe az üzletek egymástól való fizikai távolságát, a megközelíthetőséget. Nagyon szépen hangzik, hogy egy db procedure megmondja, hogy a kettes id-jú üzletből vigyünk át 50 bizbazt a 14-es id-jú üzletbe, de ha ezek a város két végén helyezkednek el, akkor az ész nélküli ide-oda szállítgatás felzabálja a profitot. Arról nem is beszélve, hogy az ezt intéző munkavállalók azt fogják kérdezgetni, hogy ki volt az az idióta, aki ezt így kitalálta... és teljesen jogosan fogják megkérdőjelezni az értelmét.

A való életben ennél sokkal komplexebb feladat egy elosztott raktárkészlet optimális fenntartása, marhára nem egy temptáblával megoldható probléma. Mármint megoldható, csak az olyan is lesz. Ízlés dolga, kinek mit vesz be a gyomra ugye. :)

[ Szerkesztve ]

(#4745) bambano válasza Szmeby (#4744) üzenetére


bambano
titán

de amit te írsz, az arra szolgál, hogy kijön a táblázatból n darab lehetőség, hogy honnan hova, és abból az általad leírt további szempontok szerint választ ki egyet. ettől független kérdés, hogy hogyan adminisztrálja a mozgást magát.

Egy átlagos héten négy hétfő és egy péntek van (C) Diabolis

(#4746) olywer.smith


olywer.smith
csendes tag

Hello Mindenkinek!
Segítséget szeretnék kérni egy látszólag egyszerű lekérdezéshez.
Egy tábla első oszlopa egy azonosító, további oszlopok egyike a rögzítés ideje (datetime).
Le kellene gyűjteni azonosítónként az utoljára rögzített sorokat (minden oszlopával).

Előre is kösz a segítséget!

Üdv: olywer

(#4747) nyunyu válasza olywer.smith (#4746) üzenetére


nyunyu
félisten

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...

[ Szerkesztve ]

Hello IT! Have you tried turning it off and on again?

(#4748) olywer.smith válasza nyunyu (#4747) üzenetére


olywer.smith
csendes tag

Hi nyunyu !

És működik! :C :C

Ez félelmetesen gyors volt! Nagyon szépen köszönöm!

Üdv Olywer

(#4749) Heavyrain


Heavyrain
őstag

Sziasztok, a segítségeteket szeretném kérni.
Nyilván összetetteb, de példa kedvéért egyszerüsített formában az adatbázis:
2 oszlop van:
[A] oszlopban 3 számjegyű azonosítók vannak.
[B] oszlopban szövegek.

A probléma az, hogy [A] oszlop értékei többször is szerepelnek az adatbázisban és a duplikációk között eltérnek a [B] oszlopbeli szövegek.

Jelenleg ki tudom listázni az összes duplikációt de nem szeretném az összeset látni csak azokat amiknél eltér a B oszlopbeli szöveg. (Nem jelent gondot, hogy az [A]-ban duplikáció van)

Példa:
[A] ; [B]
123; asd
456; xyz
456; xyz
789; qwe
813; bnm
813; ijk
555; zzz
555; zzz
622; poi

Amit most kapok a duplikációk megkeresésével:
[A] ; [B]
456; xyz
456; xyz
813; bnm
813; ijk
555; zzz
555; zzz

Amit kapni szeretnék:
[A] ; [B]
813; bnm
813; ijk

Accessben dolgozom és sok mindent még csak most tanulok de nagyon megköszönném a segítségeteket. :R

[ Szerkesztve ]

(#4750) tm5 válasza Heavyrain (#4749) üzenetére


tm5
tag

Hát egy normális SQL-ben kb. így nézne ki:
SELECT t.a, t.b
FROM tabla t
, (SELECT a, COUNT(*) FROM
  (SELECT DISTINCT a,b FROM tabla)
   GROUP BY a
  HAVING COUNT(*)>1) x
WHERE t.a = x.a
Ha ez már túl sok az Accessnek, akkor csinálj az eredeti táblából a DISTINCT-es verziót (tabla2), majd erre egy SELECT a, COUNT(*) FROM table2 GROUP BY a HAVING COUNT(*) >1. Ez lesz a tabla3 és ezt joinold össze az eredeti tabla-val

[ Szerkesztve ]

Útvonal

Fórumok  »  Szoftverfejlesztés  »  SQL kérdések (kiemelt téma)
Copyright © 2000-2024 PROHARDVER Informatikai Kft.