2016-07-11 12 views
1

Meine sql-fu ist nicht stark, und ich bin sicher, ich vermisse etwas Einfaches in dem Versuch, das funktioniert zu bekommen. Ich habe eine ziemlich Standard-Gruppe von Tabellen:Postgres: Ermitteln einer Gesamtzahl von verwandten basierend auf einer Bedingung aus einer verwandten Tabelle

users 
----- 
id 
name 


carts 
----- 
id 
user_id 
purchased_at 


line_items 
---------- 
id 
cart_id 
product_id 


products 
-------- 
id 
permalink 

Ich mag für jeden Benutzer eine Gesamtzahl von gekauften Wagen bekommen, wenn der Benutzer ein bestimmtes Produkt gekauft hat. Das heißt: Wenn mindestens einer ihrer gekauften Wagen ein Produkt mit einem bestimmten Permalink hat, möchte ich die Gesamtzahl der gekauften Wagen ungeachtet ihres Inhalts zählen.

Die Definition eines gekauften Einkaufswagens lautet, wenn carts.purchased_at nicht null ist.

select 
    u.id, 
    count(c2.*) as purchased_carts 

from users u 

inner join carts c on u.id = c.user_id 
inner join line_items li on c.id = li.cart_id 
inner join products p on p.id = li.product_id 
left join carts c2 on u.id = c2.user_id 

where 
    c.purchased_at is not NULL 
    and 
    c2.purchased_at is not NULL 
    and 
    p.permalink = 'product-name' 
group by 1 
order by 2 desc 

Die Zahlen, die möglicherweise für purchased_carts kommen werden, sind seltsam hoch, durch die Anzahl der Wagen, multipliziert mit der Gesamtzahl der Positionen im Zusammenhang? Könnte sein? Ich bin ziemlich überrascht über das Ergebnis. Jede Hilfe würde sehr geschätzt werden.

Antwort

1

Dies sollte helfen:

select u.id, 
     count(*) 
from users u join 
     carts c on c.user_id = u.id 
where c.purchased_at is not NULL and 
     exists (
     select null 
     from carts  c2 
     join line_items l on l.cart_id = c2.id 
     join products p on p.id  = l.product_id 
     where c2.user_id  = u.id and 
       c2.purchased_at is not NULL 
       p.permalink  = 'product-name') 
group by u.id 
order by count(*) desc; 

Das existiert Prädikat ist ein Semi-Join.

1

bool_or ist, was Sie brauchen

select 
    u.id, 
    count(distinct c.id) as purchased_carts 
from 
    users u 
    inner join 
    carts c on u.id = c.user_id 
    inner join 
    line_items li on c.id = li.cart_id 
    inner join 
    products p on p.id = li.product_id 
where c.purchased_at is not NULL 
group by u.id 
having bool_or (p.permalink = 'product-name') 
order by 2 desc