Friss topikok

SELECT * FROM t WHERE t.x = MAX(t.x)

2008.08.26. 07:02 | koc | 1 komment

A fent leírt select így nyilvánvalóan értelmetlen, de arra alkalmas, hogy a probléma velejét megragadjuk, azaz hogyan tudjuk kiválasztani egy tablából azt a sort, amelyik egy tetszőleges oszlop szerinti rendezés alapján maximális, vagyis utolsó.

A hagyományos módszer így nézne ki:

SELECT t.* FROM t, (SELECT  MAX(r) mr FROM t) t1 WHERE t.r = t1.mr

Fontos észrevennünk, hogy a fenti eljárás minden olyan sort visszaad, ahol r maximális. A továbbiakban korlátozzuk vizsgálatunkat arra a gyakori speciális esetre, amikor r egyértelmű rendezést jelent, vagy az azonos r értékű sorok számunkra releváns értékeitől elvárható az egyezés, azaz voltaképp egy ilyen halmazból tetszőleges sort választhatunk.

 

Ha a LAST_VALUE analítikus függvényt ismerjük, akkor adódik rögtön a megoldási lehetőség egy oszlop értékének kiválasztására:

SELECT DISTINCT LAST_VALUE(x) OVER (ORDER BY r) FROM t

Ahol x a számunkra releváns egy darab oszlop. Ha ezt kipróbáljuk hamar kiderül, hogy minden r értékhez külön eredményt kapunk, ami nem meglepő az alapértelmezett window ismeretében, ami a rendezés szerinti első sortól a rendezés szerinti aktuális sorig tart. Definiáljuk hát a window-t is amire szükségünk van.

SELECT DISTINCT
LAST_VALUE(x) OVER (ORDER BY r ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
FROM t

Mint látható a kapott kód nem túl esztétikus, de ezen egy kis trükkel segíthetünk. Ha az alapérterlmezett window-ban az utolsó sor nem is egyértelmű, az első azért az, fordítsuk hát meg a rendezést és használjuk a FIRST_VALUE függvényt.

SELECT DISTINCT FIRST_VALUE(x) OVER (ORDER BY r DESC) FROM t

Ez eddig jó is, de vajon mi a helyzet ha több oszlop értékére is kiváncsiak vagyunk az adott sorból? Soroljuk fel egyszerüen az oszlopokat egyenként egy-egy analítikus függvénybe ágyazva?

SELECT DISTINCT
FIRST_VALUE(x1) OVER (ORDER BY r DESC),
FIRST_VALUE(x2) OVER (ORDER BY r DESC),
[...],
FIRST_VALUE(xn) OVER (ORDER BY r DESC)
FROM t

Ez természetesen működik, de javasolni mégsem tudom, hiszen az Oracle ilyen esetben annyi window sort műveletet fog végrehajtani, ahány oszlop értékét így szxeretnénk kiválasztani. Márpedig nagy táblák esetén egy rendezés roppant időigényes lehet. Mit tehetünk akkor? Válasszünk egy alkalmas szeparátor karaktert, az egyes xi oszlopokat szükség esetén alakítsuk karakteres formátumúvá, majd szükség esetén vissza, és az alábbi konkatenációs trükkel a window sort műveletek számát máris leszoríthatjuk egyre. Fontos, hogy a szeparátor karaktert úgy válasszuk meg, hogy az bizonyosan ne szerepeljen egyetlen oszlop karakteres formájában sem.

SELECT
SUBSTR(conc, 1, INSTR(conc, '@', 1, 1)-1) x1,
SUBSTR(conc, INSTR(conc, '@', 1, 1)+1, INSTR(conc, '@', 1, 2)-INSTR(conc, '@', 1, 1)-1 ) x2,
[...],
SUBSTR(conc, INSTR(conc, '@', 1, i-1)+1, INSTR(conc, '@', 1, i)-INSTR(conc, '@', 1, i-1)-1 ) xi,
[...]
SUBSTR(conc, INSTR(conc, '@', 1, n-1)+1) xn
FROM (
SELECT DISTINCT
FIRST_VALUE(x1 ||'@'|| x2 ||'@'|| [...] ||'@'|| xi  ||'@'|| [...] ||'@'|| xn) OVER (ORDER BY r DESC) conc
FROM t)

 

Címkék: max analytic query last value first value

A bejegyzés trackback címe:

https://plsql.blog.hu/api/trackback/id/tr84633218

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

csillagp 2008.09.11. 18:14:51

Ez egyszerubbnek tunik, es nem biztos hogy lassabb :-)

select *
from
(select
t.*,
case when r=max(r) over () then 'M' end maxind
from
t)
where maxind = 'M'

nincs string-e alakitas oda-vissza, csak egy tablescan, egy window muvelet - es csak egy filterrel tobb...
süti beállítások módosítása