Subqueries and Combining Queries together - postgresql

I have a problem I've been working on. I've broken it down to a couple of steps below. I have trouble combining all the queries together to solve the following:
Find members who have spent over $1000 in departments that have
brought in more than $10000 total ordered by the members' id.
Schema:
departments(id, name)
products (id, name, price)
members(id, name, number, email, city, street_name, street_address)
sales(id, department_id, product_id, member_id, transaction_date
Step 1)
I found the departments that have brought in more than 10,000$
select s.department_id
from sales s join products p on
s.product_id = p.id
group by s.department_id
having sum(price) > '10000'
Step 2) I found the members and the departments that they shop in
select *
from members m
join sales s
on m.id = s.member_id
join departments d
on d.id = s.department_id
Step 3) I combined 1 and 2 to find members taht shop in departments that have brought in more than 10,000
select *
from members m
join sales s
on m.id = s.member_id
join departments d
on d.id = s.department_id
where s.department_id in
(select s.department_id
from sales s join products p on
s.product_id = p.id
group by s.department_id
having sum(price) > '10000')
Step 4) I found members and their id, email, total_spending > 1,000$
select m.id, m.name, m.email, sum(price) as total_spending
from members m join sales s on
m.id = s.member_id
join products p on
p.id = s.product_id
group by m.id
having sum(price) > '1000'
Step 5)
All of the steps work individually but when I put them together in my attempt:
select m.id, m.name, m.email, sum(price) as total_spending
from members m join sales s on
m.id = s.member_id
join products p on
p.id = s.product_id
where m.id in (select distinct m.id
from members m
join sales s
on m.id = s.member_id
join departments d
on d.id = s.department_id
where s.department_id in
(select s.department_id
from sales s join products p on
s.product_id = p.id
group by s.department_id
having sum(price) > '10000'))
group by m.id
having sum(price) > '1000'
The output is wrong. (This is on CodeWars) If someone could point me in the right direction that would be really great! Thank you.

Try to group by member_id and department_id:
select s.member_id,s.department_id,sum(p.price) as total_spending
from members m
join sales s on m.id = s.member_id
join products p on p.id = s.product_id
where s.department_id in (
select s.department_id
from sales s
join products p on s.product_id = p.id
group by s.department_id
having sum(p.price) > 10000 -- the departments which brought in more than $10000 total
)
group by s.member_id,s.department_id
having sum(p.price) > 1000 -- who have spent over $1000 in one department
And if you need you will able to calc how much spent each of members:
select member_id,sum(total_spending) total
from
(
-- the first query is here
) q
group by member_id

Related

SQL query involving specific count with distinct

I have these tables:
person (id primary key, name)
money (acct primary key, loaner)
loan (id primary key, acct)
How would I create a SQL query that shows for each loaner the names of persons who took more than four loans from that specific loaner? And I want the 4 persons that he loaned to be different with each other.
SELECT
p.id, p.name, m.loaner, COUNT(*)
FROM
person p
INNER JOIN
loan l ON p.id = l.id
INNER JOIN
money m ON l.acct = m.acct
GROUP BY
id, name, lower
HAVING
COUNT(*) = 4
With this query you can find the first part of the question - what should I add?
I would try this out and see what happens :D
SELECT distinct *
FROM person as p_loaner_detailed
WHERE p_loaner_detailed.id in (
SELECT loanerId
FROM (
SELECT p.id, p.name, m.loaner as loanerId
COUNT(*)
FROM person p
INNER JOIN loan l
ON p.id = l.id
INNER JOIN money m
ON l.acct = m.acct
GROUP BY id, name, loanerId
HAVING COUNT(*) > 4
)
)

Problems with Postgresql ERROR: subquery uses ungrouped column "ev.title" from outer query

