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.
Related
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.
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
In a DB2 Database, I want to do the following simple mathematics using a SQL query:
AvailableStock = SupplyStock - DemandStock
SupplyStock is stored in 1 table in 1 row, let's call this table the Supply table.
So the Supply table has this data:
ProductID | SupplyStock
---------------------
109 10
244 7 edit: exclude this product from the search
DemandStock is stored in a separate table Demand, where demand is logged as each customer logs demand during a customer order journey. Example data from the Demand table:
ProductID | DemandStock
------------------------
109 1
244 4 edit: exclude this product
109 6
109 2
So in our heads, if I want to calculate the AvailableStock for product '109', Supply is 10, Demand for product 109 totals to 9, and so Available stock is 1.
How do I do this in one select query in DB2 SQL?
The knowledge I have so far of some of the imagined steps in PseudoCode:
I select SupplyStock where product ID = '109'
I select sum(DemandStock) where product ID = '109'
I subtract SupplyStock from DemandStock
I present this as a resulting AvailableStock
The results will look like this:
Product ID | AvailableStock
109 9
I'd love to get this selected in one SQL select query.
Edit: I've since received an answer (that was almost perfect) and realised the question missed out some information.
This information:
We need to exclude data from products we don't want to select data for, and we also need to specifically select product 109.
My apologies, this was omitted from the original question.
I've since added a 'where' to select the product and this works for me. But for future sake, perhaps the answer should include this information too.
You do this using a join to bring the tables together and group by to aggregate the results of the join:
select s.ProductId, s.SupplyStock, sum(d.DemandStock),
(s.SupplyStock - sum(d.DemandStock)) as Available
from Supply s left join
Demand d
on s.ProductId = d.ProductId
where s.ProductId = 109
group by s.ProductId, s.SupplyStock;
I'm trying to format a select statement. The assignment specifies that it has to be formatted this way.
I have a database regarding a taxi service. I have to put together a view with the company name, passenger name, and taxi number. Easy. However, the output specifies that the company name should only appear once in the output, at the top of it's own group. So I have:
CREATE VIEW TAXITRIPS(COMPANYNAME, PASSENGERNAME, TAXI#) AS
(SELECT COMPANY.NAME, BOOKING.NAME, VEHICLES.TAXI#
FROM BOOKING JOIN VEHICLES ON BOOKING.TAXI# = VEHICLES.TAXI#
RIGHT OUTER JOIN COMPANY ON VEHICLES.NAME = COMPANY.NAME);
The right outer join is so that companies with no booking recorded are still displayed. If I now run:
SELECT * FROM TAXITRIPS ORDER BY COMPANYNAME ASC;
It will give me something like
COMPANYNAME PASSENGERNAME TAXI#
---------------------------------------------
ABC TAXIS DAVE 192
LEGION CABS
PREMIER CABS SHANE 2154
PREMIER CABS TIM 2169
SILVER SERVICE DAVE 18579
SILVER SERVICE TIM 18124
SILVER SERVICE AARON 18917
No result for legion cabs, all field displayed, et cetera. Assignment specification says it has to look like this.
COMPANYNAME PASSENGERNAME TAXI#
---------------------------------------------
ABC TAXIS DAVE 192
LEGION CABS
PREMIER CABS SHANE 2154
TIM 2169
SILVER SERVICE DAVE 18579
TIM 18124
AARON 18917
The company name should only be displayed on its first row. DISTINCT is not helping. Any advice?
Normally, you would do this at the application layer, because the result set relies on the ordering of the rows -- a bad thing in SQL.
But you can do it as:
SELECT (CASE WHEN ROW_NUMBER() OVER (PARTITION BY c.NAME ORDER BY v.TAXI#) = 1
THEN c.NAME
END) as CompanyName, b.NAME, v.TAXI#
FROM COMPANY c LEFT JOIN
VEHICLES v
ON v.NAME = c.NAME LEFT JOIN
BOOKING b
ON b.TAXI# = v.FLIGHT#
ORDER BY c.name, v.taxi#;
Note: I rearranged the joins to be LEFT JOINs. Most people find that easier to follow than RIGHT JOINs.
I hit this issue regularly but here is an example....
I have a Order and Delivery Tables. Each order can have one to many Deliveries.
I need to report totals based on the Order Table but also show deliveries line by line.
I can write the SQL and associated Access Report for this with ease ....
SELECT xxx
FROM
Order
LEFT OUTER JOIN
Delivery on Delivery.OrderNO = Order.OrderNo
until I get to the summing element. I obviously only want to sum each Order once, not the 1-many times there are deliveries for that order.
e.g. The SQL might return the following based on 2 Orders (ignore the banalness of the report, this is very much simplified)
Region OrderNo Value Delivery Date
North 1 £100 12-04-2012
North 1 £100 14-04-2012
North 2 £73 01-05-2012
North 2 £73 03-05-2012
North 2 £73 07-05-2012
South 3 £50 23-04-2012
I would want to report:
Total Sales North - £173
Delivery 12-04-2012
Delivery 14-04-2012
Delivery 01-05-2012
Delivery 03-05-2012
Delivery 07-05-2012
Total Sales South - £50
Delivery 23-04-2012
The bit I'm referring to is the calculation of the £173 and £50 which the first of which obviously shouldn't be £419!
In the past I've used things like MAX (for a given Order) but that seems like a fudge.
Surely there must be a regular answer to this seemingly common problem but I can't find one.
I don't necessarily need the code - just a helpful point in the right direction.
Many thanks,
Chris.
A roll up operator may not look pretty. However, it would do the regular aggregates that you see now, and it show the subtotals of the order. This is what you're looking for.
SELECT xxx
FROM
Order
LEFT OUTER JOIN
Delivery on Delivery.OrderNO = Order.OrderNo
GROUP BY xxx
WITH ROLLUP;
I'm not exactly sure how the rest of your query is set up, but it would look something like this:
Region OrderNo Value Delivery Date
North 1 £100 12-04-2012
North 1 £100 14-04-2012
North 2 £73 01-05-2012
North 2 £73 03-05-2012
North 2 £73 07-05-2012
NULL NULL f419 NULL
I believe what you want is called a windowing function for your aggregate operation. It looks like the following:
SELECT xxx, SUM(Value) OVER (PARTITION BY Order.Region) as OrderTotal
FROM
Order
LEFT OUTER JOIN
Delivery on Delivery.OrderNO = Order.OrderNo
Here's the MSDN article. The PARTITION BY tells the SUM to be done separately for each distinct Order.Region.
Edit: I just noticed that I missed what you said about orders being counted multiple times. One thing you could do is SUM() the values before joining, as a CTE (guessing at your schema a bit):
WITH RegionOrders AS (
SELECT Region, OrderNo, SUM(Value) OVER (PARTITION BY Region) AS RegionTotal
FROM Order
)
SELECT Region, OrderNo, Value, DeliveryDate, RegionTotal
FROM RegionOrders RO
INNER JOIN Delivery D on D.OrderNo = RO.OrderNo