Actual Data
using these queries:
Select P.productid, Sum(pr.quantity) AS PQuantity from Products p
join purchases pr on pr.Productid = p.productid
group by p.productid;
Select P.productid, Sum(s.quantity) AS SQuantity from Products p
join Sales s on s.Productid = p.productid
group by p.productid;
This is the content in my tables (Purchases and Sales), the one on the right is the Sum with group by:
Problem:
select p.productid, sum(pr.quantity) as PQuantity, sum(s.quantity) as SQuantity
from products p
join sales s on p.productid = s.productid
join purchases pr on p.productid = pr.productid
group by p.productid
But the problem arises when I join three tables:
products
purchases
sales
You'll have to sum the figures before joining, something like this:
select isnull(P.productid, S.productid), P.PQuantity, S.SQuantity
from
(
Select P.productid, Sum(pr.quantity) AS PQuantity from Products p
join purchases pr on pr.Productid = p.productid
group by p.productid
) P
full outer join
(
Select P.productid, Sum(s.quantity) AS SQuantity from Products p
join Sales s on s.Productid = p.productid
group by p.productid
) S on S.productid = P.productid
Related
I am using the Northwind database
For now i have tried
It is where i select the Orders of the Client
select od.ProductID from Customers c JOIN
Orders o on c.CustomerID=o.CustomerID
JOIN [Order Details] od on o.OrderID=od.OrderID
where c.CustomerID='CENTC'
And here is my solution
select distinct c.CompanyName, sum(od.ProductID) as suma from Customers c JOIN
Orders o on c.CustomerID=o.CustomerID
JOIN [Order Details] od on o.OrderID=od.OrderID
where od.ProductID = '40' or od.ProductID = '11'
group by c.CompanyName
having sum(od.ProductID)='51'
But it's a one use solution so i am not satisfied.
You can use an IN subquery for this
SELECT
c.CompanyName,
c.ContactName,
SUM(od.quantity) AS quantity
FROM Customers c
JOIN Orders o on c.CustomerID = o.CustomerID
JOIN OrderDetails od on o.OrderID = od.OrderID
WHERE od.ProductID IN (
SELECT od2.ProductID
FROM Orders o2
JOIN OrderDetails od2 on o2.OrderID = od2.OrderID
WHERE o2.CustomerID = 'CENTC'
)
GROUP BY
c.CustomerID,
c.CompanyName,
c.ContactName;
I have a query like this:
SELECT
*
FROM Product.Stock AS PS
INNER JOIN Product.Product AS P ON PS.ProductId = P.ProductId
INNER JOIN Product.ProductDetail AS PD ON P.ProductId = PD.ProductId
INNER JOIN Product.ProductSize AS PSI ON P.ProductId = PSI.ProductId
I want to know how many ProductsId with same SizeId I have, for example:
in this case I have two products with same ProductId and SizeId, so I wish get: 2 because I have 2 products with sizeId 1
ProductId comes from table: Product.Product
SizeId comes from table: Product.ProductSize
How can I achieve it? Regards
SELECT
PSI.SizeId, COUNT(DISTINCT P.ProductId)
FROM Product.Stock AS PS
INNER JOIN Product.Product AS P ON PS.ProductId = P.ProductId
INNER JOIN Product.ProductDetail AS PD ON P.ProductId = PD.ProductId
INNER JOIN Product.ProductSize AS PSI ON P.ProductId = PSI.ProductId
GROUP BY PSI.SizeId
I'm assuming that the SizeId column is in the Product.ProductSize table.
Agree with #Jack's answer, still I think joins seem to be redundant here.
SELECT
SizeId, COUNT(DISTINCT ProductId)
FROM Product.ProductSize
GROUP BY SizeId
Use Having Count in order to just show sizes with multiple products and no need for inner joins, since you already have all the fields in one table:
SELECT SizeId, COUNT(Distinct ProductId)
FROM Product.ProductSize
GROUP BY SizeId
Having Count(Distinct ProductId)> 1
SO i have two tables:
Products
Product ID | Quantity
OrdersLines
Product ID | Amount (multiple lines with same ID)
I want to join two tables. Result should be - Product ID (Group by), Quantity and Sum of all amounts from OrdersLines table.
I got this so far:
SELECT P.ProductID, P.Quantity, SUM(OL.Amount)
FROM atbl_Sales_Products AS P
LEFT JOIN atbl_Sales_OrdersLines AS OL ON OL.ProductID = P.ProductID
GROUP BY P.ProductID
This produces error:
Column 'atbl_Sales_Products.Quantity' is invalid in the select list
because it is not contained in either an aggregate function or the
GROUP BY clause.
Thanks for help!
Well, there are two ways to write this depending on what you want
Adding the Quantity to the aggregate...
SELECT
P.ProductID,
SUM(P.Quantity),
SUM(OL.Amount)
FROM atbl_Sales_Products AS P
LEFT JOIN atbl_Sales_OrdersLines AS OL ON OL.ProductID = P.ProductID
GROUP BY P.ProductID
Adding the quantity to the grouping
SELECT
P.ProductID,
P.Quantity,
SUM(OL.Amount)
FROM atbl_Sales_Products AS P
LEFT JOIN atbl_Sales_OrdersLines AS OL ON OL.ProductID = P.ProductID
GROUP BY P.ProductID, P.Quantity
--based on comment
HAVING SUM(OL.Amount) > P.Quantity
I am trying to implement a pivoted table in sql but it is not working. What I currently have is the following:
WITH Pivoted
AS
(
select vg.ParentProductCategoryName, c.CompanyName, sd.LineTotal
FROM SalesLT.Product p join SalesLT.vGetAllCategories vg on p.ProductCategoryID = vg.ProductCategoryID
Join SalesLT.SalesOrderDetail sd on p.ProductID = sd.ProductID
JOIN SalesLT.SalesOrderHeader as soh ON sd.SalesOrderID = soh.SalesOrderID
JOIN SalesLT.Customer AS c ON soh.CustomerID = c.CustomerID
pivot(Sum([LineTotal]) for [ParentProductCategoryName] in (Accessories, Bikes, Clothing, Components)) AS sales
)
select * from Pivoted p;
;
I get the error:
multi part "Column name" Identifier could not be bounded.
If I removed the column names in the select part and used * instead, I get:
The column 'ProductCategoryID' was specified multiple times for...
What I want is to have a view of the total Revenue (as specified by the sum of the lineTotal in the SalesOrderDetail Table) per each ParentProductCategoryName (in vGetAllCategories) stated (pivoted as columns) with respect to each CompanyName (in Customer). How to better achieve this? Thanks.
Not sure why you'd need a CTE for this.. but put your JOINS in a derived table and pivot that derived table instead.
SELECT *
FROM (SELECT vg.ParentProductCategoryName,
c.CompanyName,
sd.LineTotal
FROM SalesLT.Product p
JOIN SalesLT.vGetAllCategories vg ON p.ProductCategoryID = vg.ProductCategoryID
JOIN SalesLT.SalesOrderDetail sd ON p.ProductID = sd.ProductID
JOIN SalesLT.SalesOrderHeader AS soh ON sd.SalesOrderID = soh.SalesOrderID
JOIN SalesLT.Customer AS c ON soh.CustomerID = c.CustomerID
) t
PIVOT( SUM([LineTotal])
FOR [ParentProductCategoryName] IN (Accessories,Bikes,Clothing,Components) ) AS sales
or you could just use the SUM aggregate with CASE
SELECT c.CompanyName,
Accessories = SUM(CASE WHEN vg.ParentProductCategoryName = 'Accessories' THEN sd.LineTotal END),
Bikes = SUM(CASE WHEN vg.ParentProductCategoryName = 'Bikes' THEN sd.LineTotal END),
Clothing = SUM(CASE WHEN vg.ParentProductCategoryName = 'Clothing' THEN sd.LineTotal END),
Components = SUM(CASE WHEN vg.ParentProductCategoryName = 'Components' THEN sd.LineTotal END)
FROM SalesLT.Product p
JOIN SalesLT.vGetAllCategories vg ON p.ProductCategoryID = vg.ProductCategoryID
JOIN SalesLT.SalesOrderDetail sd ON p.ProductID = sd.ProductID
JOIN SalesLT.SalesOrderHeader AS soh ON sd.SalesOrderID = soh.SalesOrderID
JOIN SalesLT.Customer AS c ON soh.CustomerID = c.CustomerID
GROUP BY c.CompanyName
I'm trying to use a calculated column in a where clause.
I've trying everything from CROSS APPLY, to sub-query select but it does not give me the anything near what I need.
My query so far:
SELECT p.Code, c.AccountNumber, Sales = (SUM(p.UnitPrice) * SUM(od.QtyShipped)) FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
WHERE Sales > 100
GROUP BY p.Code, c.AccountNumber, Sales
This does not work, as 'Sales' is an invalid column
Using Derived Columns in a predicate
You'll need to wrap the inner query in a derived table or CTE in order to be able to use derived columns in the WHERE clause (Also, note SUM() is specified just once, using the results of the multiplication):
SELECT x.Code, x.AccountNumber, x.Sales
FROM
(
SELECT p.Code, c.AccountNumber, SUM(p.UnitPrice *od.QtyShipped) AS Sales
FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
GROUP BY p.Code, c.AccountNumber
) AS x
WHERE x.Sales > 100;
Repeating the Derived Column in a HAVING clause
As per #Jonny's comment, the other way is not to DRY up the calculated column, but to instead repeat the calculation. Use HAVING instead of WHERE after a GROUP BY has been applied.
SELECT p.Code, c.AccountNumber, SUM(p.UnitPrice *od.QtyShipped) AS Sales
FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
GROUP BY p.Code, c.AccountNumber
HAVING SUM(p.UnitPrice * od.QtyShipped) > 100;
In either case, as per comments below, note that the calculated expression is SUM(p.UnitPrice * od.QtyShipped) and not SUM(p.UnitPrice) * SUM(od.QtyShipped).
You can use the common table expression for this
;WITH CTE AS
(
SELECT p.Code, c.AccountNumber, Sales = (SUM(p.UnitPrice) * SUM(od.QtyShipped)) FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
GROUP BY p.Code, c.AccountNumber, Sale
)
SELECT *
FROM CTE WHERE CTE.Sales>100
If it's a calculated column you can use "HAVING".
SELECT p.Code, c.AccountNumber, Sales = (SUM(p.UnitPrice) * SUM(od.QtyShipped)) FROM [dbo].Customer c
LEFT JOIN [dbo].OrderHeader oh ON oh.CustomerId = c.Id
LEFT JOIN [dbo].OrderDetail od ON od.OrderHeaderId = oh.Id
LEFT JOIN [dbo].Product p ON p.Id = od.ProductId
GROUP BY p.Code, c.AccountNumber, Sales
HAVING SALES > 100;