Fórum Root.cz
Hlavní témata => Server => Téma založeno: Pupi1 19. 02. 2014, 18:14:06
-
Ahoj,
dlhsi cas sedim nad jednym dotazom, ktory mi robi problemy.
Mam 3 tabulky.
1. obsahuje: T1_ID,NAME,....
2. obsahuje: T2_ID,T1_ID,ADDRESS, .... (medzi tabulkami 1 a 2 je relacia 1:M)
3. obsahuje: T3_ID,T1_ID,.... (relacia s tabulkou 1, 1:M)
Mojim cielom je prepojit tieto 3 tabulky, kde vo vysledku maju byt vsetky udaje z tabulky 3 a z tabulky 2 len adresa a z tabulky 1 len meno. Problem je, ze v tabulke 2 moze byt viac udajov, ktore su v relacii s udajom v tabulke 1. Ja ale potrebujem tabulku 2 zoradit podla datumu a zobrat prvy zaznam. samozrejme tento zaznam s ID musi sediet s ID v tabulke 1. a potom uz len spojit s tabulkou 3.
Moj pokus, ale to vracia vsetky riadky aj z tabulky 2, nie len jeden:
--select R.RFP_ID, R."from", R.FORM_PDF, R.FORM_XML, R.ORGANISATION_ID, R.PAYMENT_AMOUNT, R.CREATED_ON, T.ADDRESS_LINE1, T.NAME from (
--select OU.ADDRESS_LINE1, O.ORGANISATION_ID, O.NAME
--from Organisation_unit OU join ORGANISATION O ON OU.ORGANISATION_ID = O.ORGANISATION_ID ORDER BY OU.CREATED_ON ASC) T join RFP R ON R.ORGANISATION_ID = T.ORGANISATION_ID;
-
tak trochu po lopate: zober zaznam z tabulky 1, z tabulky 2 zober udaje, ktore su v relacii so zaznamom z tabulky 1, zotried zaznamy, zober prvy a potom urob inner join s tabulkou 3.
-
tak trochu po lopate: zober zaznam z tabulky 1, z tabulky 2 zober udaje, ktore su v relacii so zaznamom z tabulky 1, zotried zaznamy, zober prvy a potom urob inner join s tabulkou 3.
No a kde je problém? Normální join tabulek 1 a 2, k tomu order by (zotried zaznamy), where rownum<=1 (zober prvy), to celé do závorek, označit aliasem a join s tabulkou 3.
-
Mám pocit, že tazatel potřebuje ke každému jménu je ho první (či poslední adresu) + detaily z třetí tabulky. Podle postupů viz výše se vyberou podle mého názoru jen jedno jméno s adresou + detaily. Kde jsou ostatní jména?
-
Jakou máte verzi DB? Následující postup myslím funguje až od 10g. Také nevím, jaké mají být joiny, t.j. zda se má jméno zobrazit, když nejsou data v dalších tabulkách atd., takže jsme všude použil inner join čili každý záznam z t1 tabulky musí mít odpovídající záznam v dalších tabulkách.
Vytvořil jsem tři testovací tabulky:
create table table1 (
t1_id number,
name varchar2(20)
);
create table table2 (
t2_id number,
t1_id number,
address varchar2(20),
ins_date date
);
create table table3 (
t3_id number,
t1_id number,
something varchar2(20)
);
Obsahují tyto záznamy:
select * from table1;
T1_ID NAME
----- --------------------
1 JOHN
2 ADRIAN
3 VACLAV
select * from table2;
T2_ID T1_ID ADDRESS INS_DATE
----- ----- -------------------- --------
1 1 NEW YORK 24.10.13
2 1 CHICAGO 23.09.13
3 1 SAN FRANCISCO 23.11.13
4 2 DORTMUND 01.01.12
5 2 MUNCHEN 01.02.11
select * from table3;
T3_ID T1_ID SOMETHING
----- ----- --------------------
1 1 MERCEDES
2 1 HONDA
3 2 BMW
3 2 AUDI
3 2 HONDA
Váš požadavek by mohl splnit snad následující select:
select t1.name, t2.address, t3.something from table1 t1
inner join (select tmp.*, row_number() over (partition by tmp.t1_id order by tmp.ins_date asc) rn from table2 tmp) t2 on t1.t1_id = t2.t1_id and rn = 1
inner join table3 t3 on t3.t1_id = t1.t1_id
Výsledek:
NAME ADDRESS SOMETHING
-------------------- -------------------- --------------------
JOHN CHICAGO MERCEDES
JOHN CHICAGO HONDA
ADRIAN MUNCHEN BMW
ADRIAN MUNCHEN AUDI
ADRIAN MUNCHEN HONDA
Pokud byste potřeboval poslední adresu, stačí místo ASC použít DESC. Snad jsem pochopil zadání správně, kdyžtak dejte vědět a zkusíme to ještě poupravit.
-
Váš požadavek by mohl splnit snad následující select:
select t1.name, t2.address, t3.something from table1 t1
inner join (select tmp.*, row_number() over (partition by tmp.t1_id order by tmp.ins_date asc) rn from table2 tmp) t2 on t1.t1_id = t2.t1_id and rn = 1
inner join table3 t3 on t3.t1_id = t1.t1_id
A co pokud nebude table2.ins_date unikátní? Pak by možná bylo lepší vrátit všechny relevantní záznamy:
select t1.name, t2.address, t3.something
from table1 t1,
(select tmp.address, tmp.ins_date, min(ins_date) over (partition by tmp.t1_id) min_ins_date from table2 tmp) t2,
table t3
where t1.t1_id = t2.t1_id
and t2.ins_date=t2.min_ins_date
and t3.t1_id = t1.t1_id
-
A co pokud nebude table2.ins_date unikátní? Pak by možná bylo lepší vrátit všechny relevantní záznamy:
Autor původně specifikoval, že chce jen první nalezený, to už záleží na přesnějším zadání jaký z nich pak použít či zda by vyhohoval postup zobrazit všechny relevantní jak píšete. Aspoň si teď může vybrat :)
-
Pokud byste potřeboval poslední adresu, stačí místo ASC použít DESC. Snad jsem pochopil zadání správně, kdyžtak dejte vědět a zkusíme to ještě poupravit.
Dát místo ASC pouze DESC může vést k nepříjemnému chování pokud se ve sloupci vyskytnou NULL - obvykle je tedy lepší místo DESC raději dávat DESC NULLS LAST.
-
cele som to myslel takto: predstavte si ze v tabulke 1 su Nazvy. v druhej tabulke 2 su adresy, a datum vytvorenia zaznamu. vsetko su povinne atributy. tabulky 1 a 2 su v relacii 1:M. A dajme tomu, ze zoberiem z tabulky 1 jeden zaznam. K tomuto zaznamu mozu existovat viacere zaznamy v tabulke 2. No a ja chcem aby mi prave z tej tabulky 2 vratilo len prvy zaznam. najskor to treba zoradit podla datumu vytvorenia zaznamu v tabulke 2 a zobrat prvy. No a potom uz len to spojit s udajmi v tabulke 3.
-
a co treba
select q.* from (select * from tabulka2 order by datum) q where ROWNUM = 1
tohle musi fungovat urcite, akorat to teda nebude moc efektivni. Ty joiny si uz udelej sam....
-
Jakou máte verzi DB? Následující postup myslím funguje až od 10g. Také nevím, jaké mají být joiny, t.j. zda se má jméno zobrazit, když nejsou data v dalších tabulkách atd., takže jsme všude použil inner join čili každý záznam z t1 tabulky musí mít odpovídající záznam v dalších tabulkách.
Vytvořil jsem tři testovací tabulky:
create table table1 (
t1_id number,
name varchar2(20)
);
create table table2 (
t2_id number,
t1_id number,
address varchar2(20),
ins_date date
);
create table table3 (
t3_id number,
t1_id number,
something varchar2(20)
);
Obsahují tyto záznamy:
select * from table1;
T1_ID NAME
----- --------------------
1 JOHN
2 ADRIAN
3 VACLAV
select * from table2;
T2_ID T1_ID ADDRESS INS_DATE
----- ----- -------------------- --------
1 1 NEW YORK 24.10.13
2 1 CHICAGO 23.09.13
3 1 SAN FRANCISCO 23.11.13
4 2 DORTMUND 01.01.12
5 2 MUNCHEN 01.02.11
select * from table3;
T3_ID T1_ID SOMETHING
----- ----- --------------------
1 1 MERCEDES
2 1 HONDA
3 2 BMW
3 2 AUDI
3 2 HONDA
Váš požadavek by mohl splnit snad následující select:
select t1.name, t2.address, t3.something from table1 t1
inner join (select tmp.*, row_number() over (partition by tmp.t1_id order by tmp.ins_date asc) rn from table2 tmp) t2 on t1.t1_id = t2.t1_id and rn = 1
inner join table3 t3 on t3.t1_id = t1.t1_id
Výsledek:
NAME ADDRESS SOMETHING
-------------------- -------------------- --------------------
JOHN CHICAGO MERCEDES
JOHN CHICAGO HONDA
ADRIAN MUNCHEN BMW
ADRIAN MUNCHEN AUDI
ADRIAN MUNCHEN HONDA
Pokud byste potřeboval poslední adresu, stačí místo ASC použít DESC. Snad jsem pochopil zadání správně, kdyžtak dejte vědět a zkusíme to ještě poupravit.
jop toto by mohlo byt :) odskusam to
-
a co treba
select q.* from (select * from tabulka2 order by datum) q where ROWNUM = 1
tohle musi fungovat urcite, akorat to teda nebude moc efektivni. Ty joiny si uz udelej sam....
toto vrati len jeden zaznam pre vsetko, to nie je dobre.
-
dobre to IMHO je, za prepokladu, ze si k tomu dodelas selekt z tabulky1 a join z tabulky3 a provazes to idckama. Metoda copy&paste s vyuzitim platforme zavislejch konstrukci je trochu o nicem. Az ti tam pribyde ctvrta tabulka, tak alespon budes vedet, jak to napsat sam ;) no flame
-
ja som skusal uz nieco podobne ako si napisal, nerobil som ctrl+c/v ;)
jedno riesenie co som vymyslel a vyskusal je toto:
select * from ORGANISATION O join
(select min(created_on) as CREATED_ON,organisation_id from ORGANISATION_UNIT GROUP BY ORGANISATION_ID) T
on T.Organisation_id = O.ORGANISATION_ID
join ORGANISATION_UNIT OU ON OU.ORGANISATION_ID=O.ORGANISATION_ID WHERE T.CREATED_ON = OU.CREATED_ON;
este mi tam chyba tretia tabulka, ale to je detail.
-
a co treba
select q.* from (select * from tabulka2 order by datum) q where ROWNUM = 1
tohle musi fungovat urcite, akorat to teda nebude moc efektivni. Ty joiny si uz udelej sam....
toto vrati len jeden zaznam pre vsetko, to nie je dobre.
Podle mě to bylo myšlené jako korelovaný poddotaz, ale ten join si tam musíte doplnit, třeba takhle:
select q.* from (select * from tabulka2 where tabulka1.t1_id=tabulka2.t1_id order by datum) q where ROWNUM = 1
-
to Vaclav Lesek:
vase riesenie funguje. Zial nie som este taky skuseny v SQL. Mohli by ste mi prosim vas vysvetlit, co to "over partition by" znamena? Rad by som to pochopil a nieco nove sa naucil.
dakujem
-
to Vaclav Lesek:
vase riesenie funguje. Zial nie som este taky skuseny v SQL. Mohli by ste mi prosim vas vysvetlit, co to "over partition by" znamena? Rad by som to pochopil a nieco nove sa naucil.
dakujem
http://www.oracle-base.com/articles/misc/analytic-functions.php
-
to Vaclav Lesek:
vase riesenie funguje. Zial nie som este taky skuseny v SQL. Mohli by ste mi prosim vas vysvetlit, co to "over partition by" znamena? Rad by som to pochopil a nieco nove sa naucil.
dakujem
Omlouvám se, nějak jsem zapomněl sledovat tento thread. Pokud vám nepomohl odkaz od Pavla, kdyžtak se ozvěte.
-
a co treba
select q.* from (select * from tabulka2 order by datum) q where ROWNUM = 1
tohle musi fungovat urcite, akorat to teda nebude moc efektivni. Ty joiny si uz udelej sam....
toto vrati len jeden zaznam pre vsetko, to nie je dobre.
Podle mě to bylo myšlené jako korelovaný poddotaz, ale ten join si tam musíte doplnit, třeba takhle:
select q.* from (select * from tabulka2 where tabulka1.t1_id=tabulka2.t1_id order by datum) q where ROWNUM = 1
Stejně pořád vrátíte jen jeden záznam. Nebo nevím kam míříte.