Group by with left join - postgresql

I need to to sum (quantity and amount) for each product sold in in the table "account_invoice_line"
SELECT seller.name
ipartner.name AS invoice
brand.name AS brand, pt.name AS product,
SUM(ail.quantity) AS quantity, SUM(ail.price_subtotal) as amount
FROM account_invoice_line ail
LEFT JOIN account_invoice i ON ail.invoice_id = i.id
LEFT JOIN res_partner AS ipartner on ipartner.id = i.partner_id
LEFT JOIN res_users u ON u.id = i.user_id
LEFT JOIN res_partner AS seller ON seller.id = u.partner_id
LEFT JOIN product_product pp ON pp.id = ail.product_id
LEFT JOIN product_template pt ON pt.id = pp.product_tmpl_id
LEFT JOIN brand ON brand.id = pp.brand_id
GROUP BY seller.name, invoice, brand, pt.name
ORDER BY seller.name, invoice, brand, pc.name, pt.name
Unfortunately, I get this king of result:
-
Seller, Invoice, Brand, Product, Quantity, Amount
...
Seller1, Customer1, Brand1, Product1, 5, 4.70
Seller1, Customer1, Brand1, Product1, 10, 9.30
...
I was expecting for this (summed quantity and amount for the same product):
Seller1, Customer1, Brand1, Product1, 15, 14.0

