SQL Sum and Group on two tables - sql-server

I'm incredibly new to SQL and working on completing some assignments in order to advance my knowledge. I found myself stuck on a problem, though.
I have to find the total profit on items by using multiplication and subtraction, which I have completed with the following commands:
select
production.product.ProductID,
StandardCost,
sales.SalesOrderDetail.OrderQty,
UnitPrice,
(sales.SalesOrderDetail.UnitPrice*sales.SalesOrderDetail.OrderQty)-
(production.product.StandardCost*sales.salesorderdetail.OrderQty) as
'Total Profit'
from
sales.SalesOrderDetail,
production.product
What I need to do is sum the total profit and group it by the ProductID in order to find the most profitable items and the least profitable. I thought this would work:
select
production.product.ProductID,
StandardCost,
sales.SalesOrderDetail.OrderQty,
UnitPrice,
sum((sales.SalesOrderDetail.UnitPrice*sales.SalesOrderDetail.OrderQty)-
(production.product.StandardCost*sales.salesorderdetail.OrderQty)) as
'Total Profit'
from
sales.SalesOrderDetail,
production.product
group by
Production.Product.ProductID
However, I receive the following error:
Column 'production.product.StandardCost' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I'm at a loss on where to continue. I tried rearranging and doing inner/left joins, but I've been unsuccessful.

so for grouping you need to aggregate or include in the group by statement.
you are grouping by the productID but the other columns are not aggregated and are not in the group by statement.
a correction could be (depending on how you want to aggregate the other columns)
select
production.product.ProductID
, avg(StandardCost) as AvgCost
, sum(sales.SalesOrderDetail.OrderQty) as TotalQuantity
, avg(UnitPrice) as AvgUnitPrice
, sum((sales.SalesOrderDetail.UnitPrice*sales.SalesOrderDetail.OrderQty)-
(production.product.StandardCost*sales.salesorderdetail.OrderQty)) as [Total Profit]
from sales.SalesOrderDetail
, production.product
group by Production.Product.ProductID

Related

AdventureWorks in SQL Server 2019 : ordershare percent for each item per month

I'm new to SQL Server. I'm trying to write a code to find the sale percent/per item/per month. Something like this:
Year
Month
ProductID
Order_Quantity_Per_Month
Total_Sold_Per_Month
%_Of_Total_Sale
2011
5
707
422
17024
2
First and most importantly, I want to write this code with "CTE" and "Group by". I've tried many times but I failed. How can I write this code with cte and group by?
I wrote this code with "Over" and "Partition". Could someone check the codes I've written to see if it's actually correct:
USE AdventureWorks2019
GO
SELECT
YEAR (soh.OrderDate) As Year,
MONTH (soh.OrderDate) As Month,
pro.productid AS [Product ID],
pro.Name AS [Product Name],
SUM(sod.OrderQty) OVER (PARTITION BY Month(soh.OrderDate) ORDER BY by soh.OrderDate) AS [Order Quantity Per Month],
SUM(sod.OrderQty) OVER (PARTITION BY Month(soh.OrderDate)) AS [Total Sold Per Month],
SUM(sod.OrderQty) OVER (PARTITION BY Month(soh.OrderDate) ORDER BY by soh.OrderDate) * 100 / SUM(sod.OrderQty) OVER (PARTITION BY Month(soh.OrderDate)) AS [% of TotalSale]
FROM
Production.Product pro
INNER JOIN
Sales.SalesOrderdetail sod ON pro.ProductID = sod.ProductID
INNER JOIN
Sales.SalesOrderheader soh ON soh.SalesOrderID = sod.SalesOrderID
GROUP BY
YEAR(soh.OrderDate), MONTH(soh.OrderDate),
soh.OrderDate, pro.productid, pro.Name, sod.OrderQty
ORDER BY
Year, Month
If the above code is correct, How can I write the code with cte and group by?
I think the better question is why you want (or need) to use a CTE. A simple CTE (i.e., not recursive) is just syntactic sugar for a derived table. There is nothing particular special or complicated about writing and using one in a query. If you "tried many times", you should have included those attempts in your question.
But to satisfy the need to use a CTE, you can simply "cram" the query you have into the CTE and select rows from it. Example:
with cteOrders as (
select ... -- your original query here without ORDER BY clause
)
select * from cteOrders
order by [Year], [Month]
;
That is a extremely simplistic way of using a CTE. There is no real or obvious advantage to doing so but it does satisfy your goal. Because of that, I smell a XY problem.

Joins and subqueries in SQL Server

I am trying to find all continents and their most-used currency.
ContinentCode
CurrencyCode
CurrencyUsage
I am not familiar with grouping so I will be very grateful if you can give me a hint using only subqueries and joins if they can be used adequately here.
Join the countries to the continents. Then aggregate to get the number the currencies are used. Then use row_number() (or rank(), if you want to keep ties) to produce an ordinal per continent -- the more the currency is used the lesser the ordinal. Only get the rows where this ordinal equals 1.
SELECT x.continentcode,
x.currencycode,
x.currencyusage
FROM (SELECT ct.continentcode,
cy.currencycode,
count(cy.currencycode) currencyusage,
row_number() OVER (PARTITION BY ct.continentcode
ORDER BY count(cy.currencycode) DESC) rn
FROM continents ct
LEFT JOIN countries cy
ON cy.continentcode = ct.continentcode
GROUP BY ct.continentcode,
cy.currencycode) x
WHERE x.rn = 1;
And next time do not post images of tables. Instead paste the CREATE and INSERT statements to create them as text.

SELECT statement with sub-query

