Invalid subquery, trying to get the customer ID that goes along with the invoice - sql

Here is my SQL, I am trying to get the DISTINCT item ids that have not been invoiced in the past two years that also have a qty on hand greater than 0. I am having an issue getting the last customer id that was invoiced for each distinct item id.
SELECT DISTINCT
im.item_id,
MAX(il.date_created),
(SELECT TOP 1 customer_id
FROM invoice_hdr ih2
WHERE ih.invoice_no = ih2.invoice_no) AS customer_id,
inv_loc.qty_on_hand,
ih.sales_location_id,
MAX(il.commission_cost)
FROM
invoice_hdr ih
INNER JOIN
invoice_line il ON ih.invoice_no = il.invoice_no
INNER JOIN
inv_mast im ON il.inv_mast_uid = im.inv_mast_uid
INNER JOIN
inv_loc ON im.inv_mast_uid = inv_loc.inv_mast_uid
WHERE
inv_loc.qty_on_hand > '0'
GROUP BY
im.item_id, inv_loc.qty_on_hand, ih.sales_location_id
HAVING
(MAX(il.date_created) < DATEADD(year, -2, GETDATE()))
I get this error:
Column 'invoice_hdr.invoice_no' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I understand the error, but no matter what I try I cannot get it to work.

I was able to get the correct data with the following query:
SELECT DISTINCT il.item_id,
ih.customer_id,
il.customer_part_number,
il.date_created,
SUM(inv_loc.qty_on_hand) AS [Qty On Hand],
ih.sales_location_id,
MAX(il.commission_cost) AS [Max Commission Cost]
FROM invoice_hdr ih
JOIN invoice_line il ON ih.invoice_no = il.invoice_no
JOIN inv_loc ON il.inv_mast_uid = inv_loc.inv_mast_uid
WHERE (SELECT TOP 1 il2.date_created FROM invoice_line il2 WHERE il2.item_id = il.item_id ORDER BY il2.date_created DESC) < DATEADD(YEAR, -2, GETDATE())
AND (SELECT TOP 1 il2.invoice_no FROM invoice_line il2 WHERE il2.item_id = il.item_id ORDER BY il2.date_created DESC) = ih.invoice_no
GROUP BY il.item_id,
ih.customer_id,
il.date_created,
ih.sales_location_id,
customer_part_number
HAVING SUM(inv_loc.qty_on_hand) > 0
ORDER BY il.item_id

Related

SUM all prices from table SQL