Are you sure you need left joins for all of the tables?
Having account_invoice_line and then add LEFT JOIN, could make that one of the fields is NULL on the other tables, and that might be a reason why you see 2 records instead of one (let's say partner id is NULL in one of them).

If u just group by one column name only (for example: brand), do u still get same result?

Related

COALESCE TSQL with a join tsql

I have a requirement to pick up data that is in more than one place and I have some form of recognition if using the coalesce function. Basically I am looking to coalesce the join itself but looking online its seems as if i can only do this on the fields.
So we have a Products and Suppliers table, we also have these as a temp table so in total 4 tables (products, tempproducts, suppliers, tempsuppliers). In the suppliers and products table is where we store our products and suppliers and their temptables we store any new suppliers/products. We also have a tempsupplierproduct which joins new suppliers to new products. However we can end in a situation where a new supplier has an existing product so the new supplier will be in the tempsuppliers table and its product is in the products table NOT the tempproducts as it is not new, we will also have a new tempsupplierproduct to join the two up.
So i want a query which looks in the tempsupplierproducts table and then gets basic information about the supplier and products. To do this i am using a coalesce.
SELECT DISTINCT SP.*, COALESCE(P.Product, PD.Product) 'Product', COALESCE(S.Supplier, SU.Supplier) 'Supplier'
FROM tempsupplierproduct SP
LEFT JOIN tempProduct P ON SP.ProductCode = P.Code
LEFT JOIN Products PD ON SP.ProductCode = PD.Code
LEFT JOIN tempSupplier S ON SP.SupplierCode = S.Code
LEFT JOIN Suppliers SU ON SP.SupplierCode = SU.Code
Now while this works, something at the back of my head tells me it is not entirely right, ideally i want if data is not in table A then join to table B. I have seen maybe coalescing inside the join itself but I am unsure how to do this
LEFT JOIN Suppliers Su ON SP.SupplierCode = COALESCE(S.Code, SU.Code)
maybe away, but I am confused by this, all it is saying is use code in temptable if not there then use supplier code. So what would this mean if we have a code in the temptable, will this try to join on it, if so then this is incorrect also.
Any help is appreciated
You can union the two suppliers tables together and then join them in one go like this. I'm assuming that there are no duplicates between the two tables in this case but with a bit of extra work that could be resolved as well.
WITH AllSuppliers AS
(
SELECT Code, Supplier FROM Suppliers
UNION ALL
SELECT Code, Supplier FROM tempSupplier
)
SELECT DISTINCT SP.*, COALESCE(P.Product, PD.Product) 'Product', S.Supplier
FROM tempsupplierproduct SP
LEFT JOIN tempProduct P ON SP.ProductCode = P.Code
LEFT JOIN Products PD ON SP.ProductCode = PD.Code
LEFT JOIN AllSuppliers S ON SP.SupplierCode = S.Code
If you need to handle duplicates in the two suppliers tables then an approach like this should work, essentially we rank the duplicates and then pick the highest ranked result. For two tables you could use a full outer join between the two but this approach will scale to any number of tables.
WITH AllSuppliers AS
(
SELECT Code, Supplier, 1 AS TablePriority FROM Suppliers
UNION ALL
SELECT Code, Supplier, 2 AS TablePriority FROM tempSupplier
),
SuppliersRanked AS
(
SELECT Code, Supplier,
ROW_NUMBER() OVER (PARTITION BY Code ORDER BY TablePriority) AS RowPriority
FROM AllSuppliers
)
SELECT DISTINCT SP.*, COALESCE(P.Product, PD.Product) 'Product', S.Supplier
FROM tempsupplierproduct SP
LEFT JOIN tempProduct P ON SP.ProductCode = P.Code
LEFT JOIN Products PD ON SP.ProductCode = PD.Code
LEFT JOIN SuppliersRanked S ON SP.SupplierCode = S.Code
AND RowPriority = 1
You can absolutely join on a coalesced field. Here is a snippet from one of my production views:
LEFT JOIN [Portal].tblHelpdeskresource supplier ON PO.fld_str_SupplierID = supplier.fld_str_SupplierID
-- Job type a
LEFT JOIN [Portal].tblHelpDeskFault HDF ON PO.fld_int_HelpdeskFaultID = HDF.fld_int_ID
-- Job Type b
LEFT JOIN [Portal].tblProjectHeader PH ON PO.fld_int_ProjectHeaderID = PH.fld_int_ID
LEFT JOIN [Portal].tblPPMScheduleLine PSL ON PH.fld_int_PPMScheduleRef = PSL.fld_int_ID
-- Managers (used to be separate for a & b type, now converged)
LEFT JOIN [Portal].uvw_HelpDeskSiteManagers PSM ON COALESCE(PSL.fld_int_StoreID,HDF.fld_int_StoreID) = PSM.PortalSiteId
LEFT JOIN [Portal].tblHelpdeskResource PHDR ON PSM.PortalResourceId = PHDR.fld_int_ID

GROUP BY AND RIGHT JOINS IN DB2

Select p.prodCode,
p.description,
p.unit,
SUM(sd.quantity) "Total quantity"
FROM salesDetail sd
RIGHT JOIN product p
ON p.prodCode = sd.prodCode
GROUP BY p.prodCode
ORDER BY 4 DESC
Help! My Script is not running. I need to get the total quantity of every product but my group by is not working.
Compute the sum of the quantity per product in separate subquery, and then join this back to the original product table:
SELECT t1.prodCode,
t1.description,
t1.unit,
t2.total_quantity
FROM product t1
INNER JOIN
(
SELECT p.prodCode, SUM(sd.quantity) total_quantity
FROM product p
LEFT JOIN salesDetail sd
ON p.prodCode = sd.prodCode
GROUP BY p.prodCode
) t2
ON t1.prodCode = t2.prodCode
Note that I replaced the RIGHT JOIN with a LEFT JOIN by switching the order of the joined tables in the subquery.
Update:
If you absolutely need to use a RIGHT JOIN, then just replace the subquery with this:
SELECT p.prodCode, SUM(sd.quantity) total_quantity
FROM salesDetail sd
RIGHT JOIN product p
ON p.prodCode = sd.prodCode
GROUP BY p.prodCode

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

I need to count the right amount of discount with the right country, how do i do this?

this is the code i have atm:
SELECT Discount,
country,
count(country) AS total
FROM OrderDetails,
Customers
WHERE discount != 0
GROUP BY Discount,
country
HAVING ( count(country) > 0 )
ORDER BY discount DESC
what i need to do now, and can't find anywhere, is to have the count(country) add up with the right Discount numbers. That way i know how much discount each country has gotten.
I have looked everywhere and i can't find anything. Even in my own papers i got from school.
so this is the code with the join, so it's a little more clear to look at:
select Discount, country, count(country) as total
from Orders O
join Customers C
on C.CustomerID = O.CustomerID
join OrderDetails OD
on OD.OrderID = O.OrderID
where discount != 0
group by Discount, country
having (count(country)>0)
order by discount DESC
select c.country, sum(od.discount) as totalDiscount
from orders o
inner join customers c
on c.customerID = o.customerID
inner join orderDetails od
on od.orderID = o.orderID
where od.discount != 0
group by c.country
order by sum(od.discount) desc

T-SQL filter on external join

Using the schema below, write a query which lists the total value of all sales for customers who bought an item from a sales person with the same middle initial as them. Your query should return a single result.
The quantity and price columns are both ints.
The Sales - Employee link is on EmployeeID - SalesPersonID.
Something like this should work:
select sum(s.Quantity * p.Price) as TotalSales
from Sales s
join Products p on s.ProductID = p.ProductID
join Customers c on s.CustomerID = c.CustomerID
join Empleyees e on s.SalesPersonID = e.EmployeeID
where c.MiddleInitial = e.MiddleInitial