I want to get the subscriber that has maximum value of Bill (Total Bill).
I tried using the following script but SQL did not execute successflly.
Please help me on what I did wrong on this.
I have 2 tables:
Subscriber
FirstName
MIN
Ben
258999542
Reed
458524896
Steve
586692155
Clint
1007772121
Frank
1287548752
Jane
2345824215
Total Bill
Total
MIN
131.5
258999542
139.4
458524896
164
586692155
101
1007772121
224.12
1287548752
97.52
2345824215
And here's the code I tried:
SELECT MAX(B.Total), S.FirstName
FROM Subscriber AS S
JOIN Bill AS B ON S.MIN = B.MIN
It seems you just need TOP + ORDER BY:
SELECT TOP 1 B.Total, S.FirstName
FROM Subscriber AS S
JOIN Bill AS B ON S.MIN = B.MIN
ORDER BY B.Total DESC;
That's based on the fact that your sample data isn't showing multiple Bill records per Subscriber therefore you don't need a sum.
Related
This question already has answers here:
Get top 1 row of each group
(19 answers)
Closed 10 months ago.
Let's say I had two tables that looked like this:
Prod_SerialNo
Prod_TestOnAt
Prod_AccountNo
SN0001
2021-04-08
045678
SN0001
2021-01-14
067891
SN0001
2021-11-29
091234
SN0002
2022-01-19
045678
SN0002
2020-07-30
045678
SN0002
2022-03-30
012345
SN0003
2022-04-01
078912
SN0003
2022-02-19
089123
SN0003
2022-03-18
023456
S_AccountNo
S_AccountType
S_AccountName
012345
Homeowner
Adam Smith
023456
Homeowner
Jeremy Chan
034567
Manufacturer
Anne Hudson
045678
Distributor
Barney Jones
056789
Distributor
Jasmine Coleman
067891
Homeowner
Christian Lewis
078912
Distributor
Heather Ogden
089123
Homeowner
Stephen Gray
091234
Distributor
Antony Newman
The Prod Table tabulates specific product tests by what serial number was used, when the product was tested, and who tested it. (There are other things in the table, including a primary key not shown here)
The S Table is a list of subscribers with a variety of information about them. S_AccountNo is the parent to Prod_AccountNo.
I want to query when the last test was performed for each Serial Number and what account name it was that performed the test, but I don't want multiple results (duplicates) for the same serial number. I have tried the following code:
SELECT
Prod_SerialNo,
MAX(Prod_TestOnAt) AS "Last Time Tested",
S_AccountName
FROM Prod
INNER JOIN S ON S.S_AccountNo = Prod.Prod_AccountNo
GROUP BY Prod_SerialNo, S_AccountName
ORDER BY Prod_SerialNo
However, the query ends up outputting the same serial number on multiple rows even though I ask for the max TestOnAt date and I group by serial number. What am I getting wrong?
I think there is no need to use Group by you can get result with Row_Number like this:
SELECT
t.Prod_SerialNo,
t.Prod_TestOnAt AS "Last Time Tested",
t.S_AccountName
FROM (
SELECT
Prod_SerialNo,
Prod_TestOnAt,
S_AccountName,
ROW_NUMBER() OVER (PARTITION BY Prod_SerialNo ORDER BY Prod_TestOnAt DESC) rw
FROM Prod
INNER JOIN S ON S.S_AccountNo = Prod.Prod_AccountNo
) t
WHERE t.rw=1
ORDER BY t.Prod_SerialNo
You are grouping by Prod_SerialNo, S_AccountName so you will get duplicate Prod_SerialNo if multiple rows exist with that Prod_SerialNo and different S_AccountNames. You could do a MAX on Prod_TestOnAt and get that value with it's Prod_SerialNo, then join the result on the table to get your desired info using a subquery like so:
SELECT
p.[Prod_SerialNo],
max.[LastTimeTested],
s.[S_AccountName]
FROM PROD as p
INNER JOIN
(
SELECT
Prod_SerialNo,
MAX(Prod_TestOnAt) as [LastTimeTested]
FROM Prod
GROUP BY [Prod_SerialNo]
) as max
on max.[Prod_SerialNo] = p.[Prod_SerialNo] and max.[LastTimeTested] = p.[Prod_TestOnAt]
INNER JOIN S as s
ON s.[S_AccountNo] = p.[Prod_AccountNo]
ORDER BY p.[Prod_SerialNo]
If you don't like the solution using ROW_NUMBER an alternative is to use CROSS APPLY to identify the last Prod_TestOnAt and the associated Prod_AccountNo.
SELECT DISTINCT p.Prod_SerialNo, ca.Prod_TestOnAt, s.S_AccountName
FROM Prod p
CROSS APPLY (SELECT TOP 1 Prod_TestOnAt, Prod_AccountNo
FROM Prod
WHERE Prod_SerialNo = p.Prod_SerialNo
ORDER BY Prod_TestOnAt DESC) ca
INNER JOIN S ON S.S_AccountNo = ca.Prod_AccountNo
I am in a SQL class and struggling with one of the questions. We are using the AdventureWorksDW2014 database in SQL Server and this is the problem I'm stuck on:
Write a query that will return the employee key, first name, middle name, last name, total sales, and average amount per sale for every employee who has made sales to resellers. All monetary values should be rounded to two decimal places. Names should appear as a single record as "Last, First Middle." Sort the results by total sales (highest first), then by average amount per sale (highest first), then by employee name.
I have no problem selecting the EmployeeKey, nor with using concat and formatting the name as instructed. After exploring the data, it is clear that the employee information will need to come from the DimEmployee table, and the sales figures will need to come from the FactResellerSales table, and I am able to complete the inner join between the tables with no problem. I also know how to use the sum and avg functions to calculate the totals and averages for the employees individually, but those will only calculate for one employee at a time and only returns a single result. The part that I'm hung up on is creating the columns for the calculated sums and averages for each employee. The result I need to come up with needs to have a single column that shows the total sales of each employee and a single column that shows the average amount per sales for each employee, along with other information requested for each employee. So far, I have run
select distinct EmployeeKey
from FactResellerSales
to determine which employee keys are associated with sales, and it shows that there are 17. I attempted to construct the query using a subquery for each employee in the from statement,
(select EmployeeKey, sum (SalesAmount) as TotalSalesByEmp, avg (SalesAmount)
as AvgPerSaleByEmp
from FactResellerSales
where EmployeeKey = 272)
thinking that, even though it would be time consuming to do 17 subqueries, I could ultimately draw the requested data from them into the main query, but I get an error message of "Msg 8120, Level 16, State 1, Line 359
Column 'FactResellerSales.EmployeeKey' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause" when I try to test the subquery. But I can't leave out the EmployeeKey as I need it for the linking field of the inner join. My query so far (including the aliases I will use for the other fields as appropriate in the order by statement) is:
USE AdventureWorksDW2014
select e.EmployeeKey,
concat (e.LastName, ', ' + e.FirstName, ' ' + e.MiddleName) as EmployeeName
from FactResellerSales as s
inner join DimEmployee as e
on s.EmployeeKey = e.EmployeeKey
order by TotalSalesByEmp desc, AvgPerSaleByEmp desc, EmployeeName
I just need to figure out how to add the other two fields.
I've already described what the results I need should look like, but since that is apparently not good enough for some people, I will try to give an example. Apologies if the formatting is weird in the transition (I promise it looks right as I'm typing it).
| EmployeeKey | EmployeeName | TotalSalesByEmp | AvgPerSaleByEmp |
| 282 | Mitchell, Linda C | 10367007.43 | 1458.70 |
| 283 | Carson, Jillian | 10065803.54 | 1286.36 |
| 281 | Blythe, Michael G | 9293903.01 | 1314.74 |
| 272 | Jiang, Stephen Y | 1092123.86 | 1378.94 |
Please help.
Simply run your aggregation with GROUP BY on employee details which will calculate the total and average reseller sales across all 17 employees:
USE AdventureWorksDW2014
select e.EmployeeKey,
concat(e.LastName, ', ' + e.FirstName, ' ' + e.MiddleName) as EmployeeName,
sum(s.SalesAmount) as TotalSalesByEmp,
avg(s.SalesAmount) as AvgPerSaleByEmp
from FactResellerSales as s
inner join DimEmployee as e
on s.EmployeeKey = e.EmployeeKey
group by e.EmployeeKey,
e.LastName,
e.FirstName,
e.MiddleName
order by TotalSalesByEmp desc,
AvgPerSaleByEmp desc,
EmployeeName
I'm writing a query that counts company complaints. The query should count the total number of complaints from a company and also break it down into who called from the company to make the complaint. So an example output would be:
Company Ref Company Name Company Complaints Caller Caller Complaints
11 Argos 10 Steve 8
11 Argos 10 JIM 2
So as you can see the query counts the total number of complaints, then also breaks it down to who complained. So far I have everything perfect apart from the total count. My code is:
SELECT COMPANYREF,
COMPANY,
(SELECT COUNT(COMPANYREF)
FROM XCALLSTABLE) AS CompanyCalls,
CALLER,
COUNT(*)
FROM XCALLSTABLE
JOIN XCUSTOMERTABLE ON (XCALLSTABLE.COMPANYREF = XCUSTOMERTABLE.CUSTREF)
JOIN XTELEPHONETABLE ON (XCUSTOMERTABLE.TELEPHONE = XTELEPHONETABLE.PHONENUMBER)
GROUP BY COMPANYREF,
COMPANY,
CALLER
HAVING COUNT(*) > 0 ;
Some sample output for the current code is:
Company Ref Company Name Company Complaints Caller Caller Complaints
145 Comfiture Traders 500 Alexis Patel 4
The issue here is the total count for the company just counts every row, whereas I'm trying to count the occurances of that company appearing in the column.
Any and all help would be greatly appreciated.
Using sstan's code gave a result of
111 Medusa Shipping 4 Lily Morgan 5
111 Medusa Shipping 4 Ruby Walker 6
Whereas the result should be
111 Medusa Shipping 11 Lily Morgan 5
111 Medusa Shipping 11 Ruby Walker 6
I'm sure there is a cleaner way of doing this, but the following query should work:
SELECT companyref,
company,
CompanyCalls,
caller,
COUNT(*)
FROM (SELECT c.companyref,
company,
COUNT(*) OVER (PARTITION BY c.companyref) AS CompanyCalls,
caller
FROM xcallstable c
JOIN xcustomertable ct
ON ct.custref = c.companyref
JOIN xtelephonetable t
ON t.phonenumber = ct.telephone)
GROUP BY companyref, company, CompanyCalls, caller
HAVING COUNT(*) > 0
I have 2 tables joined with political results and I need to have the votes SUM per county, and then the MAX of the vote counts per county, with the Party that relates to the MAX in another column. I'm having trouble getting the Party into the Query results without messing up the SUM and MAX columns.
This Table I can get with the Following SQL
County Name SumOfVoteCount MaxOfVoteCount OfficeID
Baker 7253 4008 S
SELECT NY_Race.[County Name], Sum(NY_Results.VoteCount) AS SumOfVoteCount, Max(NY_Results.VoteCount) AS MaxOfVoteCount
FROM NY_Race INNER JOIN NY_Results ON NY_Race.RaceCountyID = NY_Results.RaceCountyID
GROUP BY NY_Race.[County Name], NY_Race.OfficeID
HAVING (((NY_Race.OfficeID)="S"));
What I need is for the Party that has that 4008 vote total to be included in the query results, but when I try to select Party to be added, it shows all of them and messes up the SUM of the vote count, and I end of with this:
County Name SumOfVoteCount MaxOfVoteCount1 Party OfficeID
Baker 2927 2927 Dem S
Baker 4008 4008 GOP S
Baker 101 101 Lib S
Baker 53 53 Prg S
Baker 164 164 WF S
This is the SQL code I am using that gets the above Table:
SELECT NY_Race.[County Name], Sum(NY_Results.VoteCount) AS SumOfVoteCount, Max(NY_Results.VoteCount) AS MaxOfVoteCount, NY_Results.Party
FROM NY_Race INNER JOIN NY_Results ON NY_Race.RaceCountyID = NY_Results.RaceCountyID
GROUP BY NY_Race.[County Name], NY_Race.OfficeID, NY_Results.Party
HAVING (((OR_Race.OfficeID)="S"));
How can I get this table in the query results?
County Name SumOfVoteCount MaxOfVoteCount Party OfficeID
Baker 7253 4008 GOP S
I can't help but think I'm missing a WHERE claus somewhere that compares Party to MAXofVoteCount
One way to approach these is to have a nested subquery that gets the MAX() for the field of interest. Then, only select the record with that MAX(). Here's the structure:
select COUNTY_NAME, R1.*
, (select sum(votecount) from results R2 where R1.COUNTY_ID=R2.COUNTY_ID and R1.OFFICE_ID=R2.OFFICE_ID)
from RESULTS R1
join RACE on R1.COUNTY_ID=RACE.COUNTY_ID and R1.OFFICE_ID=RACE.OFFICE_ID
where R1.office_id = 'S'
and voteCount =
(select max(votecount) from results R3 where R1.COUNTY_ID=R3.COUNTY_ID and R1.OFFICE_ID=R3.OFFICE_ID)
I created a demo on SQLFiddle.
One issue: what if two get exactly the same number of votes. That's a functional issue you will have to resolve.
I am looking at making a simple leader board for a time trial. A member may perform many time trials, but I only want for their fastest result to be displayed. My table columns are as follows:
Members { ID (PK), Forename, Surname }
TimeTrials { ID (PK), MemberID, Date, Time, Distance }
An example dataset would be:
Forename | Surname | Date | Time | Distance
Bill Smith 01-01-11 1.14 100
Dave Jones 04-09-11 2.33 100
Bill Smith 02-03-11 1.1 100
My resulting answer from the example above would be:
Forename | Surname | Date | Time | Distance
Bill Smith 02-03-11 1.1 100
Dave Jones 04-09-11 2.33 100
I have this so far, but access complains that I am not using Date as part of an aggregate function:
SELECT Members.Forename, Members.Surname, Min(TimeTrials.Time) AS MinOfTime, TimeTrials.Date
FROM Members
INNER JOIN TimeTrials ON Members.ID = TimeTrials.Member
GROUP BY Members.Forename, Members.Surname, TimeTrials.Distance
HAVING TimeTrials.Distance = 100
ORDER BY MIN(TimeTrials.Time);
IF I remove the Date from the SELECT the query works (without the date). I have tried using FIRST upon the TimeTrials.Date, but that will return the first date which is normally incorrect.
Obviously putting the Date as part of the GROUP BY would not return the result set that I am after.
Make this task easier on yourself by starting with a smaller piece of the problem. First get the minimum Time from TimeTrials for each combination of MemberID and Distance.
SELECT
tt.MemberID,
tt.Distance,
Min(tt.Time) AS MinOfTime
FROM TimeTrials AS tt
GROUP BY
tt.MemberID,
tt.Distance;
Assuming that SQL is correct, use it in a subquery which you join back to TimeTrials again.
SELECT tt2.*
FROM
TimeTrials AS tt2
INNER JOIN
(
SELECT
tt.MemberID,
tt.Distance,
Min(tt.Time) AS MinOfTime
FROM TimeTrials AS tt
GROUP BY
tt.MemberID,
tt.Distance
) AS sub
ON
tt2.MemberID = sub.MemberID
AND tt2.Distance = sub.Distance
AND tt2.Time = sub.MinOfTime
WHERE tt2.Distance = 100
ORDER BY tt2.Time;
Finally, you can join that query to Members to get Forename and Surname. Your question shows you already know how to do that, so I'll leave it for you. :-)