Subquery in SQL Server using Min, Max, Avg - sql-server

Task: write a query to generate the total number of invoices, the invoice total for all of the invoices, the smallest invoice amount, the largest invoice amount, and the average of all of the invoices.
My attempt so far:
SELECT
COUNT(DISTINCT Lines.inv_number) as NumberOfInvoices,
SUM(Lines.line_price * Lines.line_units) as TotalSales,
MIN(SELECT SUM(Lines.line_price * Lines.line_units)
FROM dbo.Lines
INNER JOIN dbo.Invoices ON Invoices.inv_number = Lines.inv_number
GROUP BY Invoices.cus_code) as MinimumSale,
MAX(Lines.line_price * Lines.line_units) as LargestSale,
AVG(Lines.line_price * Lines.line_units) as AverageSale
FROM
dbo.Lines
INNER JOIN
dbo.Invoices ON Invoices.inv_number = Lines.inv_number;
I keep getting an error when running. Not sure if I am putting the subquery in the right place.

You can use subquery as below:
SELECT COUNT(A.InvNumber) AS NumberOfInvoices
,A.TotalSales
,MIN(A.TotalSales) AS MinimumSale
,MAX(A.TotalSales) AS LargestSale
,AVG(A.TotalSales) AS AverageSale
FROM (
SELECT
Lines.InvNumber
,SUM(Lines.line_price*Lines.line_units) AS TotalSales
FROM dbo.Lines INNER JOIN dbo.Invoices
ON Invoices.inv_number=Lines.inv_number
GROUP BY Lines.InvNumber
) A
You cannot select minimum on sum as SUM itself returns only one value... Also your syntax itself is not correct

Related

Trying to get total number of active employees

I am looking to get a count of total number of active employees for 2022 and 2023.
Our tables have records on a weekly basis, so when I am pulling the records, its counting an employee 52 times . I am looking to have the query count based on if the person has an active record within the year, to have it only count once. I have includes distinct in the select statement but still getting multiple counts and its not really duplicate so distinct is probable not the solution here.
select distinct count(*)
from TimeSheetsView TSV
inner join Person_Identification PI on PI.PersonId=TSV.Personid
inner join Order_Person_Detail_Record OPDR on OPDR.PersonId=Pi.PersonId and OPDR.DetailRecId=TSV.DetailRecId and OPDR.OrderId=TSV.orderid
where PI.PersonType='AS' and tsv.recordtype='A' and left(yearweek,4) IN ( '2022')
group by PI.PersonId
You shouldn't take "PI" as an alias, since PI is a reserved word.
Simply take DISTINCT within the brackets of the COUNT aggregation, you do not need to group:
SELECT
COUNT(DISTINCT PI.PersonId) AS "Total Count"
FROM TimeSheetsView TSV
INNER JOIN Person_Identification P ON P.PersonId=TSV.Personid
INNER JOIN Order_Person_Detail_Record OPDR
ON OPDR.PersonId=P.PersonId
AND OPDR.DetailRecId=TSV.DetailRecId
AND OPDR.OrderId=TSV.orderid
WHERE P.PersonType='AS'
AND tsv.recordtype='A'
AND left(yearweek,4) IN ( '2022');
If you want to see the Totals per Year, you can use:
SELECT
LEFT(yearweek,4) AS "Year",
COUNT(DISTINCT PI.PersonId) AS "Total Count"
FROM TimeSheetsView TSV
INNER JOIN Person_Identification P ON P.PersonId=TSV.Personid
INNER JOIN Order_Person_Detail_Record OPDR
ON OPDR.PersonId=P.PersonId
AND OPDR.DetailRecId=TSV.DetailRecId
AND OPDR.OrderId=TSV.orderid
WHERE P.PersonType='AS' AND tsv.recordtype='A'
GROUP BY LEFT(yearweek,4);

SQL Server: getting max purchase value for each individual

