Fórum Root.cz

Hlavní témata => Server => Téma založeno: Pupi1 19. 02. 2014, 18:14:06

Název: Oracle: pomoc s SQL dotazem
Přispěvatel: 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:

Kód: [Vybrat]
--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;
Název: Re:Pomoc s SQL dotazom - ORACLE
Přispěvatel: Pupi1 19. 02. 2014, 18:29:05
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.
Název: Re:Pomoc s SQL dotazom - ORACLE
Přispěvatel: Někdo 19. 02. 2014, 21:22:38
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.
Název: Re:Pomoc s SQL dotazom - ORACLE
Přispěvatel: Václav Lešek 19. 02. 2014, 21:58:03
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?
Název: Re:Pomoc s SQL dotazom - ORACLE
Přispěvatel: Václav Lešek 19. 02. 2014, 22:06:31
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:
Kód: [Vybrat]
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:
Kód: [Vybrat]
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.
Název: Re:Pomoc s SQL dotazom - ORACLE
Přispěvatel: Kolemjdoucí 19. 02. 2014, 23:13:18
Váš požadavek by mohl splnit snad následující select:
Kód: [Vybrat]
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:

Kód: [Vybrat]
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
Název: Re:Pomoc s SQL dotazom - ORACLE
Přispěvatel: Václav Lešek 20. 02. 2014, 08:56:38

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 :)
Název: Re:Pomoc s SQL dotazom - ORACLE
Přispěvatel: Kolemjdoucí 20. 02. 2014, 10:18:15
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.
Název: Re:Oracle: pomoc s SQL dotazem
Přispěvatel: Pupi1 20. 02. 2014, 21:16:48
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.
Název: Re:Oracle: pomoc s SQL dotazem
Přispěvatel: Petr 20. 02. 2014, 21:47:50
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....
Název: Re:Pomoc s SQL dotazom - ORACLE
Přispěvatel: Pupi1 20. 02. 2014, 21:53:14
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:
Kód: [Vybrat]
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:
Kód: [Vybrat]
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
Název: Re:Oracle: pomoc s SQL dotazem
Přispěvatel: Pupi1 20. 02. 2014, 21:54:13
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.
Název: Re:Oracle: pomoc s SQL dotazem
Přispěvatel: Petr 20. 02. 2014, 22:11:22
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
Název: Re:Oracle: pomoc s SQL dotazem
Přispěvatel: Pupi1 20. 02. 2014, 22:30:24
ja som skusal uz nieco podobne ako si napisal, nerobil som ctrl+c/v ;)

jedno riesenie co som vymyslel a vyskusal je toto:

Kód: [Vybrat]
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.
Název: Re:Oracle: pomoc s SQL dotazem
Přispěvatel: Kolemjdoucí 21. 02. 2014, 10:45:42
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
Název: Re:Oracle: pomoc s SQL dotazem
Přispěvatel: Pupi1 21. 02. 2014, 11:02:56
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
Název: UTFG
Přispěvatel: Pavel... 21. 02. 2014, 11:29:18
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
Název: Re:Oracle: pomoc s SQL dotazem
Přispěvatel: Václav Lešek 03. 03. 2014, 21:44:05
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.
Název: Re:Oracle: pomoc s SQL dotazem
Přispěvatel: Václav Lešek 03. 03. 2014, 21:46:50
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.