2015-10-03 6 views
5

die folgende StrukturPostgres mit selbst zählen Referenz Joinbedingung

CREATE TABLE products (
    id integer NOT NULL, 
    subcategory_id integer, 
    stack_id integer, 
) 

CREATE TABLE subcategories (
    id integer NOT NULL, 
    name character varying(255) 
) 

Wo products.stack_id ist eine selbstReferenzBeziehung zurück zu den Produkten gegeben.

Ich bin im Grunde eine Zählung der Unterkategorien zu tun versuchen beitreten Produkte auf

products.subcategory_id = subcategories.id 

aber die Zählung auf einmal pro deutliche Stapelungsgruppe begrenzen.

Probe Unterkategorien Tabelle

id name 
1  subcategory_1 
2  subcategory_2 
3  subcategory_3 

Probenprodukte Tabelle

id subcategory_id stack_id  
1  1     NULL   
2  1     1   
3  2     1   
4  3     1   
5  2     NULL   
6  2     5   
7  2     5   
8  2     NULL   
9  3     8   
10 3     8 

Probe gewünschte Ausgangs

id name    total 
1  subcategory_1 1  (row 1) 
2  subcategory_2 3  (row 1 + row 5 + row 8) 
3  subcategory_3 2  (row 1 + 8) 

Erklärung der Ausgabe

Unterkategorie-ID 1
Wenn ich eine einfache mit Produkten kommen habe ich Produkte erhalten würde (1, 2). Ich möchte nur die Anzahl der verschiedenen übergeordneten Objekte (stack_id ist null), also 1 zählt und 2 Referenzen 1, die bereits gezählt wurde, so erhöht nicht die Anzahl.

Unterkategorie id 2
Join wäre (3, 5, 6, 7, 8). 3's stack_id ist 1, also zählt es 1. Produkte 5, 6 und 7 Referenz 5, so zählt 1. Produkt 8 zählt 1.

Unterkategorie 3
Join ist (4, 9, 10). 4 Referenzen 1 und 9 und 10 beide Referenz 8.

aktualisieren

entfernt zusätzliche möglicherweise verwirrende Spalten hinzugefügt Abtastdaten und Ausgang

+0

Beispieldaten und die gewünschten Ergebnisse wirklich kommunizieren würden helfen, was Sie tun mögen. –

Antwort

2

Wenn die maximale Tiefe von Referenzen eine Ebene ist, dann ist dieser einfache Abfrage macht den Job:

select subcategory_id, name, count(*) 
from (
    select distinct subcategory_id, coalesce(stack_id, id) stack_id 
    from products 
    ) sub 
join subcategories s on s.id = sub.subcategory_id 
group by 1, 2 
order by 1, 2; 

subcategory_id |  name  | count 
----------------+---------------+------- 
       1 | subcategory_1 |  1 
       2 | subcategory_2 |  3 
       3 | subcategory_3 |  2 
(3 rows) 

Diese rekursive Abfrage richtig auch auf Referenzen tiefer als eine Ebene funktioniert:

with recursive pr(id, subcategory_id, stack_id, stack) as (
    select id, subcategory_id, stack_id, array[id] 
    from products 
union 
    select pr.id, pr.subcategory_id, products.stack_id, pr.stack_id || pr.stack 
    from pr 
    join products on pr.stack_id = products.id 
    ) 
select distinct on (id) id, subcategory_id, stack 
from pr 
order by id, array_length(stack, 1) desc 

id | subcategory_id | stack 
----+----------------+-------- 
    1 |    1 | {1} 
    2 |    1 | {1,2} 
    3 |    2 | {1,3} 
    4 |    3 | {1,4} 
    5 |    2 | {5} 
    6 |    2 | {5,6} 
    7 |    2 | {5,7} 
    8 |    2 | {8} 
    9 |    3 | {8,9} 
10 |    3 | {8,10} 
(10 rows) 

Join Unterkategorien mit dem obigen Daten-Set:

select subcategory_id, name, count(*) 
from (
    select distinct subcategory_id, stack[1] 
    from (
     with recursive pr(id, subcategory_id, stack_id, stack) as (
      select id, subcategory_id, stack_id, array[id] 
      from products 
     union 
      select pr.id, pr.subcategory_id, products.stack_id, pr.stack_id || pr.stack 
      from pr 
      join products on pr.stack_id = products.id 
      ) 
     select distinct on (id) id, subcategory_id, stack 
     from pr 
     order by id, array_length(stack, 1) desc 
     ) sub 
    ) sub 
join subcategories s on s.id = sub.subcategory_id 
group by 1, 2 
order by 1, 2 

subcategory_id |  name  | count 
----------------+---------------+------- 
       1 | subcategory_1 |  1 
       2 | subcategory_2 |  3 
       3 | subcategory_3 |  2 
(3 rows)  
+0

Vielen Dank für eine so detaillierte Antwort. Ich habe beide Ansätze ausprobiert und sie funktionieren perfekt! – djohnson