i have following SQL query which is summing tourist tax from selected period.
SELECT
BTR_DESCRIPTION AS TOURIST_TAX_NAME,
ISNULL(BREAG_TOURIST_TAX_PRICE,0) AS PRICE,
SUM(DATEDIFF(d, BRE_DATEFROM, BRE_DATETO)) AS QUANTITY,
ISNULL(BREAG_TOURIST_TAX_PRICE,0) * SUM(DATEDIFF(d, BRE_DATEFROM, BRE_DATETO)) AS FINAL_PRICE
FROM BOS_RESERVATION
LEFT OUTER JOIN BOS_RESADDGUEST ON BREAG_BRE_ID = BRE_ID
LEFT OUTER JOIN BOS_TAX_REASONS ON BTR_ID = BREAG_BTR_ID
WHERE BREAG_DATEFROM >= '2018-02-28' AND BREAG_DATETO <= '2018-03-31'
GROUP BY BTR_DESCRIPTION, BREAG_TOURIST_TAX_PRICE
Query result:
Now i want to sum all values from FINAL_PRICE row. So the result must be: 5,652
But i dont know how to do this. I tried with following SQL:
SUM(ISNULL(BREAG_TOURIST_TAX_PRICE,0) * SUM(DATEDIFF(d, BRE_DATEFROM, BRE_DATETO))) AS FINAL_PRICE_SUM
But this gives me error: Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
Can you please help me how to sum all values from FINAL_PRICE row?
Thanks!
You can do it like this:
WITH AggregatedTable as (SELECT
BTR_DESCRIPTION AS TOURIST_TAX_NAME,
ISNULL(BREAG_TOURIST_TAX_PRICE,0) AS PRICE,
SUM(DATEDIFF(d, BRE_DATEFROM, BRE_DATETO)) AS QUANTITY,
ISNULL(BREAG_TOURIST_TAX_PRICE,0) * SUM(DATEDIFF(d, BRE_DATEFROM, BRE_DATETO)) AS FINAL_PRICE
FROM BOS_RESERVATION
LEFT OUTER JOIN BOS_RESADDGUEST ON BREAG_BRE_ID = BRE_ID
LEFT OUTER JOIN BOS_TAX_REASONS ON BTR_ID = BREAG_BTR_ID
WHERE BREAG_DATEFROM >= '2018-02-28' AND BREAG_DATETO <= '2018-03-31'
GROUP BY BTR_DESCRIPTION, BREAG_TOURIST_TAX_PRICE)
Select at.*,
(SELECT SUM(FINAL_PRICE) from AggregatedTable)) as Total_FP
from AggregatedTable AS at
If you want the total final price, use a CTE or subquery:
WITH r as (
SELECT BTR_DESCRIPTION AS TOURIST_TAX_NAME,
COALESCE(BREAG_TOURIST_TAX_PRICE, 0) AS PRICE,
SUM(DATEDIFF(day, BRE_DATEFROM, BRE_DATETO)) AS QUANTITY,
COALESCE(BREAG_TOURIST_TAX_PRICE, 0) * SUM(DATEDIFF(day, BRE_DATEFROM, BRE_DATETO)) AS FINAL_PRICE
FROM BOS_RESERVATION LEFT OUTER JOIN
BOS_RESADDGUEST
ON BREAG_BRE_ID = BRE_ID LEFT OUTER JOIN
BOS_TAX_REASONS
ON BTR_ID = BREAG_BTR_ID
WHERE BREAG_DATEFROM >= '2018-02-28' AND BREAG_DATETO <= '2018-03-31'
GROUP BY BTR_DESCRIPTION, BREAG_TOURIST_TAX_PRICE
)
SELECT SUM(FINAL_PRICE)
FROM r;

SQL - Tracking Monthly Sales

