webForumDet fria alternativet

Outer join mot två tabeller

2 svar · 1 221 visningar · startad av henkus

henkusMedlem sedan jan. 20111 inlägg
#1

Jag har tre tabeller:
ARTIKEL
ARTIKELNR,ARTIKELNAMN
1,Test1
2,Test2
3,Test3

InventeringHead
ID, DATUM
1,2010-01-01
2,2010-01-02
3,2010-01-02

InventeringPos
ID,ARTIKELNR, ANTAL
1,1,10
1,3,20
2,1,5
2,3,6
3,3,10

Önskat resultat:
ARTIKEL.ARTIKELNR, COUNT(distinct InventeringHead.ID)
Där jag ser alla artiklar från ARTIKEL.
Jag kan göra en OUTER JOIN - mitt problem är att jag inte fattar hur jag skall skriva eftersom jag först behöver OUTER JOINA ARTIKEL mot InventeringPos, som i sin tur skall vara INNER JOINad mot InventeringHead.
Just nu ser min query ut såhär:
select artikel.artikelnr, count(distinct InventeringHead.ID)
from artikel
right outer join InventeringPos
on artikel.artikelnr=InventeringPos.artikelnr
left join InventeringHead
on InventeringPos.ID=InventeringHead.ID
group by artikelnr;

Vilket resulterar i resultatet:
1,2
3,3

Jag vill alltså ha:
1,2
2,0
3,3

@ndersMedlem sedan juni 200032 969 inlägg
#2

Ett alternativ är att göra uträkningen med en subquery.

select a.artikelnr, 
   (select count(distinct ih.id) from inventeringpos ip inner join inventeringhead ih on ih.id = ip.id and ip.artikelnr = a.artikelnr) as antal
from artikel a
order by a.artikelnr

mvh

adde2Medlem sedan maj 2000144 inlägg
#3

4 alternativ

4 olika förslag.
Kör man detta i sql server 2008 och tittar på executionplanen så är alla alternativen lika snabba.

Tar man bort indexen så är de tre sista alternativen aningens snabbare än den första. 29%, 24%, 24% och 24% av totala exekveringstiden.
(frågeoptimeraren skapar samma queryplan för 2,3 & 4)

Jag har dock fått lära mig en gång i tiden att man ska undvika om man kan att nästla sqlfrågor direkt i projektionen (av prestandaskäl).

Eftersom att vi har VÄLDIGT lite data i tabellerna så kan man egentligen inte dra några slutsatser om hastighet (även om det är kul att dra förhastade slutsatser). Det är mycket möjligt att servern skulle optimera annorlunda om det handlar om större volymer data.

create table #artikel (ARTIKELNR int, ARTIKELNAMN nvarchar(20));
create table #InventeringHead (id int, datum date);
create table #InventeringPos (id int, artikelnr int, antal int);

create index ix on #artikel(artikelnr);
create index ix on #InventeringHead(id);
create index ix on #InventeringPos(id,artikelnr);

insert into #artikel values (1, 'test1');
insert into #artikel values (2, 'test2');
insert into #artikel values (3, 'test3');

insert into #InventeringHead values (1, '2010-01-01');
insert into #InventeringHead values (2, '2010-01-02');
insert into #InventeringHead values (3, '2010-01-02');

insert into #InventeringPos values (1,1,10);
insert into #InventeringPos values (1,3,20);
insert into #InventeringPos values (2,1,5);
insert into #InventeringPos values (2,3,6);
insert into #InventeringPos values (3,3,10);

select a.artikelnr, 
   (select count(distinct ih.id) from #inventeringpos ip inner join #inventeringhead ih on ih.id = ip.id and ip.artikelnr = a.artikelnr) as antal
from #artikel a
order by a.artikelnr;

select a.ARTIKELNR, coalesce(t.antal,0)
from #artikel a
left outer join (select COUNT(distinct h.id) as antal, p.artikelnr from #InventeringPos p inner join #InventeringHead h on p.id = h.id group by p.artikelnr) t on a.ARTIKELNR = t.artikelnr;

select a.ARTIKELNR, coalesce(t.antal,0)
from #artikel a
outer apply (select COUNT(distinct h.id) as antal, p.artikelnr from #InventeringPos p inner join #InventeringHead h on p.id = h.id where a.ARTIKELNR = p.artikelnr group by p.artikelnr) t;

with data
as
(
	select COUNT(distinct h.id) as antal, p.artikelnr from #InventeringPos p inner join #InventeringHead h on p.id = h.id group by p.artikelnr
)
select a.ARTIKELNR, coalesce(d.antal,0)
from #artikel a
left outer join data d on a.ARTIKELNR = d.artikelnr;
125 ms totalt · 3 externa anrop · v20260731065814-full.30151723
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
123 ms — hämta tråd, inlägg och bilagor (db)