I have the following query
select
C.Persona, C.Producto, Sum(C.Cantidad * P.Precio) [Total_Purchase]
from
Compras C
join
Precios P on C.Producto = P.Item
group by
C.Producto, C.Persona
which returns the total purchase made by each customer (Persona) for each Product.
How can i get it to bring the Max Total Purchase for each customer and the Product involved?
You can use the MAX() function to do this. You can add it to your select and it will work, even with SUM() being used.
MAX() Examples
Change SUM aggregate to MAX
Or include both
select C.Persona,C.Producto,
Sum(C.Cantidad*P.Precio) [Total_Purchase],
MAX (C.Cantidad*P.Precio) [Total_Purchase
from
Compras C JOIN Precios P ON C.Producto=P.Item
group by C.Producto ,C.Persona
Try this:
select
max(c.[Total_Purchase]), C.Producto ,C.Persona
from
(select
C.Persona, C.Producto, Sum(C.Cantidad*P.Precio) [Total_Purchase]
from
Compras C
join
Precios P on C.Producto = P.Item
group by
C.Producto, C.Persona) c
group by
C.Producto, C.Persona

SQL Inner join show numeric value once

I know my question is not very logical but I have the folowing chalenge:
HeadTab (Uniq_Id N(10)
Name C(30)
Tax N(18,2))
TrsTab (Uniq_Id N(10)
MonthlyDesc C(20)
Amount N(18,2))
What I want is the following select * from headtab inner join Trstab on uniq_id = Uniq_id
the issue is that I want to see the tax field only once per name other related should be 0...(Eventhough I have many lines in the details tab).
Thank you for any help
If you give the query a row number to determine the first row for each Name you can use a case statement to select which value you want for Tax.
SELECT
ht.Uniq_ID,
ht.NAME,
(CASE WHEN ROW_NUMBER() OVER (PARTITION BY ht.NAME ORDER BY ht.Uniq_ID) = 1 THEN ht.Tax ELSE 0 END) Tax,
tt.*
FROM
headtab ht
INNER JOIN Trstab tt ON ht.uniq_id = tt.Uniq_id

Using the results of WITH clause IN where STATEMENT of main query

I am relatively new at SQL so I apologise if this is obvious but I cannot work out how to use the results of the WITH clause query in the where statement of my main query.
My with query pulls the first record for each customer and gives the sale date for that record:
WITH summary AS(
SELECT ed2.customer,ed2.saledate,
ROW_NUMBER()OVER(PARTITION BY ed2.customer
ORDER BY ed2.saledate)AS rk
FROM Filteredxportdocument ed2)
SELECT s.*
FROM summary s
WHERE s.rk=1
I need to use the date in the above query as the starting point and pull all records for each customer for their first 12 months i.e. where the sale date is between ed2.saledate AND ed2.saledate+12 months.
My main query is:
SELECT ed.totalamountincvat, ed.saledate, ed.name AS SaleRef,
ed.customer, ed.customername, comp.numberofemployees,
comp.companyuid
FROM exportdocument AS ed INNER JOIN
FilteredAccount AS comp ON ed.customer = comp.accountid
WHERE (ed.statecode = 0) AND
ed.saledate BETWEEN ed2.saledate AND DATEADD(M,12,ed2.saledate)
I am sure that I need to add the main query into the WITH clause but I cant work out where. Is anyone able to help please
Does this help?
;WITH summary AS(
SELECT ed2.customer,ed2.saledate,
ROW_NUMBER()OVER(PARTITION BY ed2.customer
ORDER BY ed2.saledate)AS rk
FROM Filteredxportdocument ed2)
SELECT ed.totalamountincvat, ed.saledate, ed.name AS SaleRef,
ed.customer, ed.customername, comp.numberofemployees,
comp.companyuid
FROM exportdocument AS ed INNER JOIN
FilteredAccount AS comp ON ed.customer = comp.accountid
OUTER APPLY (SELECT s.* FROM summary s WHERE s.rk=1) ed2
WHERE ed.statecode = 0 AND
ed.saledate BETWEEN ed2.saledate AND DATEADD(M,12,ed2.saledate)
and ed.Customer = ed2.Customer
Results of CTE are not cached or stored, so you can't reuse it.
EDIT:
Based upon your requirement that all the records from CTE should be in final result, this is a new query:
;WITH summary AS(
SELECT ed2.customer,ed2.saledate,
ROW_NUMBER()OVER(PARTITION BY ed2.customer
ORDER BY ed2.saledate)AS rk
FROM Filteredxportdocument ed2)
SELECT
ed.totalamountincvat,
ed.saledate,
ed.name AS SaleRef,
ed.customer,
ed.customername,
comp.numberofemployees,
comp.companyuid
FROM
summary ed2
left join exportdocument ed
on ed.Customer = ed2.Customer
and ed.statecode = 0
AND ed.saledate BETWEEN ed2.saledate AND DATEADD(M,12,ed2.saledate)
INNER JOIN FilteredAccount comp
ON ed.customer = comp.accountid
WHERE
s.rk=1
summary you will be able to use only once. Alternate solution is store summary into temp table and use that as many times as u want.
Something like : Select * into #temp from Summary s where s.rk=1

How can I nest a query as a variable in SQL?

Obviously, SQL isn't my first language, so I need help with something that is probably trivial.
I have the following query:
SELECT Airports.IATA_Code,
COUNT(*) AS Departures,
(SELECT COUNT(*) FROM Flights WHERE DestinationAirportId = 63384) AS Arrivals,
SUM(Flights.Tickets) AS Tickets,
SUM(Flights.Fare * Flights.Tickets) As Revenue,
AVG(Flights.Demand) AS Demand
FROM Flights
LEFT JOIN Airports
ON Flights.OriginAirportId = Airports.Id
WHERE AnalysisId = 2
GROUP BY IATA_Code
ORDER BY Tickets DESC
This query works fine, but I need to replace the hard-coded id of 63384 with the actual Airport Id. This would be Airports.Id but when I try that, I get the following error:
Column 'Airports.Id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Solved!
Just needed to group by the Airport Id as well:
SELECT Airports.IATA_Code,
COUNT(*) AS Departures,
(SELECT COUNT(*) FROM Flights WHERE DestinationAirportId = Airports.Id) AS Arrivals,
SUM(Flights.Tickets) AS Tickets,
SUM(Flights.Fare * Flights.Tickets) As Revenue,
AVG(Flights.Demand) AS Demand
FROM Flights
LEFT JOIN Airports
ON Flights.OriginAirportId = Airports.Id
WHERE AnalysisId = 2
GROUP BY IATA_Code, Airports.Id <---------------------------
ORDER BY Tickets DESC
Just guessing here... there should be a FK on OriginAirportId referencing Airports.Id. If that's the case, you can do an inner join instead of left join.
Also, try using CROSS APPLY if that's an option for you.
SELECT a.IATA_Code,
COUNT(*) AS Departures,
t.Arrivals,
SUM(f.Tickets) AS Tickets,
SUM(f.Fare * f.Tickets) As Revenue,
AVG(f.Demand) AS Demand
FROM Flights f
INNER JOIN Airports a
ON f.OriginAirportId = a.Id
CROSS APPLY (
SELECT COUNT(*) AS Arrivals
FROM Flights f1
WHERE f1.DestinationAirportId = a.Id) t
WHERE AnalysisId = 2
GROUP BY IATA_Code, a.Id
ORDER BY Tickets DESC
I didn't test this code so please just use it as reference only please.
Or you can even try this...
;WITH AirportDepartureCount AS (
SELECT
OriginAirportId AS AirportId,
Count(*) AS DepartCount,
SUM(f.Tickets) AS Tickets,
SUM(f.Fare * f.Tickets) As Revenue,
AVG(f.Demand) AS Demand
FROM Flights
GROUP BY OriginAirportId
), AirportArrivalCount AS (
SELECT DestinationAirportId AS AirportId, COUNT(*) AS ArrivalCount
FROM Flights
GROUP BY DestinationAirportId
)
SELECT a.Id, a.IATA_Code,
COALESCE(depart.DepartCount,0) AS DepartCount,
COALESCE(arrival.ArrivalCount,0) AS ArrivalCount,
COALESCE(depart.Tickets,0) AS Tickets,
COALESCE(depart.Revenue,0) AS Revenue,
COALESCE(depart.Demand,0) AS Demand
FROM Airports a
LEFT JOIN AirportDepartureCount depart
ON a.Id = depart.AirportId
LEFT JOIN AirportArrivalCount arrival
ON a.Id = arrival.AirportId
ORDER BY COALESCE(depart.Tickets,0) DESC
Main difference here is that this code accounts for all airports (even those that did not have any flights). In your solution, you're ignoring any airports that did not have any departing flights. Perhaps that's by design but thought I'd throw this out there for completeness sake... ;)

Resources