I am writing a query to summarize sales by month. My problem is that my query only returns records for months with sales. For example, I am looking over a 15 month range. But for one specific part in the example below only 3 of the 15 months had sales.
I'm hoping to have 15 records show up and the other ones have 0's for sales. The reason I am hoping for the additional records is I want to take the standard deviation of this, and dropping records impacts that calculation.
Sample Code:
SELECT I.PartNumber as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
COUNT(*) as TotalDemand
FROM OrderDetails OD
INNER JOIN Orders O on O.Id = OD.OrderId
INNER JOIN Items I on I.Id = OD.ItemId
WHERE
O.CreateDate >= '1-1-2016'
AND O.CreateDate <= '3-31-2017'
AND I.PartNumber = '5144831-2'
GROUP BY I.PartNumber, YEAR(O.CreateDate) , MONTH(O.CreateDate);
Sample Current Output:
Part # | Year | Month | Demand
5144831-2 2017 1 1
5144831-2 2017 2 3
5144831-2 2016 3 1
Desired Output:
I would want an additional row such as:
5144831-2 2016 11 0
To show there were no sales in Nov 2016.
I do have a temp table #_date_array2 with the possible months/years, I think I need help incorporating a LEFT JOIN.
If you want to use left join, you would not be able to use it directly with the inner join. You can do the inner join inside the parenthesis and then do the left join outside to avoid messing with the results of left join. Try this:
SELECT Z.PartNumber as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
COUNT(Z.OrderId) as TotalDemand
FROM Orders O
LEFT JOIN
(
SELECT OrderId, PartNumber
FROM
OrderDetails OD
INNER JOIN Items I ON I.Id = OD.ItemId
AND I.PartNumber = '5144831-2'
) Z
ON O.Id = Z.OrderId
AND O.CreateDate >= '1-1-2016'
AND O.CreateDate <= '3-31-2017'
GROUP BY Z.PartNumber, YEAR(O.CreateDate) , MONTH(O.CreateDate);
To get a count of 0 for months with no order, avoid using count(*) and use count(OrderId) as given above.
Note - You will have to make sure the Orders table has all months and years available i.e. if there is no CreateDate value of, say, November 2016 in the Orders table(left table in the join), the output will also not produce this month's entry.
Edit:
Can you try this:
SELECT Z.PartNumber as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
COUNT(O.OrderId) as TotalDemand
FROM Orders O
RIGHT JOIN
(
SELECT OrderId, PartNumber
FROM
OrderDetails OD
INNER JOIN Items I ON I.Id = OD.ItemId
AND I.PartNumber = '5144831-2'
) Z
ON O.Id = Z.OrderId
AND O.CreateDate >= '1-1-2016'
AND O.CreateDate <= '3-31-2017'
GROUP BY Z.PartNumber, YEAR(O.CreateDate) , MONTH(O.CreateDate);
Assuming you have sales of something in every month, the simplest solution is to switch to conditional aggregation:
SELECT '5144831-2' as PartNumber,
YEAR(O.CreateDate) as CreateDateYear,
MONTH(O.CreateDate) as CreateDateMonth,
SUM(CASE WHEN I.PartNumber = '5144831-2' THEN 1 ELSE 0 END) as TotalDemand
FROM OrderDetails OD INNER JOIN
Orders O
ON O.Id = OD.OrderId INNER JOIN
Items I
ON I.Id = OD.ItemId
WHERE O.CreateDate >= '2016-01-01' AND
O.CreateDate <= '2017-03-31'
GROUP BY YEAR(O.CreateDate) , MONTH(O.CreateDate);
Note: This is something of a hack for solving the problem. More robust solutions involve generating the dates and using LEFT JOIN (or similar functionality). However, this is often the fastest way to get the result.
based on all of your comments on other posts etc it seems like you have a table that has a date range you want and you want to be able to run the analysis for multiple/all of the part numbers. So the main issue is you will need a cartesian join between your date table and partnumbers that were sold during that time in order to accomplish you "0"s when not sold.
;WITH cteMaxMinDates AS (
SELECT
MinDate = MIN(DATEFROMPARTS(CreateDateYear,CreateDateMonth,1))
,MaxDate = MAX(DATEFROMPARTS(CreateDateYear,CreateDateMonth,1))
FROM
#_date_array2
)
;WITH cteOrderDetails AS (
SELECT
d.CreateDateYear
,d.CreateDateMonth
,I.PartNumber
FROM
#_date_array2 d
INNER JOIN Orders o
ON d.CreateDateMonth = MONTH(o.CreateDate)
AND d.CreateDateYear = YEAR(o.CreateDate)
INNER JOIN OrderDetails od
ON o.Id = od.OrderId
INNER JOIN Items i
ON od.ItemId = i.Id
AND i.PartNumber = '5144831-2'
)
, cteDistinctParts AS (
SELECT DISTINCT PartNumber
FROM
cteOrderDetails
)
SELECT
d.CreateDateYear
,d.CreateDateMonth
,I.PartNumber
,COUNT(od.PartNumber) as TotalDemand
FROM
#_date_array2 d
CROSS JOIN cteDistinctParts p
LEFT JOIN cteOrderDetails od
ON d.CreateDateYear = od.CreateDateYear
AND d.CreateDateMonth = od.CreateDateMonth
AND p.PartNumber = od.PartNumber
GROUP BY
d.CreateDateYear
,d.CreateDateMonth
,I.PartNumber
To get ALL part numbers simply remove AND i.PartNumber = '5144831-2' join condition.

Filter between dates grouping 3 tables in SQL Server