I have a query like this:
select c.id, c.name, c.website, c.longdescription, c.description, c.email,
(SELECT jsonb_agg(ev) FROM
(SELECT ev.title, ev.description, ev.longdescription,
(SELECT jsonb_agg(ed) FROM
(SELECT ed.startdate, ed.enddate, ed.id WHERE ed.id notnull)ed) as dates, ev.id WHERE ev.id notnull) ev) as events,
(SELECT jsonb_agg(ca) FROM (SELECT ct.zip, ca.id, ca.street1, ca.street2, ca.addresstype_id, ST_Y(ca.geopoint::geometry) as latitude, ST_X(ca.geopoint::geometry) as longitude
WHERE ca.id notnull)ca) as addresses
FROM companies c
LEFT JOIN events ev ON ev.company_id = c.id
LEFT JOIN companyaddresses ca ON ca.company_id = c.id
LEFT JOIN cities ct ON ct.id = ca.city_id
LEFT JOIN eventdates ed ON ed.event_id = ev.id
GROUP by c.id
I am getting the error "ERROR: subquery uses ungrouped column "ev.title" from
outer query Position: 125".
Can't figure out how to group it correctly for the subqueries. Any suggestions?
Give this a try:
SELECT c.id, c.name, c.website, c.longdescription, c.description, c.email,
    (SELECT jsonb_agg(ev) FROM
        (SELECT even.title, even.description, even.longdescription,
            (SELECT jsonb_agg(ed) FROM
                (SELECT eventdates.startdate, eventdates.enddate, eventdates.id FROM eventdates WHERE eventdates.event_id = even.id)ed) as dates,
        even.id FROM events even WHERE even.company_id = c.id) ev) as events,
jsonb_agg((SELECT ca FROM (SELECT ct.zip, ca.id, ca.street1, ca.street2, ca.addresstype_id, ST_Y(ca.geopoint::geometry) as latitude, ST_X(ca.geopoint::geometry) as longitude WHERE ca.id notnull)ca)) as addresses
FROM companies c
LEFT JOIN companyaddresses ca ON ca.company_id = c.id
LEFT JOIN cities ct ON ct.id = ca.city_id
Group by c.id

Postgres: Getting a total related count based on a condition from a related table

My sql-fu is not strong, and I'm sure I'm missing something simple in trying to get this working. I have a fairly standard group of tables:
users
-----
id
name
carts
-----
id
user_id
purchased_at
line_items
----------
id
cart_id
product_id
products
--------
id
permalink
I want to get a total count of purchased carts for each user, if that user has purchased a particular product. That is: if at least one of their purchased carts has a product with a particular permalink, I'd like a count of the total number of purchased carts, regardless of their contents.
The definition a purchased cart is when carts.purchased_at is not null.
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
The numbers that are coming up for purchased_carts are strangely high, possibly related to the total number of line items multiplied by the number of carts? Maybe? I'm pretty stumped at the result. Any help would be greatly appreciated.
This ought to help:
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;
The exists predicate is a semi-join.
bool_or is what you need
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

Return records if all conditions Match

I need a query to return records if all conditions Match.
Example:
Lets say I have a User “John” (UserID: '37') that belongs to groups 'A','B','C' (GroupID: '47', '48', '166')
And I type
Select person, group
from persons p inner join groups g
on p.id = g.id
where p.id = '37'
and g.id in ('47','166')
The query should return No Record because not all conditions match, Group 'C' was not part of the query.
How can I do this?
This has to be a dup but I cannot find it
Select p.id
from persons p inner join groups g
on p.id = g.UserID
where p.id = '37'
and g.GroupID in ('47','166')
group by person
having count(*) = 2
--The subquery did what I was after
SELECT p.id, g.id
FROM persons p inner join groups g
on p.id = g.Userid
where g.Userid =
(select Userid from groups gs
where p.id = gs.Userid
And gs.id in (47,166)
group by g.Userid
having count(distinct gs.id) = 3)

Join two queries become one subquery

I want to ask how to combine these two queries become one subquery?
select c.CustomerName, A.Qty
from Customer c join (select s.CustomerID, pd.Date, s.Qty
from Period pd join Sales s on pd.TimeID = s.TimeID) A on c.CustomerID = A.CustomerID
where #Date = A.Date
and
select sum(case when (pd.Date between '2010-03-15' and #Date) then s.Qty else 0 end) as TotalQty
from Period pd full join Sales s on pd.TimeID = s.TimeID full join Customer c on s.CustomerID = c.CustomerID
group by c.CustomerName, c.CustomerID
They should result one table contains these following columns: CustomerName, Qty, and TotalQty. I've tried many ways but they didn't work at all. Really hope your help, thanks.
Answering your question assuming you are looking at the result as one row and not "column" :
select c.CustomerName, A.Qty,(select sum(case when (pd.Date between '2010-03-15' and #Date) then s.Qty else 0 end)
from Period pd full join Sales s on pd.TimeID = s.TimeID full join Customer c on s.CustomerID = c.CustomerID
group by c.CustomerName, c.CustomerID
) as TotalQty
from Customer c join (select s.CustomerID, pd.Date, s.Qty
from Period pd join Sales s on pd.TimeID = s.TimeID) A on c.CustomerID = A.CustomerID
where #Date = A.Date
If you still want the result as a single column , google "row to column transpose"