Oracle: pomoc s SQL dotazem

Pupi1

Oracle: pomoc s SQL dotazem
« kdy: 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;
« Poslední změna: 20. 02. 2014, 10:28:56 od Petr Krčmář »


Pupi1

Re:Pomoc s SQL dotazom - ORACLE
« Odpověď #1 kdy: 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ěkdo

Re:Pomoc s SQL dotazom - ORACLE
« Odpověď #2 kdy: 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.

Re:Pomoc s SQL dotazom - ORACLE
« Odpověď #3 kdy: 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?

Re:Pomoc s SQL dotazom - ORACLE
« Odpověď #4 kdy: 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.


Kolemjdoucí

Re:Pomoc s SQL dotazom - ORACLE
« Odpověď #5 kdy: 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

Re:Pomoc s SQL dotazom - ORACLE
« Odpověď #6 kdy: 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 :)

Kolemjdoucí

Re:Pomoc s SQL dotazom - ORACLE
« Odpověď #7 kdy: 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.

Pupi1

Re:Oracle: pomoc s SQL dotazem
« Odpověď #8 kdy: 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.

Petr

Re:Oracle: pomoc s SQL dotazem
« Odpověď #9 kdy: 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....

Pupi1

Re:Pomoc s SQL dotazom - ORACLE
« Odpověď #10 kdy: 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

Pupi1

Re:Oracle: pomoc s SQL dotazem
« Odpověď #11 kdy: 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.

Petr

Re:Oracle: pomoc s SQL dotazem
« Odpověď #12 kdy: 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

Pupi1

Re:Oracle: pomoc s SQL dotazem
« Odpověď #13 kdy: 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.

Kolemjdoucí

Re:Oracle: pomoc s SQL dotazem
« Odpověď #14 kdy: 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