I have this SQL in SQL Server:
SELECT
Itens.Mercadoria, Mercadoria.Nome, Cabecalho.Data,
SUM(ValorUnitario) AS Total,
SUM(Quantidade) AS Quantidade
FROM
Itens
INNER JOIN
Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN
Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE
Cabecalho.Data >= '2016-01-01'
AND Cabecalho.Data <= '2018-12-31'
GROUP BY
Itens.Mercadoria, Mercadoria.Nome, Cabecalho.Data
ORDER BY
4 DESC
It is returning the following result.
The highlighted values are repeating, I do not want to be repeated, I want to show only once each item and that the Quantidade and Total fields are SUM.
For example:
`Camisa Polo` -> **Quantidade = 23**
`Calça Jeans` -> **Quantidade = 15**
`Camiseta Estampada` -> **Quantidade = 21**
Assuming thate the relation between Sales and SaleItems is based on SalesId
you can use between assign to your_start_date and your_end_date a proper value
select Products.ProductName
, sum(SaleItems.Price)
, sum(SaleItems.Quantity)
from Products
inner join SaleItems on SaleItems.IdProduct = Products.IdProduct
inner join Sales on Sales.IdSale = SaleItems.IdSale
where SaleDate between your_start_date and your_end_date
group by Products.ProductName
In you case remove or aggregated the Cabecalho.Data column eg:
SELECT Itens.Mercadoria
, Mercadoria.Nome
, SUM(ValorUnitario) AS Total
, SUM(Quantidade) AS Quantidade
FROM Itens INNER JOIN Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE Cabecalho.Data between '2016-01-01' AND '2018-12-31'
GROUP BY Itens.Mercadoria, Mercadoria.Nome
ORDER BY 4 DESC
or
SELECT Itens.Mercadoria
, Mercadoria.Nome
, max(Cabecalho.Data)
, SUM(ValorUnitario) AS Total
, SUM(Quantidade) AS Quantidade
FROM Itens INNER JOIN Mercadoria ON Itens.Mercadoria = Mercadoria.Codigo
INNER JOIN Cabecalho ON Cabecalho.Codigo = Itens.Cabecalho
WHERE Cabecalho.Data between '2016-01-01' AND '2018-12-31'
GROUP BY Itens.Mercadoria, Mercadoria.Nome
ORDER BY 4 DESC

Item rows duplicate and SUM for Total Expense