Instructions:
Business case: The accounting department would like a reporting of the top ten vendors with their last invoice date and average invoice amount.
Write a SELECT statement that returns three columns:
VendorName (from the Vendors table)
LatestInv (summary function that returns the last entry from InvoiceDate)
AverageInv: (summary function that returns the average from InvoiceTotal)
Hint: you will need to join two tables before joining to the derived table (the subquery)
Subquery portion: SELECT statement that returns the top ten VendorID and AverageInv (same name and function as described in the outer query). Group the results by the appropriate column and sort the results by AverageInv from largest to smallest. Correlate the subquery as BestVendors and join it to the correct table (where both share a key field).
Group the outer query by the appropriate column and sort the results by LatestInv
most recent to oldest
My code
SELECT VendorName, MAX(InvoiceDate) AS LatestInv, AVG(InvoiceTotal) AS AverageInv
FROM Vendors v JOIN
(SELECT TOP 10 VendorID, AVG(InvoiceTotal) AS AverageInv
FROM Invoices
GROUP BY VendorID
ORDER BY AverageInv DESC) AS BestVendors
ON v.VendorID = BestVendors.VendorID
GROUP BY VendorName
ORDER BY LatestInv
MAX(InvoiceDate) has a red line under it as well as AVG(InvoiceTotal) because they are from the Invoices table. Not the Vendors. However if I use FROM Invoices in the outer query then VendorName won't be recognized? How do I fix this and get the result set that this question is looking for?
Also these pics show some sample data from the Invoices and Vendors Table
Try this:
SELECT VendorName, BestVendors.LatestInv, BestVendors.AverageInv
FROM Vendors v
INNER JOIN
(
SELECT TOP 10 VendorID
,AVG(InvoiceTotal) AS AverageInv
,MAX(InvoiceDate) AS LatestInv
FROM Invoices
GROUP BY VendorID
ORDER BY AverageInv DESC
) AS BestVendors
ON v.VendorID = BestVendors.VendorID
ORDER BY LatestInv DESC

SQL Server: Apply different multipliers by date

I have a table that records sales and I want a report on how much tax was paid on each item. The basic rule is all sales before April 1st had a .52% tax, all sales after that date will have a 0.5% tax.
I'm trying to get this using the following query
select ItemCode,
sum(Quantity) QuantitySold,
WhsCode as Store,
case when (docdate < '20170401') then sum(Quantity * .0052) else sum(Quantity * .005) end as Tax
from SalesTable
group by whscode,
itemcode
However I get a
DocDate' is invalid in the select list because it is not contained in
either an aggregate function or the GROUP BY clause.
error if I run it as is. Adding DocDate to the group by clause creates a mess of duplicates (On one example I went from 185 rows to 1508 rows).
Does SQL simply not allow you to use WHEN statements whose conditional is not included in the Group clause or should I be using something else?
Error is because you are using docdate directly without adding it to the group by clause.
I think this is what you want:
select ItemCode,
sum(Quantity) QuantitySold,
WhsCode as Store,
sum(price * case when docdate < '20170401' then 0.0052 else 0.005 end) as Tax
from SalesTable
group by whscode,
itemcode

ms access GROUP BY error

I'm trying to run this SQL in MS access
SELECT `orig`.`SONG TITLE`,`orig`.`PUBLISHER`,`orig`.`CFG DESCRIPTION`
FROM `Sheet1` AS `orig`
INNER JOIN `Sale type` AS `Sale`
ON orig.`CFG DESCRIPTION`=Sale.`CFG DESC`
GROUP BY orig.`SONG TITLE` , orig.`PUBLISHER`
;
I get an error saying: "Your query does not include the specified expression 'CFG DESCRIPTION' as a part of an aggregate function"
When I run this query without the GROUP BY clause all works fine. What am I doing wrong with the GROUP BY??
The group by clause means that you get one result row per distinct combination of the grouped columns. This means your select list can only contains columns that are grouped by, or aggregate functions (e.g., count, sum, min, max, etc.)
So you should either add CFG DESCRIPTION to the group by clause:
SELECT `orig`.`SONG TITLE`,`orig`.`PUBLISHER`,`orig`.`CFG DESCRIPTION`
FROM `Sheet1` AS `orig`
INNER JOIN `Sale type` AS `Sale`
ON orig.`CFG DESCRIPTION`=Sale.`CFG DESC`
GROUP BY orig.`SONG TITLE` , orig.`PUBLISHER`,`orig`.`CFG DESCRIPTION`
;
Or remove it from the select list:
SELECT `orig`.`SONG TITLE`,`orig`.`PUBLISHER`
FROM `Sheet1` AS `orig`
INNER JOIN `Sale type` AS `Sale`
ON orig.`CFG DESCRIPTION`=Sale.`CFG DESC`
GROUP BY orig.`SONG TITLE` , orig.`PUBLISHER`
;
Depending on the result you need, of course.
GROUP BY is an all-or-nothing concept, where every column you select needs to be in the clause unless it's an aggregate. Include orig.CFG DESCRIPTION at the end of the GROUP BY and it should run.
I think you need to add orig.[GFC DESCRIPTION] to your Group By:
GROUP BY orig.[SONG TITLE] , orig.[PUBLISHER], orig.[GFC DESCRIPTION]
If that does not work for your situation, place the orig.[GFC DESCRIPTION] in an aggregate function:
SELECT orig.SONG TITLE,orig.PUBLISHER,MIN(orig.CFG DESCRIPTION)
FROM Sheet1 AS orig
INNER JOIN Sale type AS Sale
ON orig.CFG DESCRIPTION=Sale.CFG DESC
GROUP BY orig.SONG TITLE , orig.PUBLISHER
;
You can use any aggregate function, such as MAX, FIRST (Access Specific), etc.

Resources