2016-06-30 9 views
2

Es gibt eine Rechnungstabelle mit der Person, die die Rechnung erstellt hat. Eine Person kann zu mehreren Büros gehören, nur ein Hauptbüro pro Person, aber dieselbe Person kann mehrere Rollen pro Büro haben.SQL Server 2012: So erhalten Sie die Anzahl der Gruppen aus mehreren Tabellen-Joins

declare @person table (personid int) 
declare @office table (officeid int, officename varchar(10)) 
declare @personoffice table (personid int, officeid int, mainoffice bit, personrole varchar(10)) 
declare @invoice table (personid int) 

insert into @person values (1), (2), (3), (4) 
insert into @office values (1, 'office1'), (2, 'office2'), (3, 'office3'), (4, 'office4') 
insert into @personoffice values (1, 1, 1, 'role1'), (1, 1, 1, 'role2'), (1, 2, 0, 'role1'), (1, 3, 0, 'rolex'), (2, 2, 1, 'role1'), (2, 2, 1, 'role2'), (2, 3, 0, 'rolex'), (3, 3, 1, 'role1'), (3, 4, 0, 'role2') 
insert into @invoice values (1), (1), (1), (2), (2), (3), (3), (3), (3), (3) 

So für dieses Beispiel, das wir 3 Personen haben, gehören sie mehrere Büros, sondern nur ein Hauptamt jeweils aber einige Personen haben mehrere Rollen pro Büro. Sie haben jeweils mehrere Rechnungen erstellt.

kann ich die Anzahl der Rechnungen pro Person erhalten mit:

select 
    i.personid, 
    count(*) InvoiceCountByPerson 
from 
    @invoice i 
inner join 
    @person p on p.personid = i.personid 
group by 
    i.personid 

, die zurückgibt:

personid InvoiceCountByPerson 
-------------------------------- 
    1    3 
    2    2 
    3    5 

Ich brauche von Hauptbüro Name Anzahl der Rechnungen zu erhalten. Person1 dessen Hauptbüro ist office1 3 erstellt Rechnungen, Person2 dessen Hauptbüros sind office2 2 erstellt Rechnungen und Person3 dessen Hauptbüros ist office3 5 erstellt Rechnungen so erwartetes Ergebnis:

officename InvoiceCountByOfficeName 
------------------------------------ 
office1    3 
office2    2 
office3    5 

Dies funktioniert nicht:

select 
    o.officename, 
    count(*) InvoiceCountByOfficeName 
from 
    @invoice i 
inner join 
    @person p on p.personid = i.personid 
inner join 
    @personoffice po on po.personid = p.personid AND po.mainoffice = 1 
inner join 
    @office o on o.officeid = po.officeid 
group by 
    o.officename 

wie es zurückgibt:

officename InvoiceCountByOfficeName 
------------------------------------- 
office1     6 
office2     4 
office3     5 

als die gleiche Person mehr Mainoffice = 1 Datensätze mit unterschiedlichen Rollen hat, muß ich auf dem @personof eine Art verschieden haben Fice beitreten. Auch bei Millionen von Rechnungen muss die Leistung berücksichtigt werden.

+0

Ich bin so froh, jedes Mal wenn ich eine SQL-Frage gelesen habe, die gut formatiert ist :-). +1 nur für die Aufnahme aller relevanten Details. –

+0

'inner join (wählen Sie distinct ... von @personoffice)'? –

+0

Also brauchen Sie die Rechnungen, um zur ersten Hauptstelle zu gehören? – DhruvJoshi

Antwort

2

Sie sind so nah ... Alles, was Sie tun musste, ist eine abgeleitete Tabelle zu verwenden, anstatt die @personoffice Tabelle direkt zu verwenden:

select 
    o.officename, 
    count(*) InvoiceCountByOfficeName 
from 
    @invoice i 
inner join 
    @person p on p.personid = i.personid 
inner join 
    (
     select distinct personid, officeid 
     from @personoffice 
     where mainoffice = 1 
    ) 
    po on po.personid = p.personid 
inner join 
    @office o on o.officeid = po.officeid 
group by 
    o.officename 

Ergebnisse:

officename InvoiceCountByOfficeName 
---------- ------------------------ 
office1 3 
office2 2 
office3 5 
+0

Wird die abgeleitete Tabelle nur einmal oder einmal pro Person ausgeführt? – curious

+0

abgeleitete Tabellen werden nur einmal ausgeführt, wie bei Unterabfragen (selects innerhalb der select-Klausel), die für jede Zeile in der Hauptauswahlklausel ausgeführt werden. –

1
select 
     o.officename, 
     count(*) InvoiceCountByOfficeName 
    from 
     @invoice i 
    inner join 
     @person p on p.personid = i.personid 
    inner join 
     (
     select distinct personid,officeid,mainoffice from @personoffice 
     ) po on po.personid = p.personid AND po.mainoffice = 1 
    inner join 
     @office o on o.officeid = po.officeid 
    group by 
     o.officename 

Dank

+0

Es ist besser, die 'mainoffice = 1'-Bedingung als where-Klausel in der abgeleiteten Tabelle zu setzen. –