When the below query is executed the "TotalExpense" column duplicates to the number of rows that are present in the tblOrderProduct for a given SalesID.
SELECT ItemSales.OrderDate,tblExpense.DateOfExpense ,(Nz(SUM(tblOrderProduct.Quantity * tblOrderProduct.ConsumerPrice))) AS TotalSales, (Nz(SUM(tblExpense.Expense))) AS TotalExpense , (Nz(SUM(tblOrderProduct.Quantity * tblOrderProduct.ConsumerPrice)) - Nz(SUM(tblExpense.Expense)))AS Profit
FROM (ItemSales
LEFT JOIN tblOrderProduct ON ItemSales.SalesID = tblOrderProduct.SalesID)
LEFT JOIN tblExpense ON itemSales.OrderDate = tblExpense.DateOfExpense
GROUP BY ItemSales.OrderDate, tblExpense.DateOfExpense
ORDER BY ItemSales.OrderDate
UNION SELECT ItemSales.OrderDate, tblExpense.DateOfExpense, (Nz(SUM(tblOrderProduct.Quantity * tblOrderProduct.ConsumerPrice))) AS TotalSales, (Nz(SUM(tblExpense.Expense))) AS TotalExpense ,(Nz(SUM(tblOrderProduct.Quantity * tblOrderProduct.ConsumerPrice)) - Nz(SUM(tblExpense.Expense)))AS Profit
FROM (ItemSales
RIGHT JOIN tblExpense ON ItemSales.OrderDate = tblExpense.DateOfExpense)
LEFT JOIN tblOrderProduct ON ItemSales.SalesID = tblOrderProduct.SalesID
GROUP BY ItemSales.OrderDate,tblExpense.DateOfExpense
ORDER BY ItemSales.OrderDate
EDIT :-
Please see below for the result I get from the executed query:
The value highlighted in red only has expense worth 1000 for the given date, How ever the sales related to the same day has 22 rows of data hence the result is showing 22000
What is causing this duplication?
SELECT ItemSales.OrderDate,tblExpense.DateOfExpense ,(Nz(SUM(tblOrderProduct.Quantity * tblOrderProduct.ConsumerPrice))) AS TotalSales, (Nz(SUM(tblExpense.Expense))) AS TotalExpense , (Nz(SUM(tblOrderProduct.Quantity * tblOrderProduct.ConsumerPrice)) - Nz(SUM(tblExpense.Expense)))AS Profit
FROM (ItemSales
LEFT JOIN tblOrderProduct ON ItemSales.SalesID = tblOrderProduct.SalesID)
LEFT JOIN
( select DateOfExpense,sum(Expense) AS Expense FROM tblExpense Group by DateOfExpense)
tblExpense ON itemSales.OrderDate = tblExpense.DateOfExpense
GROUP BY ItemSales.OrderDate, tblExpense.DateOfExpense
ORDER BY ItemSales.OrderDate
UNION
SELECT ItemSales.OrderDate, tblExpense.DateOfExpense, (Nz(SUM(tblOrderProduct.Quantity * tblOrderProduct.ConsumerPrice))) AS TotalSales, (Nz(SUM(tblExpense.Expense))) AS TotalExpense ,(Nz(SUM(tblOrderProduct.Quantity * tblOrderProduct.ConsumerPrice)) - Nz(SUM(tblExpense.Expense)))AS Profit
FROM ItemSales
RIGHT JOIN
( select DateOfExpense,sum(Expense) AS Expense FROM tblExpense Group by DateOfExpense)
tblExpense ON ItemSales.OrderDate = tblExpense.DateOfExpense
LEFT JOIN tblOrderProduct ON ItemSales.SalesID = tblOrderProduct.SalesID
GROUP BY ItemSales.OrderDate,tblExpense.DateOfExpense
ORDER BY ItemSales.OrderDate

Identical aggregate-function for different WHERE's

Im stuck atm. Trying to figure out how to use an aggregate function like SUM(column1*column2) for making results in multiple columns. I want to print ex. SUM(qty*unitprice) where orderdate between "blabla" and "blabla",
and then i want another column which uses the same function(sum(qty*unitprice)
but with additional expressions in the where clause. this is my code example, it doesnt show anything:
select Orderdates, Sales, SalesDisc
FROM ( select month(OH.OrderDate) as Orderdates, sum(OD.OrderQty*OD.UnitPrice) as Sales
from sales.SalesOrderDetail OD
inner join sales.salesorderheader OH on
OD.SalesOrderID = OH.SalesOrderID
where OrderDate >= ('2014-01-01') and OrderDate < ('2015-01-01')
group by month(OH.orderdate)
) A
Join
(select month(OH.OrderDate) as orderdatez, sum(OD.OrderQty*OD.UnitPrice) as SalesDisc
from sales.SalesOrderDetail OD
inner join sales.SalesOrderHeader OH on
OD.SalesOrderID = OH.SalesOrderID
where OrderDate >= ('2014-01-01') and OrderDate < ('2015-01-01')
and OD.SpecialOfferID between 2 and 16
Group by Month(OH.orderdate)
) B
on A.Orderdates = B.orderdatez and A.Sales = B.SalesDisc
If am not wrong this is what you need
SELECT Month(OH.OrderDate) AS Orderdates,
Sum(OD.OrderQty * OD.UnitPrice) AS Sales,
Sum(CASE
WHEN OD.SpecialOfferID BETWEEN 2 AND 16 THEN ( OD.OrderQty * OD.UnitPrice )
ELSE 0
END) AS SalesDisc
FROM sales.SalesOrderDetail OD
INNER JOIN sales.salesorderheader OH
ON OD.SalesOrderID = OH.SalesOrderID
WHERE OrderDate >= ( '2014-01-01' )
AND OrderDate < ( '2015-01-01' )
GROUP BY Month(OH.orderdate)
Note : It will be more meaningful if you add year(OH.orderdate) in group by